private void AutomaticallyPackageNormalProject(
            DefinitionInfo[] definitions,
            List <Service> services,
            FileFilter fileFilter,
            string rootPath,
            string platform,
            DefinitionInfo definition,
            List <string> temporaryFiles)
        {
            var document = XDocument.Load(definition.DefinitionPath);

            var externalProjectDocument = new XmlDocument();

            externalProjectDocument.AppendChild(externalProjectDocument.CreateXmlDeclaration("1.0", "UTF-8", null));
            var externalProject = externalProjectDocument.CreateElement("ExternalProject");

            externalProjectDocument.AppendChild(externalProject);
            externalProject.SetAttribute("Name", definition.Name);

            if (definition.PostBuildHook)
            {
                externalProject.SetAttribute("PostBuildHook", "True");
            }

            var externalProjectServices = externalProjectDocument.CreateElement("Services");

            externalProject.AppendChild(externalProjectServices);

            // Just import all declared services as available, regardless of conflicts or
            // requirements.  We don't have a clean way of automatically translating
            // services for packages (it has to be done manually because services can
            // change the resulting code that's built).  So that things work 95% of time,
            // just declare all services available for projects included via the automatic
            // packaging mechanism.
            var servicesToDeclare = new List <string>();
            var servicesDeclared  = document.Root.Element(XName.Get("Services"));

            if (servicesDeclared != null)
            {
                foreach (var serviceElement in servicesDeclared.Elements().Where(x => x.Name.LocalName == "Service"))
                {
                    servicesToDeclare.Add(serviceElement.Attribute(XName.Get("Name")).Value);
                }
            }

            foreach (var serviceToDeclare in servicesToDeclare)
            {
                var serviceElem = externalProjectDocument.CreateElement("Service");
                serviceElem.SetAttribute("Name", serviceToDeclare);
                var defaultForRoot = externalProjectDocument.CreateElement("DefaultForRoot");
                defaultForRoot.InnerText = "True";
                serviceElem.AppendChild(defaultForRoot);
                externalProjectServices.AppendChild(serviceElem);
            }

            var pathPrefix   = this.m_ProjectOutputPathCalculator.GetProjectOutputPathPrefix(platform, definition, document, true);
            var assemblyName = this.m_ProjectOutputPathCalculator.GetProjectAssemblyName(platform, definition, document);
            var outputMode   = this.m_ProjectOutputPathCalculator.GetProjectOutputMode(document);

            var assemblyFilesToCopy = new[]
            {
                assemblyName + ".exe",
                assemblyName + ".dll",
                assemblyName + ".dll.config",
                assemblyName + ".dll.mdb",
                assemblyName + ".pdb",
                assemblyName + ".xml",
            };

            // Copy the assembly itself out to the package.
            switch (outputMode)
            {
            case OutputPathMode.BinConfiguration:
            {
                // In this configuration, we only ship the binaries for
                // the default architecture (because that's all we know
                // about).  We also have to assume the binary folder
                // contains binaries for the desired platform.
                if (definition.Type == "Library")
                {
                    // For libraries, we only copy the assembly (and immediately related files)
                    // into it's directory. Native binaries will be expressed through the ExternalProject.
                    foreach (var assemblyFile in assemblyFilesToCopy)
                    {
                        var includeMatch = fileFilter.ApplyInclude("^" + pathPrefix + Regex.Escape(assemblyFile) + "$");
                        var rewriteMatch = fileFilter.ApplyRewrite("^" + pathPrefix + Regex.Escape(assemblyFile) + "$", definition.Name + "/AnyCPU/" + assemblyFile);
                        if (includeMatch && rewriteMatch)
                        {
                            if (assemblyFile.EndsWith(".dll"))
                            {
                                var binaryEntry = externalProjectDocument.CreateElement("Binary");
                                binaryEntry.SetAttribute("Name", assemblyFile.Substring(0, assemblyFile.Length - 4));
                                binaryEntry.SetAttribute("Path", definition.Name + "\\AnyCPU\\" + assemblyFile);
                                externalProject.AppendChild(binaryEntry);
                            }
                            else if (assemblyFile.EndsWith(".dll.config"))
                            {
                                var configEntry = externalProjectDocument.CreateElement("NativeBinary");
                                configEntry.SetAttribute("Path", definition.Name + "\\AnyCPU\\" + assemblyFile);
                                externalProject.AppendChild(configEntry);
                            }
                        }
                        else if (includeMatch || rewriteMatch)
                        {
                            throw new InvalidOperationException("Automatic filter; only one rule matched.");
                        }
                    }
                }
                else
                {
                    // For executables, we ship everything in the output directory, because we
                    // want the executables to be able to run from the package directory.
                    fileFilter.ApplyInclude("^" + pathPrefix + "(.+)$");
                    fileFilter.ApplyRewrite("^" + pathPrefix + "(.+)$", definition.Name + "/AnyCPU/$2");

                    // Mark the executable files in the directory as tools that can be executed.
                    foreach (var assemblyFile in assemblyFilesToCopy)
                    {
                        if (assemblyFile.EndsWith(".exe"))
                        {
                            var binaryEntry = externalProjectDocument.CreateElement("Tool");
                            binaryEntry.SetAttribute("Name", assemblyFile.Substring(0, assemblyFile.Length - 4));
                            binaryEntry.SetAttribute("Path", definition.Name + "\\AnyCPU\\" + assemblyFile);
                            externalProject.AppendChild(binaryEntry);
                        }
                    }
                }

                break;
            }

            case OutputPathMode.BinPlatformArchConfiguration:
            {
                // In this configuration, we ship binaries for AnyCPU, iPhoneSimulator or all .NET architectures
                // depending on whether or not the platform produces multiple architectures.  On Mono,
                // we can't use $(Platform) within a reference's path, so we have to keep this path static
                // for Mono platforms.
                string pathArchMatch, pathArchReplace, pathArchRuntime;
                switch (platform.ToLowerInvariant())
                {
                case "ios":
                {
                    pathArchMatch   = "iPhoneSimulator";
                    pathArchReplace = "iPhoneSimulator";
                    pathArchRuntime = "iPhoneSimulator";
                    break;
                }

                case "windowsphone":
                {
                    pathArchMatch   = "([^/]+)";
                    pathArchReplace = "$1";
                    pathArchRuntime = "$(Platform)";
                    break;
                }

                default:
                {
                    pathArchMatch   = "AnyCPU";
                    pathArchReplace = "AnyCPU";
                    pathArchRuntime = "AnyCPU";
                    break;
                }
                }

                if (definition.Type == "Library")
                {
                    // For libraries, we only copy the assembly (and immediately related files)
                    // into it's directory. Native binaries will be expressed through the ExternalProject.
                    foreach (var assemblyFile in assemblyFilesToCopy)
                    {
                        var includeMatch = fileFilter.ApplyInclude("^" + pathPrefix + Regex.Escape(assemblyFile) + "$");
                        var rewriteMatch = fileFilter.ApplyRewrite("^" + pathPrefix + Regex.Escape(assemblyFile) + "$", definition.Name + "/" + pathArchReplace + "/" + assemblyFile);
                        if (includeMatch && rewriteMatch)
                        {
                            if (assemblyFile.EndsWith(".dll"))
                            {
                                var binaryEntry = externalProjectDocument.CreateElement("Binary");
                                binaryEntry.SetAttribute("Name", assemblyFile.Substring(0, assemblyFile.Length - 4));
                                binaryEntry.SetAttribute("Path", definition.Name + "\\" + pathArchRuntime + "\\" + assemblyFile);
                                externalProject.AppendChild(binaryEntry);
                            }
                            else if (assemblyFile.EndsWith(".dll.config"))
                            {
                                var configEntry = externalProjectDocument.CreateElement("NativeBinary");
                                configEntry.SetAttribute("Path", definition.Name + "\\" + pathArchRuntime + "\\" + assemblyFile);
                                externalProject.AppendChild(configEntry);
                            }
                        }
                        else if (includeMatch || rewriteMatch)
                        {
                            throw new InvalidOperationException("Automatic filter; only one rule matched.");
                        }
                    }
                }
                else
                {
                    // For executables, we ship everything in the output directory, because we
                    // want the executables to be able to run from the package directory.
                    fileFilter.ApplyInclude("^" + pathPrefix + "(.+)$");

                    if (pathArchMatch == "([^/]+)")
                    {
                        fileFilter.ApplyRewrite("^" + pathPrefix + "(.+)$", definition.Name + "/" + pathArchReplace + "/$3");
                    }
                    else
                    {
                        fileFilter.ApplyRewrite("^" + pathPrefix + "(.+)$", definition.Name + "/" + pathArchReplace + "/$2");
                    }

                    // Mark the executable files in the directory as tools that can be executed.
                    foreach (var assemblyFile in assemblyFilesToCopy)
                    {
                        if (assemblyFile.EndsWith(".exe"))
                        {
                            var binaryEntry = externalProjectDocument.CreateElement("Tool");
                            binaryEntry.SetAttribute("Name", assemblyFile.Substring(0, assemblyFile.Length - 4));
                            binaryEntry.SetAttribute("Path", definition.Name + "\\" + pathArchRuntime + "\\" + assemblyFile);
                            externalProject.AppendChild(binaryEntry);
                        }
                    }
                }

                break;
            }

            case OutputPathMode.BinProjectPlatformArchConfiguration:
            {
                throw new NotSupportedException();
                break;
            }
            }

            // Convert all of the known references into references within the external project.
            var definitionsByName = definitions.ToDictionarySafe(
                k => k.Name,
                v => v,
                (dict, x) =>
            {
                var existing = dict[x.Name];
                var tried    = x;

                RedirectableConsole.WriteLine("WARNING: There is more than one project with the name " +
                                              x.Name + " (first project loaded from " + tried.AbsolutePath + ", " +
                                              "skipped loading second project from " + existing.AbsolutePath + ")");
            });

            foreach (var reference in document.XPathSelectElements("/Project/References/Reference"))
            {
                var includeAttribute = reference.Attribute(XName.Get("Include"));
                if (includeAttribute != null)
                {
                    if (definitionsByName.ContainsKey(includeAttribute.Value))
                    {
                        var targetDefinition = definitionsByName[includeAttribute.Value];

                        // If the targeted reference is an include project, skip it.
                        if (targetDefinition == null || targetDefinition.Type != "Include")
                        {
                            // This reference will be converted to an external project,
                            // so add a reference to it (in case it contains native binaries
                            // which need to be copied out).
                            var referenceEntry = externalProjectDocument.CreateElement("Reference");
                            referenceEntry.SetAttribute("Include", includeAttribute.Value);
                            externalProject.AppendChild(referenceEntry);
                        }
                    }
                }
            }

            // Copy out any files that are marked with copy-on-build flag.
            var detector    = new PlatformAndServiceActiveDetection();
            var xmlDocument = new XmlDocument();

            xmlDocument.Load(definition.DefinitionPath);
            var servicesInput         = this.m_ServiceInputGenerator.Generate(xmlDocument, definition.Name, services);
            var activeServicesElement = servicesInput.ChildNodes.OfType <XmlElement>().FirstOrDefault(x => x.LocalName == "ActiveServicesNames");
            var activeServices        = activeServicesElement.InnerText;

            foreach (var file in document.XPathSelectElements("/Project/Files/*"))
            {
                var copyOnBuild = file.XPathSelectElement("CopyToOutputDirectory");
                if (copyOnBuild == null)
                {
                    continue;
                }

                if (copyOnBuild.Value != "PreserveNewest" && copyOnBuild.Value != "Always")
                {
                    continue;
                }

                var platformsElement        = file.XPathSelectElement("Platforms");
                var includePlatformsElement = file.XPathSelectElement("IncludePlatforms");
                var excludePlatformsElement = file.XPathSelectElement("ExcludePlatforms");
                var servicesElement         = file.XPathSelectElement("Services");
                var includeServicesElement  = file.XPathSelectElement("IncludeServices");
                var excludeServicesElement  = file.XPathSelectElement("ExcludeServices");

                var platformsString        = platformsElement != null ? platformsElement.Value : string.Empty;
                var includePlatformsString = includePlatformsElement != null ? includePlatformsElement.Value : string.Empty;
                var excludePlatformsString = excludePlatformsElement != null ? excludePlatformsElement.Value : string.Empty;
                var servicesString         = servicesElement != null ? servicesElement.Value : string.Empty;
                var includeServicesString  = includeServicesElement != null ? includeServicesElement.Value : string.Empty;
                var excludeServicesString  = excludeServicesElement != null ? excludeServicesElement.Value : string.Empty;

                if (detector.ProjectAndServiceIsActive(
                        platformsString,
                        includePlatformsString,
                        excludePlatformsString,
                        servicesString,
                        includeServicesString,
                        excludeServicesString,
                        platform,
                        activeServices))
                {
                    var include     = file.Attribute(XName.Get("Include"));
                    var linkElement = file.XPathSelectElement("Link");
                    var link        = linkElement != null ? linkElement.Value : include.Value;

                    var fileInfo = new FileInfo(Path.Combine(
                                                    definition.AbsolutePath.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar),
                                                    include.Value.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar)));

                    if (definition.Type == "Library")
                    {
                        // For libraries, we're copying the content so that applications using
                        // the libraries will have the content.  This is most often used to
                        // ship native binaries (although NativeBinary in external projects now
                        // supersedes this).
                        if (link.Contains('/') || link.Contains('\\'))
                        {
                            RedirectableConsole.WriteLine(
                                "WARNING: Copy-on-build file '" + link + "' in library project which " +
                                "does not output to root of project detected.  This is not supported.");
                        }
                        else
                        {
                            if (fileInfo.Name != link)
                            {
                                RedirectableConsole.WriteLine(
                                    "WARNING: Copy-on-build file in library project does not have the same " +
                                    "name when copied to build directory.  This is not supported.");
                            }
                            else
                            {
                                var sourcePath = fileInfo.FullName;
                                sourcePath = sourcePath.Substring(rootPath.Length).Replace('\\', '/').TrimStart('/');
                                var destPath = Path.Combine("_AutomaticExternals", sourcePath);

                                var sourcePathRegex = this.ConvertPathWithMSBuildVariablesFind(sourcePath);
                                var destPathRegex   = this.ConvertPathWithMSBuildVariablesReplace(destPath.Replace('\\', '/'));

                                var includeMatch = fileFilter.ApplyInclude(sourcePathRegex);
                                fileFilter.ApplyRewrite(sourcePathRegex, destPathRegex);
                                if (includeMatch)
                                {
                                    var nativeBinaryEntry = externalProjectDocument.CreateElement("NativeBinary");
                                    nativeBinaryEntry.SetAttribute("Path", destPath);
                                    externalProject.AppendChild(nativeBinaryEntry);
                                }
                                else
                                {
                                    throw new InvalidOperationException(
                                              "File not found at " + sourcePath + " when converting " +
                                              "copy-on-build file in library project.");
                                }
                            }
                        }
                    }
                }
            }

            // Write out the external project to a temporary file and include it.
            var name = Path.GetRandomFileName() + "_" + definition.Name + ".xml";
            var temp = Path.Combine(Path.GetTempPath(), name);

            temporaryFiles.Add(temp);
            using (var writer = XmlWriter.Create(temp, new XmlWriterSettings {
                Indent = true, IndentChars = "  "
            }))
            {
                externalProjectDocument.WriteTo(writer);
            }
            fileFilter.AddManualMapping(temp, "Build/Projects/" + definition.Name + ".definition");
        }
        private void AutomaticallyPackageNormalProject(
            DefinitionInfo[] definitions,
            List <Service> services,
            FileFilter fileFilter,
            string rootPath,
            string platform,
            DefinitionInfo definition)
        {
            var document = XDocument.Load(definition.DefinitionPath);
            var platformSpecificOutputFolderElement = document.XPathSelectElement("/Project/Properties/PlatformSpecificOutputFolder");
            var projectSpecificOutputFolderElement  = document.XPathSelectElement("/Project/Properties/ProjectSpecificOutputFolder");
            var assemblyNameForPlatformElement      = document.XPathSelectElement("/Project/Properties/AssemblyName/Platform[@Name=\"" + platform + "\"]");
            var assemblyNameGlobalElement           = document.XPathSelectElement("/Project/Properties/Property[@Name=\"AssemblyName\"]");
            var platformSpecificOutputFolder        = true;
            var projectSpecificOutputFolder         = false;

            if (platformSpecificOutputFolderElement != null)
            {
                platformSpecificOutputFolder = platformSpecificOutputFolderElement.Value.ToLowerInvariant() != "false";
            }
            if (projectSpecificOutputFolderElement != null)
            {
                projectSpecificOutputFolder = projectSpecificOutputFolderElement.Value.ToLowerInvariant() == "true";
            }

            string assemblyName = null;

            if (assemblyNameForPlatformElement != null)
            {
                assemblyName = assemblyNameForPlatformElement.Value;
            }
            else if (assemblyNameGlobalElement != null)
            {
                assemblyName = assemblyNameGlobalElement.Value;
            }
            else
            {
                assemblyName = definition.Name;
            }

            var assemblyFilesToCopy = new[]
            {
                assemblyName + ".exe",
                assemblyName + ".dll",
                assemblyName + ".dll.config",
                assemblyName + ".dll.mdb",
                assemblyName + ".pdb",
                assemblyName + ".xml",
            };

            var outputMode = OutputPathMode.BinConfiguration;

            if (projectSpecificOutputFolder)
            {
                outputMode = OutputPathMode.BinProjectPlatformArchConfiguration;
            }
            if (platformSpecificOutputFolder)
            {
                outputMode = OutputPathMode.BinPlatformArchConfiguration;
            }

            var externalProjectDocument = new XmlDocument();

            externalProjectDocument.AppendChild(externalProjectDocument.CreateXmlDeclaration("1.0", "UTF-8", null));
            var externalProject = externalProjectDocument.CreateElement("ExternalProject");

            externalProjectDocument.AppendChild(externalProject);
            externalProject.SetAttribute("Name", definition.Name);

            // Copy the assembly itself out to the package.
            switch (outputMode)
            {
            case OutputPathMode.BinConfiguration:
            {
                // In this configuration, we only ship the binaries for
                // the default architecture (because that's all we know
                // about).  We also have to assume the binary folder
                // contains binaries for the desired platform.
                var pathPrefix = definition.Path.Replace('\\', '/').Replace(".", "\\.") + "/bin/([^/]+)/";

                if (definition.Type == "Library")
                {
                    // For libraries, we only copy the assembly (and immediately related files)
                    // into it's directory. Native binaries will be expressed through the ExternalProject.
                    foreach (var assemblyFile in assemblyFilesToCopy)
                    {
                        var includeMatch = fileFilter.ApplyInclude("^" + pathPrefix + Regex.Escape(assemblyFile) + "$");
                        var rewriteMatch = fileFilter.ApplyRewrite("^" + pathPrefix + Regex.Escape(assemblyFile) + "$", definition.Name + "/AnyCPU/" + assemblyFile);
                        if (includeMatch && rewriteMatch)
                        {
                            if (assemblyFile.EndsWith(".dll"))
                            {
                                var binaryEntry = externalProjectDocument.CreateElement("Binary");
                                binaryEntry.SetAttribute("Name", assemblyFile.Substring(0, assemblyFile.Length - 4));
                                binaryEntry.SetAttribute("Path", definition.Name + "\\AnyCPU\\" + assemblyFile);
                                externalProject.AppendChild(binaryEntry);
                            }
                            else if (assemblyFile.EndsWith(".dll.config"))
                            {
                                var configEntry = externalProjectDocument.CreateElement("NativeBinary");
                                configEntry.SetAttribute("Path", definition.Name + "\\AnyCPU\\" + assemblyFile);
                                externalProject.AppendChild(configEntry);
                            }
                        }
                        else if (includeMatch || rewriteMatch)
                        {
                            throw new InvalidOperationException("Automatic filter; only one rule matched.");
                        }
                    }
                }
                else
                {
                    // For executables, we ship everything in the output directory, because we
                    // want the executables to be able to run from the package directory.
                    fileFilter.ApplyInclude("^" + pathPrefix + "(.+)$");
                    fileFilter.ApplyRewrite("^" + pathPrefix + "(.+)$", definition.Name + "/AnyCPU/$2");
                }

                break;
            }

            case OutputPathMode.BinPlatformArchConfiguration:
            {
                // In this configuration, we ship binaries for AnyCPU, iPhone or all .NET architectures
                // depending on whether or not the platform produces multiple architectures.  On Mono,
                // we can't use $(Platform) within a reference's path, so we have to keep this path static
                // for Mono platforms.
                string pathArchMatch, pathArchReplace, pathArchRuntime;
                switch (platform.ToLowerInvariant())
                {
                case "ios":
                {
                    pathArchMatch   = "iPhone";
                    pathArchReplace = "iPhone";
                    pathArchRuntime = "iPhone";
                    break;
                }

                case "windowsphone":
                {
                    pathArchMatch   = "([^/]+)";
                    pathArchReplace = "$1";
                    pathArchRuntime = "$(Platform)";
                    break;
                }

                default:
                {
                    pathArchMatch   = "AnyCPU";
                    pathArchReplace = "AnyCPU";
                    pathArchRuntime = "AnyCPU";
                    break;
                }
                }

                var pathPrefix = definition.Path.Replace('\\', '/').Replace(".", "\\.") + "/bin/" + platform + "/" + pathArchMatch + "/([^/]+)/";

                if (definition.Type == "Library")
                {
                    // For libraries, we only copy the assembly (and immediately related files)
                    // into it's directory. Native binaries will be expressed through the ExternalProject.
                    foreach (var assemblyFile in assemblyFilesToCopy)
                    {
                        var includeMatch = fileFilter.ApplyInclude("^" + pathPrefix + Regex.Escape(assemblyFile) + "$");
                        var rewriteMatch = fileFilter.ApplyRewrite("^" + pathPrefix + Regex.Escape(assemblyFile) + "$", definition.Name + "/" + pathArchReplace + "/" + assemblyFile);
                        if (includeMatch && rewriteMatch)
                        {
                            if (assemblyFile.EndsWith(".dll"))
                            {
                                var binaryEntry = externalProjectDocument.CreateElement("Binary");
                                binaryEntry.SetAttribute("Name", assemblyFile.Substring(0, assemblyFile.Length - 4));
                                binaryEntry.SetAttribute("Path", definition.Name + "\\" + pathArchRuntime + "\\" + assemblyFile);
                                externalProject.AppendChild(binaryEntry);
                            }
                            else if (assemblyFile.EndsWith(".dll.config"))
                            {
                                var configEntry = externalProjectDocument.CreateElement("NativeBinary");
                                configEntry.SetAttribute("Path", definition.Name + "\\" + pathArchRuntime + "\\" + assemblyFile);
                                externalProject.AppendChild(configEntry);
                            }
                        }
                        else if (includeMatch || rewriteMatch)
                        {
                            throw new InvalidOperationException("Automatic filter; only one rule matched.");
                        }
                    }
                }
                else
                {
                    // For executables, we ship everything in the output directory, because we
                    // want the executables to be able to run from the package directory.
                    fileFilter.ApplyInclude("^" + pathPrefix + "(.+)$");

                    if (pathArchMatch == "([^/]+)")
                    {
                        fileFilter.ApplyRewrite("^" + pathPrefix + "(.+)$", definition.Name + "/" + pathArchReplace + "/$3");
                    }
                    else
                    {
                        fileFilter.ApplyRewrite("^" + pathPrefix + "(.+)$", definition.Name + "/" + pathArchReplace + "/$2");
                    }
                }

                break;
            }

            case OutputPathMode.BinProjectPlatformArchConfiguration:
            {
                throw new NotSupportedException();
                break;
            }
            }

            // Convert all of the known references into references within the external project.
            var definitionsByName = definitions.ToDictionary(k => k.Name, v => v);

            foreach (var reference in document.XPathSelectElements("/Project/References/Reference"))
            {
                var includeAttribute = reference.Attribute(XName.Get("Include"));
                if (includeAttribute != null)
                {
                    if (definitionsByName.ContainsKey(includeAttribute.Value))
                    {
                        // This reference will be converted to an external project,
                        // so add a reference to it (in case it contains native binaries
                        // which need to be copied out).
                        var referenceEntry = externalProjectDocument.CreateElement("Reference");
                        referenceEntry.SetAttribute("Include", includeAttribute.Value);
                        externalProject.AppendChild(referenceEntry);
                    }
                }
            }

            // Copy out any files that are marked with copy-on-build flag.
            var detector    = new PlatformAndServiceActiveDetection();
            var xmlDocument = new XmlDocument();

            xmlDocument.Load(definition.DefinitionPath);
            var servicesInput         = this.m_ServiceInputGenerator.Generate(xmlDocument, definition.Name, services);
            var activeServicesElement = servicesInput.ChildNodes.OfType <XmlElement>().FirstOrDefault(x => x.LocalName == "ActiveServicesNames");
            var activeServices        = activeServicesElement.InnerText;

            foreach (var file in document.XPathSelectElements("/Project/Files/*"))
            {
                var copyOnBuild = file.XPathSelectElement("CopyToOutputDirectory");
                if (copyOnBuild == null)
                {
                    continue;
                }

                if (copyOnBuild.Value != "PreserveNewest" && copyOnBuild.Value != "Always")
                {
                    continue;
                }

                var platformsElement        = file.XPathSelectElement("Platforms");
                var includePlatformsElement = file.XPathSelectElement("IncludePlatforms");
                var excludePlatformsElement = file.XPathSelectElement("ExcludePlatforms");
                var servicesElement         = file.XPathSelectElement("Services");
                var includeServicesElement  = file.XPathSelectElement("IncludeServices");
                var excludeServicesElement  = file.XPathSelectElement("ExcludeServices");

                var platformsString        = platformsElement != null ? platformsElement.Value : string.Empty;
                var includePlatformsString = includePlatformsElement != null ? includePlatformsElement.Value : string.Empty;
                var excludePlatformsString = excludePlatformsElement != null ? excludePlatformsElement.Value : string.Empty;
                var servicesString         = servicesElement != null ? servicesElement.Value : string.Empty;
                var includeServicesString  = includeServicesElement != null ? includeServicesElement.Value : string.Empty;
                var excludeServicesString  = excludeServicesElement != null ? excludeServicesElement.Value : string.Empty;

                if (detector.ProjectAndServiceIsActive(
                        platformsString,
                        includePlatformsString,
                        excludePlatformsString,
                        servicesString,
                        includeServicesString,
                        excludeServicesString,
                        platform,
                        activeServices))
                {
                    var include     = file.Attribute(XName.Get("Include"));
                    var linkElement = file.XPathSelectElement("Link");
                    var link        = linkElement != null ? linkElement.Value : include.Value;

                    var fileInfo = new FileInfo(Path.Combine(
                                                    definition.ModulePath.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar),
                                                    definition.Path.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar),
                                                    include.Value.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar)));

                    if (definition.Type == "Library")
                    {
                        // For libraries, we're copying the content so that applications using
                        // the libraries will have the content.  This is most often used to
                        // ship native binaries (although NativeBinary in external projects now
                        // supersedes this).
                        if (link.Contains('/') || link.Contains('\\'))
                        {
                            Console.WriteLine(
                                "WARNING: Copy-on-build file '" + link + "' in library project which " +
                                "does not output to root of project detected.  This is not supported.");
                        }
                        else
                        {
                            if (fileInfo.Name != link)
                            {
                                Console.WriteLine(
                                    "WARNING: Copy-on-build file in library project does not have the same " +
                                    "name when copied to build directory.  This is not supported.");
                            }
                            else
                            {
                                var sourcePath = fileInfo.FullName;
                                sourcePath = sourcePath.Substring(rootPath.Length).Replace('\\', '/').TrimStart('/');
                                var destPath = Path.Combine("_AutomaticExternals", sourcePath);

                                var sourcePathRegex = this.ConvertPathWithMSBuildVariablesFind(sourcePath);
                                var destPathRegex   = this.ConvertPathWithMSBuildVariablesReplace(destPath.Replace('\\', '/'));

                                var includeMatch = fileFilter.ApplyInclude(sourcePathRegex);
                                fileFilter.ApplyRewrite(sourcePathRegex, destPathRegex);
                                if (includeMatch)
                                {
                                    var nativeBinaryEntry = externalProjectDocument.CreateElement("NativeBinary");
                                    nativeBinaryEntry.SetAttribute("Path", destPath);
                                    externalProject.AppendChild(nativeBinaryEntry);
                                }
                                else
                                {
                                    throw new InvalidOperationException(
                                              "File not found at " + sourcePath + " when converting " +
                                              "copy-on-build file in library project.");
                                }
                            }
                        }
                    }
                }
            }

            // Write out the external project to a temporary file and include it.
            var name = Path.GetRandomFileName() + "_" + definition.Name + ".xml";
            var temp = Path.Combine(Path.GetTempPath(), name);

            using (var writer = XmlWriter.Create(temp, new XmlWriterSettings {
                Indent = true, IndentChars = "  "
            }))
            {
                externalProjectDocument.WriteTo(writer);
            }
            fileFilter.AddManualMapping(temp, "Build/Projects/" + definition.Name + ".definition");
        }
        private void AutomaticallyPackageNormalProject(
            DefinitionInfo[] definitions,
            List<Service> services,  
            FileFilter fileFilter, 
            string rootPath,
            string platform,
            DefinitionInfo definition,
            List<string> temporaryFiles)
        {
            var document = XDocument.Load(definition.DefinitionPath);

            var externalProjectDocument = new XmlDocument();
            externalProjectDocument.AppendChild(externalProjectDocument.CreateXmlDeclaration("1.0", "UTF-8", null));
            var externalProject = externalProjectDocument.CreateElement("ExternalProject");
            externalProjectDocument.AppendChild(externalProject);
            externalProject.SetAttribute("Name", definition.Name);

            if (definition.PostBuildHook)
            {
                externalProject.SetAttribute("PostBuildHook", "True");
            }

            var externalProjectServices = externalProjectDocument.CreateElement("Services");
            externalProject.AppendChild(externalProjectServices);

            // Just import all declared services as available, regardless of conflicts or
            // requirements.  We don't have a clean way of automatically translating
            // services for packages (it has to be done manually because services can
            // change the resulting code that's built).  So that things work 95% of time,
            // just declare all services available for projects included via the automatic
            // packaging mechanism.
            var servicesToDeclare = new List<string>();
            var servicesDeclared = document.Root.Element(XName.Get("Services"));
            if (servicesDeclared != null)
            {
                foreach (var serviceElement in servicesDeclared.Elements().Where(x => x.Name.LocalName == "Service"))
                {
                    servicesToDeclare.Add(serviceElement.Attribute(XName.Get("Name")).Value);
                }
            }

            foreach (var serviceToDeclare in servicesToDeclare)
            {
                var serviceElem = externalProjectDocument.CreateElement("Service");
                serviceElem.SetAttribute("Name", serviceToDeclare);
                var defaultForRoot = externalProjectDocument.CreateElement("DefaultForRoot");
                defaultForRoot.InnerText = "True";
                serviceElem.AppendChild(defaultForRoot);
                externalProjectServices.AppendChild(serviceElem);
            }

            // Copy all existing references that the normal project makes to the external project.
            var referencesDeclared = document.Root.Element(XName.Get("References"));
            if (referencesDeclared != null)
            {
                foreach (var referenceElement in referencesDeclared.Elements().Where(x => x.Name.LocalName == "Reference"))
                {
                    var referenceElem = externalProjectDocument.CreateElement("Reference");
                    referenceElem.SetAttribute("Include", referenceElement.Attribute(XName.Get("Include")).Value);
                }
            }

            var pathPrefix = this.m_ProjectOutputPathCalculator.GetProjectOutputPathPrefix(platform, definition, document, true);
            var assemblyName = this.m_ProjectOutputPathCalculator.GetProjectAssemblyName(platform, definition, document);
            var outputMode = this.m_ProjectOutputPathCalculator.GetProjectOutputMode(document);

            var assemblyFilesToCopy = new[]
            {
                assemblyName + ".exe",
                assemblyName + ".dll",
                assemblyName + ".dll.config",
                assemblyName + ".dll.mdb",
                assemblyName + ".pdb",
                assemblyName + ".xml",
            };

            // Copy the assembly itself out to the package.
            switch (outputMode)
            {
                case OutputPathMode.BinConfiguration:
                    {
                        // In this configuration, we only ship the binaries for
                        // the default architecture (because that's all we know
                        // about).  We also have to assume the binary folder
                        // contains binaries for the desired platform.
                        if (definition.Type == "Library")
                        {
                            // For libraries, we only copy the assembly (and immediately related files)
                            // into it's directory. Native binaries will be expressed through the ExternalProject.
                            foreach (var assemblyFile in assemblyFilesToCopy)
                            {
                                var includeMatch = fileFilter.ApplyInclude("^" + pathPrefix + Regex.Escape(assemblyFile) + "$");
                                var rewriteMatch = fileFilter.ApplyRewrite("^" + pathPrefix + Regex.Escape(assemblyFile) + "$", definition.Name + "/AnyCPU/" + assemblyFile);
                                if (includeMatch && rewriteMatch)
                                {
                                    if (assemblyFile.EndsWith(".dll"))
                                    {
                                        var binaryEntry = externalProjectDocument.CreateElement("Binary");
                                        binaryEntry.SetAttribute("Name", assemblyFile.Substring(0, assemblyFile.Length - 4));
                                        binaryEntry.SetAttribute("Path", definition.Name + "\\AnyCPU\\" + assemblyFile);
                                        externalProject.AppendChild(binaryEntry);
                                    }
                                    else if (assemblyFile.EndsWith(".dll.config"))
                                    {
                                        var configEntry = externalProjectDocument.CreateElement("NativeBinary");
                                        configEntry.SetAttribute("Path", definition.Name + "\\AnyCPU\\" + assemblyFile);
                                        externalProject.AppendChild(configEntry);
                                    }
                                }
                                else if (includeMatch || rewriteMatch)
                                {
                                    throw new InvalidOperationException("Automatic filter; only one rule matched.");
                                }
                            }
                        }
                        else
                        {
                            // For executables, we ship everything in the output directory, because we
                            // want the executables to be able to run from the package directory.
                            fileFilter.ApplyInclude("^" + pathPrefix + "(.+)$");
                            fileFilter.ApplyRewrite("^" + pathPrefix + "(.+)$", definition.Name + "/AnyCPU/$2");

                            // Mark the executable files in the directory as tools that can be executed.
                            foreach (var assemblyFile in assemblyFilesToCopy)
                            {
                                if (assemblyFile.EndsWith(".exe"))
                                {
                                    var binaryEntry = externalProjectDocument.CreateElement("Tool");
                                    binaryEntry.SetAttribute("Name", assemblyFile.Substring(0, assemblyFile.Length - 4));
                                    binaryEntry.SetAttribute("Path", definition.Name + "\\AnyCPU\\" + assemblyFile);
                                    externalProject.AppendChild(binaryEntry);
                                }
                            }
                        }

                        break;
                    }
                case OutputPathMode.BinPlatformArchConfiguration:
                    {
                        // In this configuration, we ship binaries for AnyCPU, iPhoneSimulator or all .NET architectures
                        // depending on whether or not the platform produces multiple architectures.  On Mono,
                        // we can't use $(Platform) within a reference's path, so we have to keep this path static
                        // for Mono platforms.
                        string pathArchMatch, pathArchReplace, pathArchRuntime;
                        switch (platform.ToLowerInvariant())
                        {
                            case "ios":
                                {
                                    pathArchMatch = "iPhoneSimulator";
                                    pathArchReplace = "iPhoneSimulator";
                                    pathArchRuntime = "iPhoneSimulator";
                                    break;
                                }
                            case "windowsphone":
                                {
                                    pathArchMatch = "([^/]+)";
                                    pathArchReplace = "$1";
                                    pathArchRuntime = "$(Platform)";
                                    break;
                                }
                            default:
                                {
                                    pathArchMatch = "AnyCPU";
                                    pathArchReplace = "AnyCPU";
                                    pathArchRuntime = "AnyCPU";
                                    break;
                                }
                        }

                        if (definition.Type == "Library")
                        {
                            // For libraries, we only copy the assembly (and immediately related files)
                            // into it's directory. Native binaries will be expressed through the ExternalProject.
                            foreach (var assemblyFile in assemblyFilesToCopy)
                            {
                                var includeMatch = fileFilter.ApplyInclude("^" + pathPrefix + Regex.Escape(assemblyFile) + "$");
                                var rewriteMatch = fileFilter.ApplyRewrite("^" + pathPrefix + Regex.Escape(assemblyFile) + "$", definition.Name + "/" + pathArchReplace + "/" + assemblyFile);
                                if (includeMatch && rewriteMatch)
                                {
                                    if (assemblyFile.EndsWith(".dll"))
                                    {
                                        var binaryEntry = externalProjectDocument.CreateElement("Binary");
                                        binaryEntry.SetAttribute("Name", assemblyFile.Substring(0, assemblyFile.Length - 4));
                                        binaryEntry.SetAttribute("Path", definition.Name + "\\" + pathArchRuntime + "\\" + assemblyFile);
                                        externalProject.AppendChild(binaryEntry);
                                    }
                                    else if (assemblyFile.EndsWith(".dll.config"))
                                    {
                                        var configEntry = externalProjectDocument.CreateElement("NativeBinary");
                                        configEntry.SetAttribute("Path", definition.Name + "\\" + pathArchRuntime + "\\" + assemblyFile);
                                        externalProject.AppendChild(configEntry);
                                    }
                                }
                                else if (includeMatch || rewriteMatch)
                                {
                                    throw new InvalidOperationException("Automatic filter; only one rule matched.");
                                }
                            }
                        }
                        else
                        {
                            // For executables, we ship everything in the output directory, because we
                            // want the executables to be able to run from the package directory.
                            fileFilter.ApplyInclude("^" + pathPrefix + "(.+)$");

                            if (pathArchMatch == "([^/]+)")
                            {
                                fileFilter.ApplyRewrite("^" + pathPrefix + "(.+)$", definition.Name + "/" + pathArchReplace + "/$3");
                            }
                            else
                            {
                                fileFilter.ApplyRewrite("^" + pathPrefix + "(.+)$", definition.Name + "/" + pathArchReplace + "/$2");
                            }

                            // Mark the executable files in the directory as tools that can be executed.
                            foreach (var assemblyFile in assemblyFilesToCopy)
                            {
                                if (assemblyFile.EndsWith(".exe"))
                                {
                                    var binaryEntry = externalProjectDocument.CreateElement("Tool");
                                    binaryEntry.SetAttribute("Name", assemblyFile.Substring(0, assemblyFile.Length - 4));
                                    binaryEntry.SetAttribute("Path", definition.Name + "\\" + pathArchRuntime + "\\" + assemblyFile);
                                    externalProject.AppendChild(binaryEntry);
                                }
                            }
                        }

                        break;
                    }
                case OutputPathMode.BinProjectPlatformArchConfiguration:
                    {
                        throw new NotSupportedException();
                        break;
                    }
            }

            // Convert all of the known references into references within the external project.
            var definitionsByName = definitions.ToDictionarySafe(
                k => k.Name,
                v => v,
                (dict, x) =>
                {
                    var existing = dict[x.Name];
                    var tried = x;

                    Console.WriteLine("WARNING: There is more than one project with the name " +
                                      x.Name + " (first project loaded from " + tried.AbsolutePath + ", " +
                                      "skipped loading second project from " + existing.AbsolutePath + ")");
                });
            foreach (var reference in document.XPathSelectElements("/Project/References/Reference"))
            {
                var includeAttribute = reference.Attribute(XName.Get("Include"));
                if (includeAttribute != null)
                {
                    if (definitionsByName.ContainsKey(includeAttribute.Value))
                    {
                        // This reference will be converted to an external project,
                        // so add a reference to it (in case it contains native binaries
                        // which need to be copied out).
                        var referenceEntry = externalProjectDocument.CreateElement("Reference");
                        referenceEntry.SetAttribute("Include", includeAttribute.Value);
                        externalProject.AppendChild(referenceEntry);
                    }
                }
            }

            // Copy out any files that are marked with copy-on-build flag.
            var detector = new PlatformAndServiceActiveDetection();
            var xmlDocument = new XmlDocument();
            xmlDocument.Load(definition.DefinitionPath);
            var servicesInput = this.m_ServiceInputGenerator.Generate(xmlDocument, definition.Name, services);
            var activeServicesElement = servicesInput.ChildNodes.OfType<XmlElement>().FirstOrDefault(x => x.LocalName == "ActiveServicesNames");
            var activeServices = activeServicesElement.InnerText;
            foreach (var file in document.XPathSelectElements("/Project/Files/*"))
            {
                var copyOnBuild = file.XPathSelectElement("CopyToOutputDirectory");
                if (copyOnBuild == null)
                {
                    continue;
                }

                if (copyOnBuild.Value != "PreserveNewest" && copyOnBuild.Value != "Always")
                {
                    continue;
                }

                var platformsElement = file.XPathSelectElement("Platforms");
                var includePlatformsElement = file.XPathSelectElement("IncludePlatforms");
                var excludePlatformsElement = file.XPathSelectElement("ExcludePlatforms");
                var servicesElement = file.XPathSelectElement("Services");
                var includeServicesElement = file.XPathSelectElement("IncludeServices");
                var excludeServicesElement = file.XPathSelectElement("ExcludeServices");

                var platformsString = platformsElement != null ? platformsElement.Value : string.Empty;
                var includePlatformsString = includePlatformsElement != null ? includePlatformsElement.Value : string.Empty;
                var excludePlatformsString = excludePlatformsElement != null ? excludePlatformsElement.Value : string.Empty;
                var servicesString = servicesElement != null ? servicesElement.Value : string.Empty;
                var includeServicesString = includeServicesElement != null ? includeServicesElement.Value : string.Empty;
                var excludeServicesString = excludeServicesElement != null ? excludeServicesElement.Value : string.Empty;

                if (detector.ProjectAndServiceIsActive(
                    platformsString,
                    includePlatformsString,
                    excludePlatformsString,
                    servicesString,
                    includeServicesString,
                    excludeServicesString,
                    platform,
                    activeServices))
                {
                    var include = file.Attribute(XName.Get("Include"));
                    var linkElement = file.XPathSelectElement("Link");
                    var link = linkElement != null ? linkElement.Value : include.Value;

                    var fileInfo = new FileInfo(Path.Combine(
                        definition.AbsolutePath.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar),
                        include.Value.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar)));

                    if (definition.Type == "Library")
                    {
                        // For libraries, we're copying the content so that applications using
                        // the libraries will have the content.  This is most often used to
                        // ship native binaries (although NativeBinary in external projects now
                        // supersedes this).
                        if (link.Contains('/') || link.Contains('\\'))
                        {
                            Console.WriteLine(
                                "WARNING: Copy-on-build file '" + link + "' in library project which " +
                                "does not output to root of project detected.  This is not supported.");
                        }
                        else
                        {
                            if (fileInfo.Name != link)
                            {
                                Console.WriteLine(
                                    "WARNING: Copy-on-build file in library project does not have the same " +
                                    "name when copied to build directory.  This is not supported.");
                            }
                            else
                            {
                                var sourcePath = fileInfo.FullName;
                                sourcePath = sourcePath.Substring(rootPath.Length).Replace('\\', '/').TrimStart('/');
                                var destPath = Path.Combine("_AutomaticExternals", sourcePath);

                                var sourcePathRegex = this.ConvertPathWithMSBuildVariablesFind(sourcePath);
                                var destPathRegex = this.ConvertPathWithMSBuildVariablesReplace(destPath.Replace('\\', '/'));

                                var includeMatch = fileFilter.ApplyInclude(sourcePathRegex);
                                fileFilter.ApplyRewrite(sourcePathRegex, destPathRegex);
                                if (includeMatch)
                                {
                                    var nativeBinaryEntry = externalProjectDocument.CreateElement("NativeBinary");
                                    nativeBinaryEntry.SetAttribute("Path", destPath);
                                    externalProject.AppendChild(nativeBinaryEntry);
                                }
                                else
                                {
                                    throw new InvalidOperationException(
                                        "File not found at " + sourcePath + " when converting " +
                                        "copy-on-build file in library project.");
                                }
                            }
                        }
                    }
                }
            }

            // Write out the external project to a temporary file and include it.
            var name = Path.GetRandomFileName() + "_" + definition.Name + ".xml";
            var temp = Path.Combine(Path.GetTempPath(), name);
            temporaryFiles.Add(temp);
            using (var writer = XmlWriter.Create(temp, new XmlWriterSettings { Indent = true, IndentChars = "  " }))
            {
                externalProjectDocument.WriteTo(writer);
            }
            fileFilter.AddManualMapping(temp, "Build/Projects/" + definition.Name + ".definition");
        }