public XslCompiledTransform LoadXSLT(ResourceType resourceType, Language language, string platform)
        {
            var currentDir = m_WorkingDirectoryProvider.GetPath();

            if (!m_CachedTransforms.ContainsKey(currentDir))
            {
                m_CachedTransforms[currentDir] = new Dictionary <int, XslCompiledTransform>();
            }
            var cache = m_CachedTransforms[currentDir];

            int hash;

            unchecked
            {
                hash = 17 *
                       resourceType.GetHashCode() * 31 +
                       language.GetHashCode() * 31 +
                       platform.GetHashCode() * 31;
            }
            if (cache.ContainsKey(hash))
            {
                return(cache[hash]);
            }

            var source = this.LoadOverriddableResource(resourceType, language, platform);

            var reader2       = new StreamReader(source);
            var readerInspect = reader2.ReadToEnd();

            source.Seek(0, SeekOrigin.Begin);

            var resolver = new EmbeddedResourceResolver();
            var result   = new XslCompiledTransform();

            using (var reader = XmlReader.Create(source))
            {
                try
                {
                    result.Load(
                        reader,
                        XsltSettings.TrustedXslt,
                        resolver
                        );
                }
                catch (XsltException ex)
                {
                    var lines         = readerInspect.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None);
                    var line          = ex.LineNumber;
                    var minLine       = Math.Max(line - 10, 0);
                    var maxLine       = Math.Min(line + 10, lines.Length - 1);
                    var selectedLines = new List <string>();
                    for (var l = minLine; l <= maxLine; l++)
                    {
                        if (l == line)
                        {
                            selectedLines.Add(">> " + lines[l]);
                        }
                        else
                        {
                            selectedLines.Add("   " + lines[l]);
                        }
                    }
                    var context = string.Join(Environment.NewLine, selectedLines);
                    throw new XsltCompileException(
                              ex.Message + "\r\n" + context,
                              ex);
                }
            }

            cache[hash] = result;
            return(result);
        }
        public int Execute(Execution execution)
        {
            var assemblyPath = Assembly.GetEntryAssembly().Location;
            var fileInfo     = new FileInfo(assemblyPath);
            var modulePath   = fileInfo.DirectoryName;

            if (modulePath == null)
            {
                Console.WriteLine(
                    "Unable to determine the location of Protobuild.");
                return(1);
            }

            if (!File.Exists(Path.Combine(modulePath, "Build", "Module.xml")))
            {
                modulePath = _workingDirectoryProvider.GetPath();
            }

            string executablePath = null;

            if (!File.Exists(Path.Combine(modulePath, "Build", "Module.xml")))
            {
                // We can only run global tools.
                var globalToolPath = this.m_PackageGlobalTool.ResolveGlobalToolIfPresent(execution.ExecuteProjectName);
                if (globalToolPath == null)
                {
                    Console.WriteLine(
                        "There is no global tool registered as '" + execution.ExecuteProjectName + "'");
                    return(1);
                }
                else
                {
                    executablePath = globalToolPath;
                }
            }
            else
            {
                var platform    = this.m_HostPlatformDetector.DetectPlatform();
                var module      = ModuleInfo.Load(Path.Combine(modulePath, "Build", "Module.xml"));
                var definitions = module.GetDefinitionsRecursively(platform).ToList();
                var target      = definitions.FirstOrDefault(x => x.Name == execution.ExecuteProjectName);
                if (target == null)
                {
                    // Check to see if there is any external project definition that provides the tool.
                    foreach (var definition in definitions)
                    {
                        var document = XDocument.Load(definition.DefinitionPath);
                        if (document.Root.Name.LocalName == "ExternalProject")
                        {
                            foreach (var node in document.Root.Elements().Where(x => x.Name.LocalName == "Tool"))
                            {
                                var name = node.Attribute(XName.Get("Name")).Value;
                                var path = node.Attribute(XName.Get("Path")).Value;

                                if (name == execution.ExecuteProjectName)
                                {
                                    executablePath = Path.Combine(definition.ModulePath, path.Replace('\\', Path.DirectorySeparatorChar).Replace('/', Path.DirectorySeparatorChar));
                                    break;
                                }
                            }
                        }
                    }

                    if (executablePath == null)
                    {
                        var globalToolPath = this.m_PackageGlobalTool.ResolveGlobalToolIfPresent(execution.ExecuteProjectName);
                        if (globalToolPath == null)
                        {
                            Console.WriteLine(
                                "There is no project definition with name '" + execution.ExecuteProjectName + "'");
                            return(1);
                        }
                        else
                        {
                            executablePath = globalToolPath;
                        }
                    }
                }
                else
                {
                    var document = XDocument.Load(target.DefinitionPath);
                    if (document.Root.Name.LocalName == "Project")
                    {
                        var assemblyName       = this.m_ProjectOutputPathCalculator.GetProjectAssemblyName(platform, target, document);
                        var prefixPath         = this.m_ProjectOutputPathCalculator.GetProjectOutputPathPrefix(platform, target, document, false);
                        var directory          = new DirectoryInfo(Path.Combine(modulePath, prefixPath));
                        var subdirectories     = directory.GetDirectories();
                        var preferredName      = (execution.ExecuteProjectConfiguration ?? "Debug").ToLowerInvariant();
                        var preferredDirectory = subdirectories.FirstOrDefault(x => x.Name.ToLowerInvariant() == preferredName);
                        if (preferredDirectory != null && File.Exists(Path.Combine(preferredDirectory.FullName, assemblyName + ".exe")))
                        {
                            executablePath = Path.Combine(preferredDirectory.FullName, assemblyName + ".exe");
                        }
                        else
                        {
                            string tempPath = null;
                            foreach (var subdirectory in subdirectories)
                            {
                                tempPath = Path.Combine(subdirectory.FullName, assemblyName + ".exe");
                                if (File.Exists(tempPath))
                                {
                                    break;
                                }
                            }
                            if (tempPath != null && File.Exists(tempPath))
                            {
                                executablePath = tempPath;
                            }
                        }
                    }
                    else if (document.Root.Name.LocalName == "ExternalProject")
                    {
                        foreach (var node in document.Root.Elements().Where(x => x.Name.LocalName == "Tool"))
                        {
                            var name = node.Attribute(XName.Get("Name")).Value;
                            var path = node.Attribute(XName.Get("Path")).Value;

                            if (name == execution.ExecuteProjectName)
                            {
                                executablePath = Path.Combine(target.ModulePath, path.Replace('\\', Path.DirectorySeparatorChar).Replace('/', Path.DirectorySeparatorChar));
                                break;
                            }
                        }
                    }

                    if (executablePath == null)
                    {
                        var globalToolPath = this.m_PackageGlobalTool.ResolveGlobalToolIfPresent(execution.ExecuteProjectName);
                        if (globalToolPath == null)
                        {
                            Console.WriteLine(
                                "There is no output path for '" + execution.ExecuteProjectName + "'; has the project been built?");
                            return(1);
                        }
                        else
                        {
                            executablePath = globalToolPath;
                        }
                    }
                }
            }

            if (!File.Exists(executablePath))
            {
                Console.WriteLine(
                    "There is no executable for '" + execution.ExecuteProjectName + "'; has the project been built?");
                return(1);
            }

            var arguments = string.Empty;

            if (execution.ExecuteProjectArguments.Length > 0)
            {
                arguments = execution.ExecuteProjectArguments
                            .Select(x => "\"" + x.Replace("\"", "\\\"") + "\"")
                            .Aggregate((a, b) => a + " " + b);
            }

            ProcessStartInfo startInfo;

            if (Path.DirectorySeparatorChar == '/')
            {
                var mono = "mono";
                if (m_HostPlatformDetector.DetectPlatform() == "MacOS" && File.Exists("/usr/local/bin/mono"))
                {
                    // After upgrading to OSX El Capitan, the /usr/local/bin folder is no longer in
                    // the system PATH.  If we can't find Mono with the which tool, manually set the
                    // path here in an attempt to find it.
                    mono = "/usr/local/bin/mono";
                }

                startInfo = new ProcessStartInfo(
                    mono,
                    "--debug \"" + executablePath + "\" " + arguments);
            }
            else
            {
                startInfo = new ProcessStartInfo(
                    executablePath,
                    arguments);
            }
            startInfo.UseShellExecute = false;

            var process = Process.Start(startInfo);

            process.WaitForExit();
            return(process.ExitCode);
        }