private void AutomaticallyPackageExternalProject(
            DefinitionInfo[] definitions,
            List <Service> services,
            FileFilter fileFilter,
            string rootPath,
            string platform,
            DefinitionInfo definition,
            List <string> temporaryFiles)
        {
            var document = new XmlDocument();

            document.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);

            // Translate all of the references (this is a seperate method so we can call it
            // again when traversing into Platform nodes).
            this.TranslateExternalProject(
                definition,
                services,
                fileFilter,
                rootPath,
                platform,
                document.DocumentElement,
                externalProject,
                false);

            // 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");
        }
        public void Autopackage(
            FileFilter fileFilter,
            Execution execution,
            ModuleInfo module,
            string rootPath,
            string platform)
        {
            var definitions    = module.GetDefinitionsRecursively(platform).ToArray();
            var loadedProjects = new List <XmlDocument>();

            foreach (var definition in definitions)
            {
                Console.WriteLine("Loading: " + definition.Name);
                loadedProjects.Add(
                    this.m_ProjectLoader.Load(
                        Path.Combine(
                            definition.ModulePath,
                            "Build",
                            "Projects",
                            definition.Name + ".definition"),
                        platform,
                        module.Path,
                        definition.ModulePath));
            }

            var            serviceManager = new ServiceManager(platform);
            List <Service> services;

            serviceManager.SetRootDefinitions(module.GetDefinitions());

            var enabledServices  = execution.EnabledServices.ToArray();
            var disabledServices = execution.DisabledServices.ToArray();

            foreach (var service in enabledServices)
            {
                serviceManager.EnableService(service);
            }

            foreach (var service in disabledServices)
            {
                serviceManager.DisableService(service);
            }

            services = serviceManager.CalculateDependencyGraph(loadedProjects);

            foreach (var service in services)
            {
                if (service.ServiceName != null)
                {
                    Console.WriteLine("Enabled service: " + service.FullName);
                }
            }

            foreach (var definition in definitions)
            {
                if (definition.SkipAutopackage)
                {
                    Console.WriteLine("Skipping: " + definition.Name);
                    continue;
                }

                switch (definition.Type)
                {
                case "External":
                    Console.WriteLine("Packaging: " + definition.Name);
                    this.AutomaticallyPackageExternalProject(definitions, services, fileFilter, rootPath, platform, definition);
                    break;

                case "Content":
                    Console.WriteLine("Content project definition skipped: " + definition.Name);
                    break;

                default:
                    Console.WriteLine("Packaging: " + definition.Name);
                    this.AutomaticallyPackageNormalProject(definitions, services, fileFilter, rootPath, platform, definition);
                    break;
                }
            }

            // If there is no Module.xml in the source mappings already, then copy the current module.
            var filterDictionary = fileFilter.ToDictionary(k => k.Key, v => v.Value);

            if (!filterDictionary.ContainsValue("Build/Module.xml"))
            {
                fileFilter.AddManualMapping(Path.Combine(module.Path, "Build", "Module.xml"), "Build/Module.xml");
            }
        }
        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");
        }
        public void Autopackage(
            string workingDirectory,
            FileFilter fileFilter,
            Execution execution,
            ModuleInfo module,
            string rootPath,
            string platform,
            string packageFormat,
            List <string> temporaryFiles)
        {
            var definitions    = module.GetDefinitionsRecursively(platform).ToArray();
            var loadedProjects = new List <LoadedDefinitionInfo>();

            foreach (var definition in definitions)
            {
                RedirectableConsole.WriteLine("Loading: " + definition.Name);
                loadedProjects.Add(
                    this.m_ProjectLoader.Load(
                        platform,
                        module,
                        definition));
            }

            var            serviceManager = new ServiceManager(platform);
            List <Service> services;

            serviceManager.SetRootDefinitions(module.GetDefinitions());

            var enabledServices  = execution.EnabledServices.ToArray();
            var disabledServices = execution.DisabledServices.ToArray();

            foreach (var service in enabledServices)
            {
                serviceManager.EnableService(service);
            }

            foreach (var service in disabledServices)
            {
                serviceManager.DisableService(service);
            }

            if (execution.DebugServiceResolution)
            {
                serviceManager.EnableDebugInformation();
            }

            services = serviceManager.CalculateDependencyGraph(loadedProjects.Select(x => x.Project).ToList());

            foreach (var service in services)
            {
                if (service.ServiceName != null)
                {
                    RedirectableConsole.WriteLine("Enabled service: " + service.FullName);
                }
            }

            var packagePaths = module.Packages
                               .Select(x => new DirectoryInfo(System.IO.Path.Combine(module.Path, x.Folder)).FullName)
                               .ToArray();

            foreach (var definition in definitions)
            {
                if (definition.SkipAutopackage)
                {
                    RedirectableConsole.WriteLine("Skipping: " + definition.Name);
                    continue;
                }

                var definitionNormalizedPath = new FileInfo(definition.AbsolutePath).FullName;
                if (packagePaths.Any(definitionNormalizedPath.StartsWith))
                {
                    RedirectableConsole.WriteLine("Skipping: " + definition.Name + " (part of another package)");
                    continue;
                }

                switch (definition.Type)
                {
                case "External":
                    RedirectableConsole.WriteLine("Packaging: " + definition.Name);
                    this.AutomaticallyPackageExternalProject(definitions, services, fileFilter, rootPath, platform, definition, temporaryFiles);
                    break;

                case "Include":
                    RedirectableConsole.WriteLine("Packaging: " + definition.Name);
                    this.AutomaticallyPackageIncludeProject(definitions, services, fileFilter, rootPath, platform, definition);
                    break;

                case "Content":
                    RedirectableConsole.WriteLine("Content project definition skipped: " + definition.Name);
                    break;

                default:
                    RedirectableConsole.WriteLine("Packaging: " + definition.Name);
                    this.AutomaticallyPackageNormalProject(definitions, services, fileFilter, rootPath, platform, definition, temporaryFiles);
                    break;
                }
            }

            // If there is no Module.xml in the source mappings already, then copy the current module.
            if (!fileFilter.ContainsTargetPath("Build/Module.xml"))
            {
                fileFilter.AddManualMapping(Path.Combine(module.Path, "Build", "Module.xml"), "Build/Module.xml");
            }
        }