Inheritance: System.MarshalByRefObject
        public override bool Execute()
        {
            if (this.LaunchDebugger)
            {
                Debugger.Launch();
            }

            // setup a logger to delegate to Log
            if (this.Logger == null)
            {
                if (this.Log != null)
                {
                    this.Logger = new TaskLoggingHelperLogger(this.Log);
                }
                else
                {
                    this.Logger = new NullLogger();
                }
            }

            var me         = Assembly.GetExecutingAssembly();
            var peVerifier = new PEVerifier(this.Logger);

            AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolve(me);

            // load me in to a new app domain for creating IConfigurations
            this.Logger.Trace("Finding assemblies to weave in " + this.WeaveDir);
            var pathToDbm       = new Uri(me.CodeBase).LocalPath;
            var configAppDomain = AppDomain.CreateDomain(
                "ConfigAppDomain",
                null,
                new AppDomainSetup {
                ApplicationBase = Path.GetDirectoryName(pathToDbm)
            });

            configAppDomain.AssemblyResolve += (sender, args) => {
                var assemblyName = new AssemblyName(args.Name);
                var loaded       = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName == assemblyName.FullName);
                if (loaded != null)
                {
                    return(loaded);
                }

                // look in embedded resources
                var resourceName = "Dashing.Console.lib." + assemblyName.Name + ".dll";
                using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)) {
                    if (stream != null)
                    {
                        var assemblyData = new byte[stream.Length];
                        stream.Read(assemblyData, 0, assemblyData.Length);
                        return(Assembly.Load(assemblyData));
                    }
                }

                // we couldn't find it, look on disk
                var path = Path.GetDirectoryName(assemblyName.Name + ".dll");
                if (File.Exists(path))
                {
                    var assemblyData = File.ReadAllBytes(path);
                    return(Assembly.Load(assemblyData));
                }

                return(null);
            };

            var configurationMapResolver =
                (ConfigurationMapResolver)configAppDomain.CreateInstanceFromAndUnwrap(me.CodeBase, typeof(ConfigurationMapResolver).FullName);

            // locate all dlls
            var assemblyDefinitions    = new Dictionary <string, AssemblyDefinition>();
            var assemblyMapDefinitions = new Dictionary <string, List <MapDefinition> >();

            foreach (var file in Directory.GetFiles(this.WeaveDir).Where(f => f.EndsWith("dll", StringComparison.InvariantCultureIgnoreCase) || f.EndsWith("exe", StringComparison.InvariantCultureIgnoreCase)))
            {
                try {
                    var readSymbols      = File.Exists(file.Substring(0, file.Length - 3) + "pdb");
                    var assemblyResolver = new DefaultAssemblyResolver();
                    assemblyResolver.AddSearchDirectory(Path.GetDirectoryName(file));
                    var assembly = AssemblyDefinition.ReadAssembly(
                        file,
                        new ReaderParameters {
                        ReadSymbols = readSymbols, AssemblyResolver = assemblyResolver
                    });
                    assemblyDefinitions.Add(file, assembly);
                    if (assembly.MainModule.AssemblyReferences.Any(a => a.Name == "Dashing"))
                    {
                        this.Logger.Trace("Probing " + assembly.FullName + " for IConfigurations");

                        // references dashing, use our other app domain to find the IConfig and instantiate it
                        var args = new ConfigurationMapResolverArgs {
                            AssemblyFilePath = file
                        };
                        configurationMapResolver.Resolve(args);
                        var definitions = JsonConvert.DeserializeObject <IEnumerable <MapDefinition> >(args.SerializedConfigurationMapDefinitions);
                        if (definitions.Any())
                        {
                            foreach (var mapDefinition in definitions)
                            {
                                if (!assemblyMapDefinitions.ContainsKey(mapDefinition.AssemblyFullName))
                                {
                                    assemblyMapDefinitions.Add(mapDefinition.AssemblyFullName, new List <MapDefinition>());
                                }

                                assemblyMapDefinitions[mapDefinition.AssemblyFullName].Add(mapDefinition);
                            }
                        }
                    }
                }
                catch (BadImageFormatException) {
                    // swallow and carry on - prob not a managed file
                }
            }

            // now we can unload the appdomain
            AppDomain.Unload(configAppDomain);

            // trim the list of assembly definitions to only those we need
            assemblyDefinitions =
                assemblyDefinitions.Where(k => assemblyMapDefinitions.Select(mk => mk.Key).Contains(k.Value.FullName))
                .ToDictionary(k => k.Key, k => k.Value);

            this.Logger.Trace(
                "Found the following assemblies that reference dashing: " + string.Join(", ", assemblyMapDefinitions.Select(a => a.Key)));

            // now go through each assembly and re-write the types
            var visitedTypes = new HashSet <string>();
            var weavers      = me.GetLoadableTypes().Where(t => typeof(IWeaver).IsAssignableFrom(t) && t.IsClass && !t.IsAbstract).Select(
                t => {
                var weaver = (IWeaver)Activator.CreateInstance(t);
                ((ITaskLogHelper)weaver).Log = this.Logger;
                return(weaver);
            }).ToArray();

            this.Logger.Trace("Found the following weavers: " + string.Join(", ", weavers.Select(w => w.GetType().Name)));

            foreach (var assemblyMapDefinition in assemblyMapDefinitions)
            {
                var assemblyDefinitionLookup = assemblyDefinitions.Single(a => a.Value.FullName == assemblyMapDefinition.Key);
                var assemblyDefinition       = assemblyDefinitionLookup.Value;
                foreach (var mapDefinition in assemblyMapDefinition.Value)
                {
                    if (visitedTypes.Contains(mapDefinition.TypeFullName))
                    {
                        continue;
                    }

                    this.Logger.Trace("Weaving {0} in {1}", mapDefinition.TypeFullName, mapDefinition.AssemblyFullName);
                    var typeDef = BaseWeaver.GetTypeDefFromFullName(mapDefinition.TypeFullName, assemblyDefinition);
                    foreach (var weaver in weavers)
                    {
                        weaver.Weave(typeDef, assemblyDefinition, mapDefinition, assemblyMapDefinitions, assemblyDefinitions);
                    }

                    visitedTypes.Add(mapDefinition.TypeFullName);
                }

                try {
                    if (File.Exists(assemblyDefinitionLookup.Key.Substring(0, assemblyDefinitionLookup.Key.Length - 3) + "pdb"))
                    {
                        assemblyDefinition.Write(
                            assemblyDefinitionLookup.Key,
                            new WriterParameters {
                            WriteSymbols = true, SymbolWriterProvider = new PdbWriterProvider()
                        });
                    }
                    else
                    {
                        assemblyDefinition.Write(assemblyDefinitionLookup.Key);
                    }
                }
                catch (UnauthorizedAccessException) {
                    this.Logger.Trace(
                        "Unable to write the pdb for assembly " + assemblyDefinition.FullName + " due to an UnauthorizedAccessException");
                    try {
                        assemblyDefinition.Write(assemblyDefinitionLookup.Key);
                    }
                    catch (Exception) {
                        return(false); // bugger it's broke
                    }
                }

                // verify assembly
                if (!peVerifier.Verify(assemblyDefinitionLookup.Key))
                {
                    if (!IgnorePEVerify)
                    {
                        return(false);
                    }
                }

                //// copy assembly back to its project location (for subsequent copies)
                //var projectFileLocations = new Queue<string>(new[] { this.BuildEngine.ProjectFileOfTaskNode, this.ProjectPath }.Where(s => !string.IsNullOrWhiteSpace(s)));
                //var processedFileLocations = new HashSet<string>();
                //while (projectFileLocations.Count > 0) {
                //    var projectFile = projectFileLocations.Dequeue();
                //    if (!processedFileLocations.Contains(projectFile)) {
                //        this.Log.LogMessage(
                //            MessageImportance.Normal,
                //            string.Format("Processing project file {0} and looking for referenced projects", projectFile));

                //        var csProj = this.GetProject(projectFile);
                //        if (csProj.GetPropertyValue("AssemblyName") != assemblyDefinition.Name.Name) {
                //            // if equal then this assembly is the one for this project so ignore
                //            var foundProject = this.FindProjectAndCopy(csProj, assemblyDefinition, assemblyDefinitionLookup.Key);
                //            if (foundProject) {
                //                break;
                //            }

                //            this.Log.LogMessage(
                //                MessageImportance.Normal,
                //                string.Format("Unable to find Project for {0} in {1}", assemblyDefinitionLookup.Key, projectFile));

                //            var parentProjectFile = csProj.GetPropertyValue("MSBuildThisFileFullPath"); // MSBUILD 4.0 only
                //            if (!string.IsNullOrWhiteSpace(parentProjectFile)) {
                //                projectFileLocations.Enqueue(parentProjectFile);
                //            }
                //        }

                //        processedFileLocations.Add(projectFile);
                //    }
                //}
            }

            return(true);
        }
        public void Resolve(ConfigurationMapResolverArgs args)
        {
            // assembly resolution
            AppDomain.CurrentDomain.AssemblyResolve += (sender, eventArgs) => {
                var assemblyName = new AssemblyName(eventArgs.Name);

                // look in app domain
                var loaded = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName == assemblyName.FullName);
                if (loaded != null)
                {
                    return(loaded);
                }

                // we couldn't find it, look on disk
                var path = Path.GetDirectoryName(args.AssemblyFilePath) + @"\" + assemblyName.Name + ".dll";
                if (File.Exists(path))
                {
                    var assemblyData = File.ReadAllBytes(path);
                    return(Assembly.Load(assemblyData));
                }

                return(null);
            };

            // load the assembly if necessary
            var assembly           = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName == args.AssemblyFullName);
            var assemblyDefinition = AssemblyDefinition.ReadAssembly(args.AssemblyFilePath);

            if (assembly == null)
            {
                assembly = Assembly.LoadFile(args.AssemblyFilePath);
            }

            // find any IConfigs, instantiate and return map definitions
            var mapDefinitions     = new List <MapDefinition>();
            var configurationTypes =
                assembly.GetLoadableTypes()
                .Where(
                    t =>
                    typeof(IConfiguration).IsAssignableFrom(t) && t.IsClass && !t.IsAbstract &&
                    t.CustomAttributes.All(a => a.AttributeType != typeof(DoNotWeaveAttribute)));

            if (configurationTypes.Any())
            {
                foreach (var configurationType in configurationTypes)
                {
                    TypeDefinition configTypeDef;
                    if (configurationType.FullName.Contains("+"))
                    {
                        var types = configurationType.FullName.Split('+');
                        configTypeDef = assemblyDefinition.MainModule.Types.Single(t => t.FullName == types.First());
                        for (var i = 1; i < types.Length; i++)
                        {
                            configTypeDef = configTypeDef.NestedTypes.Single(t => t.Name == types.ElementAt(i));
                        }
                    }
                    else
                    {
                        configTypeDef = assemblyDefinition.MainModule.Types.Single(t => t.FullName == configurationType.FullName);
                    }

                    this.InjectConnectionStringIntoConfiguration(configTypeDef);
                    var config = Activator.CreateInstance(configurationType) as IConfiguration;
                    foreach (var map in config.Maps)
                    {
                        mapDefinitions.Add(
                            new MapDefinition {
                            AssemblyFullName  = map.Type.Assembly.FullName,
                            TypeFullName      = map.Type.FullName,
                            ColumnDefinitions =
                                map.Columns.Where(c => !c.Value.IsIgnored)
                                .Select(c => c.Value)
                                .Select(
                                    c =>
                                    new ColumnDefinition {
                                Name         = c.Name,
                                TypeFullName = c.Type.FullName,
                                Relationship = c.Relationship,
                                DbName       = c.DbName,
                                DbType       = c.DbType,
                                IsPrimaryKey = c.IsPrimaryKey
                            })
                        });
                    }
                }
            }

            args.SerializedConfigurationMapDefinitions = JsonConvert.SerializeObject(mapDefinitions);
        }
        public void Resolve(ConfigurationMapResolverArgs args) {
            // assembly resolution
            AppDomain.CurrentDomain.AssemblyResolve += (sender, eventArgs) => {
                var assemblyName = new AssemblyName(eventArgs.Name);

                // look in app domain
                var loaded = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName == assemblyName.FullName);
                if (loaded != null) {
                    return loaded;
                }

                // we couldn't find it, look on disk
                var path = Path.GetDirectoryName(args.AssemblyFilePath) + @"\" + assemblyName.Name + ".dll";
                if (File.Exists(path)) {
                    var assemblyData = File.ReadAllBytes(path);
                    return Assembly.Load(assemblyData);
                }

                return null;
            };

            // load the assembly if necessary
            var assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName == args.AssemblyFullName);
            var assemblyDefinition = AssemblyDefinition.ReadAssembly(args.AssemblyFilePath);
            if (assembly == null) {
                assembly = Assembly.LoadFile(args.AssemblyFilePath);
            }

            // find any IConfigs, instantiate and return map definitions
            var mapDefinitions = new List<MapDefinition>();
            var configurationTypes =
                assembly.GetLoadableTypes()
                        .Where(
                            t =>
                            typeof(IConfiguration).IsAssignableFrom(t) && t.IsClass && !t.IsAbstract
                            && t.CustomAttributes.All(a => a.AttributeType != typeof(DoNotWeaveAttribute)));
            if (configurationTypes.Any()) {
                foreach (var configurationType in configurationTypes) {
                    TypeDefinition configTypeDef;
                    if (configurationType.FullName.Contains("+")) {
                        var types = configurationType.FullName.Split('+');
                        configTypeDef = assemblyDefinition.MainModule.Types.Single(t => t.FullName == types.First());
                        for (var i = 1; i < types.Length; i++) {
                            configTypeDef = configTypeDef.NestedTypes.Single(t => t.Name == types.ElementAt(i));
                        }
                    }
                    else {
                        configTypeDef = assemblyDefinition.MainModule.Types.Single(t => t.FullName == configurationType.FullName);
                    }

                    this.InjectConnectionStringIntoConfiguration(configTypeDef);
                    var config = Activator.CreateInstance(configurationType) as IConfiguration;
                    foreach (var map in config.Maps) {
                        mapDefinitions.Add(
                            new MapDefinition {
                                                  AssemblyFullName = map.Type.Assembly.FullName,
                                                  TypeFullName = map.Type.FullName,
                                                  ColumnDefinitions =
                                                      map.Columns.Where(c => !c.Value.IsIgnored)
                                                         .Select(c => c.Value)
                                                         .Select(
                                                             c =>
                                                             new ColumnDefinition {
                                                                                      Name = c.Name,
                                                                                      TypeFullName = c.Type.FullName,
                                                                                      Relationship = c.Relationship,
                                                                                      DbName = c.DbName,
                                                                                      DbType = c.DbType,
                                                                                      IsPrimaryKey = c.IsPrimaryKey
                                                                                  })
                                              });
                    }
                }
            }

            args.SerializedConfigurationMapDefinitions = JsonConvert.SerializeObject(mapDefinitions);
        }
        public override bool Execute() {
            if (this.LaunchDebugger) {
                Debugger.Launch();
            }

            // setup a logger to delegate to Log
            if (this.Logger == null) {
                if (this.Log != null) {
                    this.Logger = new TaskLoggingHelperLogger(this.Log);
                }
                else {
                    this.Logger = new NullLogger();
                }
            }

            var me = Assembly.GetExecutingAssembly();
            var peVerifier = new PEVerifier(this.Logger);

            AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolve(me);

            // load me in to a new app domain for creating IConfigurations
            this.Logger.Trace("Finding assemblies to weave in " + this.WeaveDir);
            var pathToDbm = new Uri(me.CodeBase).LocalPath;
            var configAppDomain = AppDomain.CreateDomain(
                "ConfigAppDomain",
                null,
                new AppDomainSetup { ApplicationBase = Path.GetDirectoryName(pathToDbm) });
            configAppDomain.AssemblyResolve += (sender, args) => {
                var assemblyName = new AssemblyName(args.Name);
                var loaded = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName == assemblyName.FullName);
                if (loaded != null) {
                    return loaded;
                }

                // look in embedded resources
                var resourceName = "Dashing.Console.lib." + assemblyName.Name + ".dll";
                using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)) {
                    if (stream != null) {
                        var assemblyData = new byte[stream.Length];
                        stream.Read(assemblyData, 0, assemblyData.Length);
                        return Assembly.Load(assemblyData);
                    }
                }

                // we couldn't find it, look on disk
                var path = Path.GetDirectoryName(assemblyName.Name + ".dll");
                if (File.Exists(path)) {
                    var assemblyData = File.ReadAllBytes(path);
                    return Assembly.Load(assemblyData);
                }

                return null;
            };

            var configurationMapResolver =
                (ConfigurationMapResolver)configAppDomain.CreateInstanceFromAndUnwrap(me.CodeBase, typeof(ConfigurationMapResolver).FullName);

            // locate all dlls
            var assemblyDefinitions = new Dictionary<string, AssemblyDefinition>();
            var assemblyMapDefinitions = new Dictionary<string, List<MapDefinition>>();
            foreach (var file in Directory.GetFiles(this.WeaveDir).Where(f => f.EndsWith("dll", StringComparison.InvariantCultureIgnoreCase) || f.EndsWith("exe", StringComparison.InvariantCultureIgnoreCase))) {
                try {
                    var readSymbols = File.Exists(file.Substring(0, file.Length - 3) + "pdb");
                    var assemblyResolver = new DefaultAssemblyResolver();
                    assemblyResolver.AddSearchDirectory(Path.GetDirectoryName(file));
                    var assembly = AssemblyDefinition.ReadAssembly(
                        file,
                        new ReaderParameters { ReadSymbols = readSymbols, AssemblyResolver = assemblyResolver });
                    assemblyDefinitions.Add(file, assembly);
                    if (assembly.MainModule.AssemblyReferences.Any(a => a.Name == "Dashing")) {
                        this.Logger.Trace("Probing " + assembly.FullName + " for IConfigurations");

                        // references dashing, use our other app domain to find the IConfig and instantiate it
                        var args = new ConfigurationMapResolverArgs { AssemblyFilePath = file };
                        configurationMapResolver.Resolve(args);
                        var definitions = JsonConvert.DeserializeObject<IEnumerable<MapDefinition>>(args.SerializedConfigurationMapDefinitions);
                        if (definitions.Any()) {
                            foreach (var mapDefinition in definitions) {
                                if (!assemblyMapDefinitions.ContainsKey(mapDefinition.AssemblyFullName)) {
                                    assemblyMapDefinitions.Add(mapDefinition.AssemblyFullName, new List<MapDefinition>());
                                }

                                assemblyMapDefinitions[mapDefinition.AssemblyFullName].Add(mapDefinition);
                            }
                        }
                    }
                }
                catch (BadImageFormatException) {
                    // swallow and carry on - prob not a managed file
                }
            }

            // now we can unload the appdomain
            AppDomain.Unload(configAppDomain);

            // trim the list of assembly definitions to only those we need
            assemblyDefinitions =
                assemblyDefinitions.Where(k => assemblyMapDefinitions.Select(mk => mk.Key).Contains(k.Value.FullName))
                                   .ToDictionary(k => k.Key, k => k.Value);

            this.Logger.Trace(
                "Found the following assemblies that reference dashing: " + string.Join(", ", assemblyMapDefinitions.Select(a => a.Key)));

            // now go through each assembly and re-write the types
            var visitedTypes = new HashSet<string>();
            var weavers = me.GetLoadableTypes().Where(t => typeof(IWeaver).IsAssignableFrom(t) && t.IsClass && !t.IsAbstract).Select(
                t => {
                    var weaver = (IWeaver)Activator.CreateInstance(t);
                    ((ITaskLogHelper)weaver).Log = this.Logger;
                    return weaver;
                }).ToArray();

            this.Logger.Trace("Found the following weavers: " + string.Join(", ", weavers.Select(w => w.GetType().Name)));

            foreach (var assemblyMapDefinition in assemblyMapDefinitions) {
                var assemblyDefinitionLookup = assemblyDefinitions.Single(a => a.Value.FullName == assemblyMapDefinition.Key);
                var assemblyDefinition = assemblyDefinitionLookup.Value;
                foreach (var mapDefinition in assemblyMapDefinition.Value) {
                    if (visitedTypes.Contains(mapDefinition.TypeFullName)) {
                        continue;
                    }

                    this.Logger.Trace("Weaving {0} in {1}", mapDefinition.TypeFullName, mapDefinition.AssemblyFullName);
                    var typeDef = BaseWeaver.GetTypeDefFromFullName(mapDefinition.TypeFullName, assemblyDefinition);
                    foreach (var weaver in weavers) {
                        weaver.Weave(typeDef, assemblyDefinition, mapDefinition, assemblyMapDefinitions, assemblyDefinitions);
                    }

                    visitedTypes.Add(mapDefinition.TypeFullName);
                }

                try {
                    if (File.Exists(assemblyDefinitionLookup.Key.Substring(0, assemblyDefinitionLookup.Key.Length - 3) + "pdb")) {
                        assemblyDefinition.Write(
                            assemblyDefinitionLookup.Key,
                            new WriterParameters { WriteSymbols = true, SymbolWriterProvider = new PdbWriterProvider() });
                    }
                    else {
                        assemblyDefinition.Write(assemblyDefinitionLookup.Key);
                    }
                }
                catch (UnauthorizedAccessException) {
                    this.Logger.Trace(
                        "Unable to write the pdb for assembly " + assemblyDefinition.FullName + " due to an UnauthorizedAccessException");
                    try {
                        assemblyDefinition.Write(assemblyDefinitionLookup.Key);
                    }
                    catch (Exception) {
                        return false; // bugger it's broke
                    }
                }

                // verify assembly
                if (!peVerifier.Verify(assemblyDefinitionLookup.Key)) {
                    if (!IgnorePEVerify) {
                        return false;
                    }
                }

                //// copy assembly back to its project location (for subsequent copies)
                //var projectFileLocations = new Queue<string>(new[] { this.BuildEngine.ProjectFileOfTaskNode, this.ProjectPath }.Where(s => !string.IsNullOrWhiteSpace(s)));
                //var processedFileLocations = new HashSet<string>();
                //while (projectFileLocations.Count > 0) {
                //    var projectFile = projectFileLocations.Dequeue();
                //    if (!processedFileLocations.Contains(projectFile)) {
                //        this.Log.LogMessage(
                //            MessageImportance.Normal,
                //            string.Format("Processing project file {0} and looking for referenced projects", projectFile));

                //        var csProj = this.GetProject(projectFile);
                //        if (csProj.GetPropertyValue("AssemblyName") != assemblyDefinition.Name.Name) {
                //            // if equal then this assembly is the one for this project so ignore
                //            var foundProject = this.FindProjectAndCopy(csProj, assemblyDefinition, assemblyDefinitionLookup.Key);
                //            if (foundProject) {
                //                break;
                //            }

                //            this.Log.LogMessage(
                //                MessageImportance.Normal,
                //                string.Format("Unable to find Project for {0} in {1}", assemblyDefinitionLookup.Key, projectFile));

                //            var parentProjectFile = csProj.GetPropertyValue("MSBuildThisFileFullPath"); // MSBUILD 4.0 only
                //            if (!string.IsNullOrWhiteSpace(parentProjectFile)) {
                //                projectFileLocations.Enqueue(parentProjectFile);
                //            }
                //        }

                //        processedFileLocations.Add(projectFile);
                //    }
                //}
            }

            return true;
        }