Example #1
0
        private T PerformRetryableRequest <T>(string message, Uri baseUri, Func <Uri, T> func)
        {
            var exceptions = new List <Exception>();
            var backoff    = 100;

            for (var i = 0; i < MaxRequests; i++)
            {
                try
                {
                    RedirectableConsole.WriteLine("(" + (i + 1) + "/" + MaxRequests + ") " + message);
                    return(func(baseUri));
                }
                catch (Exception ex)
                {
                    exceptions.Add(ex);

                    var webException = ex as WebException;
                    if (webException != null)
                    {
                        switch (webException.Status)
                        {
                        case WebExceptionStatus.ProtocolError:
                            var httpWebResponse = webException.Response as HttpWebResponse;
                            if (httpWebResponse != null)
                            {
                                switch (httpWebResponse.StatusCode)
                                {
                                case HttpStatusCode.NotFound:
                                case HttpStatusCode.Forbidden:
                                    // This is a permanent failure.
                                    i       = MaxRequests;
                                    backoff = 0;
                                    break;
                                }
                            }
                            break;

                        case WebExceptionStatus.ServerProtocolViolation:
                        case WebExceptionStatus.NameResolutionFailure:
                            // This is a permanent failure.
                            i       = MaxRequests;
                            backoff = 0;
                            break;
                        }
                    }

                    if (!SilentOnError || i != MaxRequests || backoff != 0)
                    {
                        RedirectableConsole.ErrorWriteLine("Exception during web request: ");
                        RedirectableConsole.ErrorWriteLine(ex);

                        RedirectableConsole.WriteLine("Backing off web requests for " + backoff + "ms...");
                    }
                    System.Threading.Thread.Sleep(backoff);
                    backoff *= 2;
                    if (backoff > 20000)
                    {
                        backoff = 20000;
                    }
                }
            }

            throw new AggregateException(exceptions);
        }
Example #2
0
        private static void PrintHelp(Dictionary <string, ICommand> commandMappings)
        {
            RedirectableConsole.WriteLine("Protobuild.exe [options]");
            RedirectableConsole.WriteLine();
            RedirectableConsole.WriteLine("By default Protobuild resynchronises or generates projects for");
            RedirectableConsole.WriteLine("the current platform, depending on the module configuration.");
            RedirectableConsole.WriteLine();

            foreach (var kv in commandMappings)
            {
                if (kv.Value.IsInternal() || !kv.Value.IsRecognised() || kv.Value.IsIgnored())
                {
                    continue;
                }

                var description = kv.Value.GetDescription();
                description = description.Replace("\n", " ");
                description = description.Replace("\r", "");

                var lines      = new List <string>();
                var wordBuffer = string.Empty;
                var lineBuffer = string.Empty;
                var count      = 0;
                var last       = false;
                for (var i = 0; i < description.Length || wordBuffer.Length > 0; i++)
                {
                    if (i < description.Length)
                    {
                        if (description[i] == ' ')
                        {
                            if (wordBuffer.Length > 0)
                            {
                                lineBuffer += wordBuffer + " ";
                            }

                            wordBuffer = string.Empty;
                        }
                        else
                        {
                            wordBuffer += description[i];
                            count++;
                        }
                    }
                    else
                    {
                        lineBuffer += wordBuffer + " ";
                        count++;
                        last = true;
                    }

                    if (count >= 74)
                    {
                        lines.Add(lineBuffer);
                        lineBuffer = string.Empty;
                        count      = 0;
                    }

                    if (last)
                    {
                        break;
                    }
                }

                if (count > 0)
                {
                    lines.Add(lineBuffer);
                    lineBuffer = string.Empty;
                }

                var argDesc = string.Empty;
                foreach (var arg in kv.Value.GetArgNames())
                {
                    if (arg.EndsWith("?"))
                    {
                        argDesc += " [" + arg.TrimEnd('?') + "]";
                    }
                    else
                    {
                        argDesc += " " + arg;
                    }
                }

                RedirectableConsole.WriteLine("  -" + kv.Key + argDesc);
                RedirectableConsole.WriteLine();

                foreach (var line in lines)
                {
                    RedirectableConsole.WriteLine("  " + line);
                }

                RedirectableConsole.WriteLine();
            }
        }
Example #3
0
        public int Execute(Execution execution)
        {
            var    hostPlatform          = _hostPlatformDetector.DetectPlatform();
            string builderPathNativeArch = null;
            string builderPath64         = null;
            string builderPath32         = null;
            var    extraArgsNativeArch   = string.Empty;
            var    extraArgs64           = string.Empty;
            var    extraArgs32           = string.Empty;
            var    extraArgsGeneral      = string.Empty;

            var targetPlatforms = (execution.Platform ?? hostPlatform).Split(',');
            var module          = ModuleInfo.Load(Path.Combine(execution.WorkingDirectory, "Build", "Module.xml"));

            if (hostPlatform == "Windows")
            {
                // Newer installs of Visual Studio (like 2017) don't create registry entries for MSBuild, so we have to
                // use a tool called vswhere in order to find MSBuild on these systems.  This call will implicitly install
                // the vswhere package if it's not already installed.
                var           vswhere       = _knownToolProvider.GetToolExecutablePath("vswhere");
                List <string> installations = null;
                if (vswhere != null && File.Exists(vswhere))
                {
                    try
                    {
                        var processStartInfo = new ProcessStartInfo();
                        processStartInfo.FileName               = vswhere;
                        processStartInfo.Arguments              = "-products * -requires Microsoft.Component.MSBuild -property installationPath";
                        processStartInfo.UseShellExecute        = false;
                        processStartInfo.RedirectStandardOutput = true;
                        var process             = Process.Start(processStartInfo);
                        var installationsString = process.StandardOutput.ReadToEnd();
                        installations = installationsString.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries).Where(x => !string.IsNullOrWhiteSpace(x)).ToList();
                        process.WaitForExit();

                        if (process.ExitCode != 0)
                        {
                            RedirectableConsole.ErrorWriteLine("Unable to locate Visual Studio 2017 and later installations (non-zero exit code from vswhere)");
                        }
                    }
                    catch (Exception ex)
                    {
                        RedirectableConsole.ErrorWriteLine("Unable to locate Visual Studio 2017 and later installations: " + ex.Message);
                    }
                }

                if (installations != null)
                {
                    // Check if MSBuild is present in any of those installation paths.
                    foreach (var basePath in installations)
                    {
                        var msbuildLocation = Path.Combine(basePath, "MSBuild\\15.0\\Bin\\MSBuild.exe");
                        if (File.Exists(msbuildLocation))
                        {
                            builderPathNativeArch = msbuildLocation;
                            extraArgsNativeArch   = "/m /nodeReuse:false ";
                            builderPath32         = msbuildLocation;
                            extraArgs32           = "/m /nodeReuse:false ";

                            var x64Location = Path.Combine(basePath, "MSBuild\\15.0\\Bin\\amd64\\MSBuild.exe");
                            if (File.Exists(x64Location))
                            {
                                builderPath64 = x64Location;
                                extraArgs64   = "/m /nodeReuse:false ";
                            }

                            break;
                        }
                    }
                }

                if (builderPathNativeArch == null)
                {
                    // Try to find via the registry.
                    foreach (var arch in new[] { RegistryView.Default, RegistryView.Registry32, RegistryView.Registry64 })
                    {
                        // Find latest version of MSBuild.
                        var registryKey =
                            RegistryKey.OpenBaseKey(
                                RegistryHive.LocalMachine,
                                arch)
                            .OpenSubKey("SOFTWARE")?
                            .OpenSubKey("Microsoft")?
                            .OpenSubKey("MSBuild")?
                            .OpenSubKey("ToolsVersions");
                        if (registryKey == null)
                        {
                            if (arch == RegistryView.Registry64)
                            {
                                continue;
                            }

                            RedirectableConsole.ErrorWriteLine(
                                "ERROR: No versions of MSBuild were available " +
                                "according to the registry (or they were not readable).");
                            return(1);
                        }

                        var subkeys         = registryKey.GetSubKeyNames();
                        var orderedVersions =
                            subkeys.OrderByDescending(x => int.Parse(x.Split('.').First(), CultureInfo.InvariantCulture));
                        var builderPath = (from version in orderedVersions
                                           let path = (string)registryKey.OpenSubKey(version)?.GetValue("MSBuildToolsPath")
                                                      where path != null && Directory.Exists(path)
                                                      let msbuild = Path.Combine(path, "MSBuild.exe")
                                                                    where File.Exists(msbuild)
                                                                    select msbuild).FirstOrDefault();

                        if (builderPath == null)
                        {
                            if (arch == RegistryView.Registry64)
                            {
                                continue;
                            }

                            RedirectableConsole.ErrorWriteLine(
                                "ERROR: Unable to find installed MSBuild in any installed tools version.");
                            return(1);
                        }

                        var extraArgs = string.Empty;
                        if (!builderPath.Contains("v2.0.50727"))
                        {
                            extraArgs = "/m /nodeReuse:false ";
                        }

                        switch (arch)
                        {
                        case RegistryView.Default:
                            builderPathNativeArch = builderPath;
                            extraArgsNativeArch   = extraArgs;
                            break;

                        case RegistryView.Registry32:
                            builderPath32 = builderPath;
                            extraArgs32   = extraArgs;
                            break;

                        case RegistryView.Registry64:
                            builderPath64 = builderPath;
                            extraArgs64   = extraArgs;
                            break;
                        }
                    }
                }
            }
            else
            {
                // Find path to xbuild.
                var whichPaths = new[] { "/bin/which", "/usr/bin/which" };

                // We can only use the new MSBuild tool if no projects are C++ projects on Mac or Linux.
                var isAnyNativeProject = false;
                foreach (var def in module.GetDefinitionsRecursively())
                {
                    var document     = XDocument.Load(def.DefinitionPath);
                    var languageAttr = document?.Root?.Attributes()?.FirstOrDefault(x => x.Name.LocalName == "Language");
                    if (languageAttr != null && languageAttr.Value == "C++")
                    {
                        isAnyNativeProject = true;
                        break;
                    }
                }
                if (!isAnyNativeProject)
                {
                    foreach (var w in whichPaths)
                    {
                        if (File.Exists(w))
                        {
                            var whichProcess = Process.Start(new ProcessStartInfo(w, "msbuild")
                            {
                                RedirectStandardOutput = true,
                                UseShellExecute        = false
                            });
                            if (whichProcess == null)
                            {
                                continue;
                            }
                            var result = whichProcess.StandardOutput.ReadToEnd().Trim();
                            if (!string.IsNullOrWhiteSpace(result) && File.Exists(result))
                            {
                                builderPathNativeArch = result;
                                break;
                            }
                        }
                    }
                }

                if (builderPathNativeArch == null)
                {
                    foreach (var w in whichPaths)
                    {
                        if (File.Exists(w))
                        {
                            var whichProcess = Process.Start(new ProcessStartInfo(w, "xbuild")
                            {
                                RedirectStandardOutput = true,
                                UseShellExecute        = false
                            });
                            if (whichProcess == null)
                            {
                                continue;
                            }
                            var result = whichProcess.StandardOutput.ReadToEnd().Trim();
                            if (!string.IsNullOrWhiteSpace(result) && File.Exists(result))
                            {
                                builderPathNativeArch = result;
                                break;
                            }
                        }
                    }
                }

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

                if (builderPathNativeArch == null)
                {
                    RedirectableConsole.ErrorWriteLine("ERROR: Unable to find msbuild or xbuild on the current PATH.");
                    return(1);
                }

                builderPath32 = builderPathNativeArch;
                builderPath64 = builderPathNativeArch;
            }

            if (!string.IsNullOrWhiteSpace(execution.BuildTarget))
            {
                extraArgsGeneral += "/t:\"" + execution.BuildTarget + "\" ";
            }
            foreach (var prop in execution.BuildProperties)
            {
                extraArgsGeneral += "/p:\"" + prop.Key.Replace("\"", "\\\"") + "\"=\"" + (prop.Value ?? string.Empty).Replace("\"", "\\\"") + "\" ";
            }

            switch (execution.BuildProcessArchitecture)
            {
            case "x86":
                RedirectableConsole.WriteLine("INFO: Using " + builderPath32 + " (forced 32-bit) to perform this build.");
                break;

            case "x64":
                RedirectableConsole.WriteLine("INFO: Using " + builderPath64 + " (forced 64-bit) to perform this build.");
                break;

            case "Default":
            default:
                RedirectableConsole.WriteLine("INFO: Using " + builderPathNativeArch + " (32-bit: " + builderPath32 + ") to perform this build.");
                break;
            }

            foreach (var platform in targetPlatforms)
            {
                string builderPath;
                string extraArgs;

                switch (execution.BuildProcessArchitecture)
                {
                case "x86":
                    builderPath = builderPath32;
                    extraArgs   = extraArgs32 + extraArgsGeneral;
                    break;

                case "x64":
                    builderPath = builderPath64;
                    extraArgs   = extraArgs64 + extraArgsGeneral;
                    break;

                case "Default":
                default:
                    builderPath = platform == "WindowsPhone" ? builderPath32 : builderPathNativeArch;
                    extraArgs   = (platform == "WindowsPhone" ? extraArgs32 : extraArgsNativeArch) + extraArgsGeneral;
                    break;
                }

                var fileToBuild = module.Name + "." + platform + ".sln";

                RedirectableConsole.WriteLine("INFO: Executing " + builderPath + " with arguments: " + extraArgs + fileToBuild);

                var process =
                    Process.Start(new ProcessStartInfo(builderPath, extraArgs + fileToBuild)
                {
                    UseShellExecute = false
                });
                if (process == null)
                {
                    RedirectableConsole.ErrorWriteLine("ERROR: Build process did not start successfully.");
                    return(1);
                }
                process.WaitForExit();

                if (process.ExitCode != 0)
                {
                    return(process.ExitCode);
                }
            }

            return(0);
        }
        public int ExecuteForTemplate(Execution execution)
        {
            if (!Directory.Exists(execution.PackageSourceFolder))
            {
                throw new InvalidOperationException("The source folder " + execution.PackageSourceFolder + " does not exist.");
            }

            RedirectableConsole.WriteLine("Starting package creation for " + execution.PackagePlatform);

            var filter = new FileFilter(_getRecursiveUtilitiesInPath.GetRecursiveFilesInPath(execution.PackageSourceFolder));

            if (execution.PackageFilterFile != null)
            {
                using (var reader = new StreamReader(execution.PackageFilterFile))
                {
                    var contents = reader.ReadToEnd();
                    contents = contents.Replace("%PLATFORM%", execution.PackagePlatform);

                    using (var inputStream = new MemoryStream(Encoding.ASCII.GetBytes(contents)))
                    {
                        this.m_FileFilterParser.ParseAndApply(filter, inputStream, new Dictionary <string, Action <FileFilter> >());
                    }
                }
            }
            else
            {
                filter.ApplyInclude("^.*$");
                filter.ApplyExclude("^\\.git/.*$");
                filter.ApplyExclude("^\\.hg/.*$");
                filter.ApplyExclude("^\\.svn/.*$");
            }

            if (File.Exists(execution.PackageDestinationFile))
            {
                RedirectableConsole.WriteLine("The destination file " + execution.PackageDestinationFile + " already exists; it will be overwritten.");
                File.Delete(execution.PackageDestinationFile);
            }

            filter.ImplyDirectories();

            var filterDictionary = filter.ToDictionary(k => k.Key, v => v.Value);

            if (!filter.ContainsTargetPath("Build/"))
            {
                RedirectableConsole.WriteLine("ERROR: The Build directory does not exist in the source folder.");
                if (execution.PackageFilterFile != null)
                {
                    this.PrintFilterMappings(filter);
                }
                return(1);
            }

            if (!filter.ContainsTargetPath("Build/Projects/"))
            {
                RedirectableConsole.WriteLine("ERROR: The Build\\Projects directory does not exist in the source folder.");
                if (execution.PackageFilterFile != null)
                {
                    this.PrintFilterMappings(filter);
                }
                return(1);
            }

            if (!filter.ContainsTargetPath("Build/Module.xml"))
            {
                RedirectableConsole.WriteLine("ERROR: The Build\\Module.xml file does not exist in the source folder.");
                if (execution.PackageFilterFile != null)
                {
                    this.PrintFilterMappings(filter);
                }
                return(1);
            }

            if (filter.ContainsTargetPath("Protobuild.exe"))
            {
                RedirectableConsole.WriteLine("ERROR: The Protobuild.exe file should not be included in the package file.");
                if (execution.PackageFilterFile != null)
                {
                    this.PrintFilterMappings(filter);
                }
                return(1);
            }

            using (var target = new FileStream(execution.PackageDestinationFile, FileMode.CreateNew, FileAccess.Write, FileShare.None))
            {
                _packageCreator.Create(
                    target,
                    filter,
                    execution.PackageSourceFolder,
                    execution.PackageFormat,
                    execution.PackagePlatform,
                    execution.PackageDestinationFile);
            }

            RedirectableConsole.WriteLine("\rPackage written to " + execution.PackageDestinationFile + " successfully.");
            return(0);
        }
Example #5
0
        public void Resolve(string workingDirectory, IPackageMetadata metadata, PackageRef reference, string templateName, bool?source,
                            bool forceUpgrade, bool?safeResolve)
        {
            if (reference.Folder == null)
            {
                if (metadata.PackageType == PACKAGE_TYPE_GLOBAL_TOOL)
                {
                }
                else
                {
                    throw new InvalidOperationException(
                              "No target folder was provided for package resolution, and the resulting package is not " +
                              "a global tool.");
                }
            }
            else
            {
                if (metadata.PackageType == PackageManager.PACKAGE_TYPE_TEMPLATE && templateName == null)
                {
                    throw new InvalidOperationException(
                              "Template referenced as part of module packages.  Templates can only be used " +
                              "with the --start option.");
                }
                else if (metadata.PackageType == PackageManager.PACKAGE_TYPE_LIBRARY)
                {
                    Directory.CreateDirectory(Path.Combine(workingDirectory, reference.Folder));

                    if (new DirectoryInfo(Path.Combine(workingDirectory, reference.Folder)).GetFiles().Length > 0 || new DirectoryInfo(Path.Combine(workingDirectory, reference.Folder)).GetDirectories().Length > 0)
                    {
                        if (!File.Exists(Path.Combine(workingDirectory, reference.Folder, ".git")) && !Directory.Exists(Path.Combine(workingDirectory, reference.Folder, ".git")) &&
                            !File.Exists(Path.Combine(workingDirectory, reference.Folder, ".pkg")))
                        {
                            bool shouldSafeResolve;
                            if (safeResolve.HasValue)
                            {
                                // If the user specifies it on the command line, use that setting.
                                shouldSafeResolve = safeResolve.Value;
                            }
                            else
                            {
                                if (!_featureManager.IsFeatureEnabled(Feature.SafeResolutionDisabled))
                                {
                                    // If the module doesn't have this feature set enabled, we default
                                    // to using safe package resolution.
                                    shouldSafeResolve = true;
                                }
                                else
                                {
                                    // If the module does have this feature set enabled, or is using the
                                    // full feature set, we default to turning safe resolution off.
                                    shouldSafeResolve = false;
                                }
                            }

                            if (shouldSafeResolve)
                            {
                                RedirectableConsole.ErrorWriteLine(
                                    "WARNING: The package directory '" + reference.Folder +
                                    "' already exists and contains " +
                                    "files and/or subdirectories, but neither a .pkg file nor a .git file or subdirectory exists.  " +
                                    "This indicates the package directory contains data that is not been instantiated or managed " +
                                    "by Protobuild.  Since there is no safe way to initialize the package in this directory " +
                                    "without a potential loss of data, Protobuild will not modify the contents of this folder " +
                                    "during package resolution.  If the folder does not contains the required package " +
                                    "dependencies, the project generation or build may unexpectedly fail.");
                                return;
                            }
                        }
                    }

                    if (source == null)
                    {
                        if (File.Exists(Path.Combine(workingDirectory, reference.Folder, ".git")) || Directory.Exists(Path.Combine(workingDirectory, reference.Folder, ".git")))
                        {
                            RedirectableConsole.WriteLine("Git repository present at " + Path.Combine(workingDirectory, reference.Folder, ".git") + "; leaving as source version.");
                            source = true;
                        }
                        else
                        {
                            RedirectableConsole.WriteLine("Package type not specified (and no file at " + Path.Combine(workingDirectory, reference.Folder, ".git") + "), requesting binary version.");
                            source = false;
                        }
                    }
                }
            }

            metadata.Resolve(workingDirectory, metadata, reference.Folder, templateName, forceUpgrade, source);
        }
        private Stream LoadOverriddableResource(string workingDirectory, ResourceType resourceType, Language language, string platform, out string loadHash)
        {
            loadHash = string.Empty;
            string name         = null;
            var    extension    = GetResourceExtension(resourceType);
            var    fileSuffix   = string.Empty;
            var    replacements = new Dictionary <string, ReplacementInfo>();
            bool   okayToFail   = false;

            switch (resourceType)
            {
            case ResourceType.GenerateProject:
                name       = "GenerateProject";
                fileSuffix = "." + this.m_LanguageStringProvider.GetFileSuffix(language);
                replacements.Add("ADDITIONAL_TRANSFORMS", new ReplacementInfo
                {
                    ResourceName = ResourceType.AdditionalProjectTransforms
                });
                break;

            case ResourceType.GenerateSolution:
                name = "GenerateSolution";
                break;

            case ResourceType.SelectSolution:
                name = "SelectSolution";
                break;

            case ResourceType.GenerationFunctions:
                name = "GenerationFunctions";
                break;

            case ResourceType.NuGetPlatformMappings:
                name = "NuGetPlatformMappings";
                break;

            case ResourceType.AdditionalGenerationFunctions:
                name       = "AdditionalGenerationFunctions";
                okayToFail = true;
                break;

            case ResourceType.AdditionalProjectTransforms:
                name       = "AdditionalProjectTransforms";
                okayToFail = true;
                break;

            default:
                throw new NotSupportedException();
            }

            switch (resourceType)
            {
            case ResourceType.GenerateProject:
            case ResourceType.GenerateSolution:
            case ResourceType.SelectSolution:
                replacements.Add("GENERATION_FUNCTIONS", new ReplacementInfo
                {
                    ResourceName         = ResourceType.GenerationFunctions,
                    ReplacementProcessor = x => _generationFunctionsProvider.ConvertGenerationFunctionsToXSLT("user", x)
                });
                replacements.Add("ADDITIONAL_GENERATION_FUNCTIONS", new ReplacementInfo
                {
                    ResourceName         = ResourceType.AdditionalGenerationFunctions,
                    ReplacementProcessor = x => _generationFunctionsProvider.ConvertGenerationFunctionsToXSLT("extra", x)
                });
                break;
            }

            var onDiskNames = new List <string>();

            onDiskNames.Add(name + fileSuffix + "." + platform + "." + extension);
            onDiskNames.Add(name + fileSuffix + "." + extension);

            if (resourceType == ResourceType.GenerateProject && language == Language.CSharp)
            {
                onDiskNames.Add(name + "." + extension);
            }

            Stream source = null;

            var globalPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), ".protobuild-xslt");

            if (Directory.Exists(globalPath))
            {
                foreach (var filename in onDiskNames)
                {
                    var path = Path.Combine(globalPath, filename);

                    if (File.Exists(path))
                    {
                        loadHash = "path:" + path;
                        RedirectableConsole.WriteLine("Loaded XSLT from global path: " + path);
                        source = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read);
                        break;
                    }
                }
            }

            if (source == null)
            {
                foreach (var filename in onDiskNames)
                {
                    var path = Path.Combine(workingDirectory, "Build", filename);

                    if (File.Exists(path))
                    {
                        loadHash = "path:" + path;
                        RedirectableConsole.WriteLine("Loaded XSLT from Build folder: " + path);
                        source = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read);
                        break;
                    }
                }
            }

            if (source == null)
            {
                var embeddedName   = name + fileSuffix + "." + extension + ".lzma";
                var embeddedStream = Assembly
                                     .GetExecutingAssembly()
                                     .GetManifestResourceStream(embeddedName);
                if (embeddedStream == null)
                {
                    if (okayToFail)
                    {
                        loadHash = "none";
                        return(new MemoryStream());
                    }
                    else
                    {
                        throw new InvalidOperationException("No embedded stream with name '" + embeddedName + "'");
                    }
                }
                loadHash = "embedded:" + embeddedName;
                RedirectableConsole.WriteLine("Loaded XSLT from Protobuild");
                source = this.GetTransparentDecompressionStream(embeddedStream);
            }

            foreach (var replacement in replacements)
            {
                var memory = new MemoryStream();
                using (var stream = source)
                {
                    using (var writer = new StringWriter())
                    {
                        string outHashTemp;
                        var    replacementDataStream = this.LoadOverriddableResource(
                            workingDirectory,
                            replacement.Value.ResourceName,
                            language,
                            platform,
                            out outHashTemp);
                        loadHash += ":" + outHashTemp;
                        string replacementData;
                        using (var reader = new StreamReader(replacementDataStream))
                        {
                            replacementData = reader.ReadToEnd();
                        }

                        if (replacement.Value.ReplacementProcessor != null)
                        {
                            replacementData = replacement.Value.ReplacementProcessor(replacementData);
                        }

                        using (var reader = new StreamReader(stream))
                        {
                            var text = reader.ReadToEnd();
                            text = text.Replace("<!-- {" + replacement.Key + "} -->", replacementData);
                            writer.Write(text);
                            writer.Flush();
                        }

                        var resultBytes = Encoding.UTF8.GetBytes(writer.GetStringBuilder().ToString());
                        memory.Write(resultBytes, 0, resultBytes.Length);
                        memory.Seek(0, SeekOrigin.Begin);
                    }
                }

                source = memory;
            }

            return(source);
        }
        public void Create(Stream target, FileFilter filter, string basePath, string packageFormat, string platform, string excludedPath)
        {
            Stream archive = new MemoryStream();
            string cleanUp = null;

            try
            {
                switch (packageFormat)
                {
                case PackageManager.ARCHIVE_FORMAT_TAR_GZIP:
                    RedirectableConsole.WriteLine("Writing package in tar/gzip format...");
                    break;

                case PackageManager.ARCHIVE_FORMAT_NUGET_ZIP:
                    RedirectableConsole.WriteLine("Writing package in NuGet ZIP format... (this is experimental!)");
                    break;

                case PackageManager.ARCHIVE_FORMAT_TAR_LZMA:
                default:
                    RedirectableConsole.WriteLine("Writing package in tar/lzma format...");
                    break;
                }

                switch (packageFormat)
                {
                case PackageManager.ARCHIVE_FORMAT_NUGET_ZIP:
                {
                    if (platform == "Unified")
                    {
                        // With unified packages, the contents have already been deduplicated in the
                        // individual packages we're combining.  Therefore we don't deduplicate again
                        // because we already have the deduplication index calculated as part of the
                        // package contents.  Just add all the files to the ZIP instead.
                        Action <ZipStorer> addFilesToZip = zip =>
                        {
                            RedirectableConsole.WriteLine("Adding files to package...");

                            var progressHelper = new AddFilesProgressRenderer(filter.CountTargetPaths());
                            var current        = 0;

                            var uniqueFiles = new HashSet <string>();

                            var entries = filter.GetExpandedEntries();

                            foreach (var kv in entries.OrderBy(kv => kv.Value))
                            {
                                if (kv.Value.EndsWith("/"))
                                {
                                    // Directory - do nothing
                                }
                                else
                                {
                                    var realFile = Path.Combine(basePath, kv.Key);

                                    if (uniqueFiles.Contains(kv.Value))
                                    {
                                        // Already exists - do nothing
                                    }
                                    else
                                    {
                                        if (excludedPath != null)
                                        {
                                            var realFileInfo = new FileInfo(realFile);

                                            var excludedPathInfo = new FileInfo(excludedPath);
                                            if (excludedPathInfo.FullName == realFileInfo.FullName)
                                            {
                                                // Skip this file because we force it to be excluded.
                                                continue;
                                            }
                                        }

                                        zip.AddFile(
                                            ZipStorer.Compression.Deflate,
                                            realFile,
                                            kv.Value,
                                            string.Empty);
                                        uniqueFiles.Add(kv.Value);
                                    }
                                }

                                current++;

                                progressHelper.SetProgress(current);
                            }

                            progressHelper.FinalizeRendering();
                        };

                        try
                        {
                            using (var zip = ZipStorer.Create(target, string.Empty, true))
                            {
                                addFilesToZip(zip);
                            }
                        }
                        catch (OutOfMemoryException)
                        {
                            // It's possible the archive is too large to store in memory.  Fall
                            // back to using a temporary file on disk.
                            cleanUp = Path.GetTempFileName();
                            RedirectableConsole.WriteLine(
                                "WARNING: Out-of-memory while creating ZIP file, falling back to storing " +
                                "temporary file on disk at " + cleanUp + " during package creation.");
                            archive.Dispose();
                            archive = new FileStream(cleanUp, FileMode.Create, FileAccess.ReadWrite);

                            using (var zip = ZipStorer.Create(archive, string.Empty, true))
                            {
                                addFilesToZip(zip);
                            }
                        }
                    }
                    else
                    {
                        // Deduplicate the contents of the ZIP package.
                        var state = _deduplicator.CreateState();

                        RedirectableConsole.Write("Deduplicating files in package...");

                        var progressHelper = new DedupProgressRenderer(filter.CountTargetPaths());
                        var current        = 0;

                        var entries = filter.GetExpandedEntries();

                        foreach (var kv in entries.OrderBy(kv => kv.Value))
                        {
                            if (kv.Value.EndsWith("/"))
                            {
                                // Directory
                                _deduplicator.AddDirectory(state, kv.Value);
                            }
                            else
                            {
                                // File
                                var realFile     = Path.Combine(basePath, kv.Key);
                                var realFileInfo = new FileInfo(realFile);

                                if (excludedPath != null)
                                {
                                    var excludedPathInfo = new FileInfo(excludedPath);
                                    if (excludedPathInfo.FullName == realFileInfo.FullName)
                                    {
                                        // Skip this file because we force it to be excluded.
                                        continue;
                                    }
                                }

                                _deduplicator.AddFile(state, realFileInfo, kv.Value);
                            }

                            current++;

                            progressHelper.SetProgress(current);
                        }

                        progressHelper.FinalizeRendering();
                        RedirectableConsole.WriteLine("Adding files to package...");

                        try
                        {
                            using (var zip = ZipStorer.Create(target, string.Empty, true))
                            {
                                _deduplicator.PushToZip(state, zip);
                            }
                        }
                        catch (OutOfMemoryException)
                        {
                            // It's possible the archive is too large to store in memory.  Fall
                            // back to using a temporary file on disk.
                            cleanUp = Path.GetTempFileName();
                            RedirectableConsole.WriteLine(
                                "WARNING: Out-of-memory while creating ZIP file, falling back to storing " +
                                "temporary file on disk at " + cleanUp + " during package creation.");
                            archive.Dispose();
                            archive = new FileStream(cleanUp, FileMode.Create, FileAccess.ReadWrite);

                            using (var zip = ZipStorer.Create(archive, string.Empty, true))
                            {
                                _deduplicator.PushToZip(state, zip);
                            }
                        }
                    }

                    break;
                }

                case PackageManager.ARCHIVE_FORMAT_TAR_GZIP:
                case PackageManager.ARCHIVE_FORMAT_TAR_LZMA:
                default:
                {
                    var state = _deduplicator.CreateState();

                    RedirectableConsole.Write("Deduplicating files in package...");

                    var progressHelper = new DedupProgressRenderer(filter.CountTargetPaths());
                    var current        = 0;

                    var entries = filter.GetExpandedEntries();

                    foreach (var kv in entries.OrderBy(kv => kv.Value))
                    {
                        if (kv.Value.EndsWith("/"))
                        {
                            // Directory
                            _deduplicator.AddDirectory(state, kv.Value);
                        }
                        else
                        {
                            // File
                            var realFile     = Path.Combine(basePath, kv.Key);
                            var realFileInfo = new FileInfo(realFile);

                            if (excludedPath != null)
                            {
                                var excludedPathInfo = new FileInfo(excludedPath);
                                if (excludedPathInfo.FullName == realFileInfo.FullName)
                                {
                                    // Skip this file because we force it to be excluded.
                                    continue;
                                }
                            }

                            _deduplicator.AddFile(state, realFileInfo, kv.Value);
                        }

                        current++;

                        progressHelper.SetProgress(current);
                    }

                    progressHelper.FinalizeRendering();
                    RedirectableConsole.WriteLine("Adding files to package...");

                    try
                    {
                        using (var writer = new tar_cs.TarWriter(archive))
                        {
                            _deduplicator.PushToTar(state, writer);
                        }
                    }
                    catch (OutOfMemoryException)
                    {
                        // It's possible the archive is too large to store in memory.  Fall
                        // back to using a temporary file on disk.
                        cleanUp = Path.GetTempFileName();
                        RedirectableConsole.WriteLine(
                            "WARNING: Out-of-memory while creating TAR file, falling back to storing " +
                            "temporary file on disk at " + cleanUp + " during package creation.");
                        archive.Dispose();
                        archive = new FileStream(cleanUp, FileMode.Create, FileAccess.ReadWrite);

                        using (var writer = new tar_cs.TarWriter(archive))
                        {
                            _deduplicator.PushToTar(state, writer);
                        }
                    }

                    break;
                }
                }

                archive.Seek(0, SeekOrigin.Begin);

                switch (packageFormat)
                {
                case PackageManager.ARCHIVE_FORMAT_NUGET_ZIP:
                    // No need to compress anything further.
                    break;

                case PackageManager.ARCHIVE_FORMAT_TAR_GZIP:
                {
                    RedirectableConsole.WriteLine("Compressing package...");

                    using (var compress = new GZipStream(target, CompressionMode.Compress))
                    {
                        archive.CopyTo(compress);
                    }

                    break;
                }

                case PackageManager.ARCHIVE_FORMAT_TAR_LZMA:
                default:
                {
                    RedirectableConsole.Write("Compressing package...");

                    var progressHelper = new CompressProgressRenderer(archive.Length);

                    LZMA.LzmaHelper.Compress(archive, target, progressHelper);

                    progressHelper.FinalizeRendering();

                    break;
                }
                }
            }
            finally
            {
                if (cleanUp != null)
                {
                    try
                    {
                        File.Delete(cleanUp);
                    }
                    catch
                    {
                        RedirectableConsole.WriteLine("WARNING: Unable to clean up temporary package file at " + cleanUp);
                    }
                }
            }
        }
        private int PushToNuGetRepository(Execution execution, bool pushGitVersion, string platform, string commitHash)
        {
            if (pushGitVersion)
            {
                // We have to patch the package file in memory to include the Git hash
                // as part of the version.  This is required so that Protobuild
                // can resolve source-equivalent binary packages.
                RedirectableConsole.WriteLine("Patching package file to include Git version information...");

                using (var patchedPackage = new MemoryStream())
                {
                    using (var patchedPackageWriter = ZipStorer.Create(patchedPackage, string.Empty, true))
                    {
                        using (var packageReader = ZipStorer.Open(execution.PackagePushFile, FileAccess.Read))
                        {
                            var entries = packageReader.ReadCentralDir();

                            var progressRenderer = new PackagePatchProgressRenderer(entries.Count);
                            var i = 0;

                            foreach (var entry in packageReader.ReadCentralDir())
                            {
                                if (entry.FilenameInZip.EndsWith(".nuspec") && !entry.FilenameInZip.Contains("/"))
                                {
                                    // This is the NuGet specification file in the root of the package
                                    // that we need to patch.
                                    using (var fileStream = new MemoryStream())
                                    {
                                        packageReader.ExtractFile(entry, fileStream);
                                        fileStream.Seek(0, SeekOrigin.Begin);
                                        string nuspecContent;
                                        using (
                                            var reader = new StreamReader(fileStream, Encoding.UTF8, true, 4096, true))
                                        {
                                            nuspecContent = reader.ReadToEnd();

                                            var regex =
                                                new Regex("version\\>[^\\<]+\\<\\/version");

                                            nuspecContent = regex.Replace(nuspecContent,
                                                                          "version>" + NuGetVersionHelper.CreateNuGetPackageVersion(commitHash, platform) + "</version");

                                            using (var patchedFileStream = new MemoryStream())
                                            {
                                                using (
                                                    var writer = new StreamWriter(patchedFileStream, Encoding.UTF8, 4096,
                                                                                  true))
                                                {
                                                    writer.Write(nuspecContent);
                                                    writer.Flush();
                                                    patchedFileStream.Seek(0, SeekOrigin.Begin);
                                                    patchedPackageWriter.AddStream(
                                                        entry.Method,
                                                        entry.FilenameInZip,
                                                        patchedFileStream,
                                                        entry.ModifyTime,
                                                        entry.Comment,
                                                        true);
                                                }
                                            }
                                        }
                                    }
                                }
                                else
                                {
                                    using (var fileStream = new MemoryStream())
                                    {
                                        packageReader.ExtractFile(entry, fileStream);
                                        fileStream.Seek(0, SeekOrigin.Begin);
                                        patchedPackageWriter.AddStream(
                                            entry.Method,
                                            entry.FilenameInZip,
                                            fileStream,
                                            entry.ModifyTime,
                                            entry.Comment,
                                            true);
                                    }
                                }

                                i++;
                                progressRenderer.SetProgress(i);
                            }

                            progressRenderer.FinalizeRendering();
                        }
                    }

                    patchedPackage.Seek(0, SeekOrigin.Begin);

                    // Push the patched package to the NuGet repository.
                    RedirectableConsole.WriteLine("Uploading package with Git version...");
                    return(this.PushNuGetBinary(execution.PackagePushUrl, execution.PackagePushApiKey,
                                                patchedPackage, execution.PackagePushIgnoreOnExisting));
                }
            }
            else
            {
                RedirectableConsole.WriteLine("Uploading package with semantic version...");
                using (
                    var stream = new FileStream(execution.PackagePushFile, FileMode.Open, FileAccess.Read,
                                                FileShare.Read))
                {
                    using (var memoryStream = new MemoryStream())
                    {
                        stream.CopyTo(memoryStream);
                        memoryStream.Seek(0, SeekOrigin.Begin);

                        // Note about the true argument here: We always ignore a conflict for the semantic version, as
                        // the build server may be pushing on every commit.  In this scenario, developers will leave
                        // the semantic version as-is until they're ready to release a new semantic version.
                        return(this.PushNuGetBinary(execution.PackagePushUrl, execution.PackagePushApiKey,
                                                    memoryStream, true));
                    }
                }
            }
        }
        private int PushToProtobuildRepository(Execution execution, string archiveType)
        {
            using (var client = new RetryableWebClient())
            {
                RedirectableConsole.WriteLine("Creating new package version...");

                if (execution.PackagePushVersion.StartsWith("hash:", StringComparison.InvariantCulture))
                {
                    var sha1   = new SHA1Managed();
                    var hashed = sha1.ComputeHash(Encoding.ASCII.GetBytes(execution.PackagePushVersion.Substring("hash:".Length)));
                    execution.PackagePushVersion = BitConverter.ToString(hashed).ToLowerInvariant().Replace("-", "");
                }

                var uploadParameters = new System.Collections.Specialized.NameValueCollection
                {
                    { "__apikey__", execution.PackagePushApiKey },
                    { "version", execution.PackagePushVersion },
                    { "platform", execution.PackagePushPlatform },
                };

                byte[] versionData;
                try
                {
                    versionData = client.UploadValues(execution.PackagePushUrl + "/version/new/api", uploadParameters);
                }
                catch (WebException ex)
                {
                    var responseData = string.Empty;

                    // Try and get the full response from the server to display in the exception message.
                    try
                    {
                        var stream = ex.Response.GetResponseStream();
                        if (stream != null)
                        {
                            using (var reader = new StreamReader(stream, Encoding.Default, true, 4096, true))
                            {
                                responseData = reader.ReadToEnd();
                            }
                        }
                    }
                    catch (Exception)
                    {
                    }

                    throw new WebException(ex.Message + "  Content of response was: " + responseData);
                }

                var json = fastJSON.JSON.ToDynamic(
                    System.Text.Encoding.ASCII.GetString(
                        versionData));

                if (json.has_error)
                {
                    RedirectableConsole.WriteLine(json.error);

                    if (execution.PackagePushIgnoreOnExisting &&
                        ((string)json.error.ToString()).Contains("Another version already exists with this Git hash and platform"))
                    {
                        return(0);
                    }

                    return(1);
                }

                var uploadTarget   = (string)json.result.uploadUrl;
                var finalizeTarget = (string)json.result.finalizeUrl;

                RedirectableConsole.WriteLine("Uploading package...");
                this.PushBinary(uploadTarget, execution.PackagePushFile);

                RedirectableConsole.WriteLine("Finalizing package version...");

                var finalizeParameters = new System.Collections.Specialized.NameValueCollection
                {
                    { "__apikey__", execution.PackagePushApiKey },
                    { "archiveType", archiveType },
                };

                json = fastJSON.JSON.ToDynamic(
                    System.Text.Encoding.ASCII.GetString(
                        client.UploadValues(finalizeTarget, finalizeParameters)));

                if (json.has_error)
                {
                    RedirectableConsole.WriteLine(json.error);
                    return(1);
                }

                if (execution.PackagePushBranchToUpdate != null)
                {
                    RedirectableConsole.WriteLine("Updating branch " + execution.PackagePushBranchToUpdate + " to point at new version...");

                    var branchUpdateParameters = new System.Collections.Specialized.NameValueCollection
                    {
                        { "__apikey__", execution.PackagePushApiKey },
                        { "name", execution.PackagePushBranchToUpdate },
                        { "git", execution.PackagePushVersion },
                    };

                    json = fastJSON.JSON.ToDynamic(
                        System.Text.Encoding.ASCII.GetString(
                            client.UploadValues(
                                execution.PackagePushUrl + "/branch/edit/" + execution.PackagePushBranchToUpdate + "/api",
                                branchUpdateParameters)));

                    if (json.has_error)
                    {
                        RedirectableConsole.WriteLine(json.error);
                        return(1);
                    }
                }

                RedirectableConsole.WriteLine("Package version pushed successfully.");
            }
            return(0);
        }
        public void ScanPackageForToolsAndInstall(string toolFolder, IKnownToolProvider knownToolProvider)
        {
            var projectsPath = Path.Combine(toolFolder, "Build", "Projects");
            var projectsInfo = new DirectoryInfo(projectsPath);

            foreach (var file in projectsInfo.GetFiles("*.definition"))
            {
                var document = XDocument.Load(file.FullName);
                var tools    = document.XPathSelectElements("/ExternalProject/Tool");

                foreach (var tool in tools)
                {
                    var toolPath = Path.Combine(toolFolder, tool.Attribute(XName.Get("Path")).Value);
                    var toolName = tool.Attribute(XName.Get("Name")).Value;

                    if (Path.DirectorySeparatorChar == '\\')
                    {
                        toolPath = toolPath.Replace("/", "\\");
                    }
                    else if (Path.DirectorySeparatorChar == '/')
                    {
                        toolPath = toolPath.Replace("\\", "/");
                    }

                    using (var writer = new StreamWriter(Path.Combine(this.GetToolsPath(), toolName + ".tool")))
                    {
                        writer.WriteLine(toolPath);
                    }

                    RedirectableConsole.WriteLine("Global tool '" + toolName + "' now points to '" + toolPath + "'");

                    if (_hostPlatformDetector.DetectPlatform() == "Windows")
                    {
                        this.InstallToolIntoWindowsStartMenu(toolName, toolPath);
                    }
                    else if (_hostPlatformDetector.DetectPlatform() == "MacOS")
                    {
                        this.InstallToolIntoUserApplicationFolder(toolName, toolPath);
                    }
                    else if (_hostPlatformDetector.DetectPlatform() == "Linux")
                    {
                        this.InstallToolIntoLinuxApplicationMenu(toolName, toolPath);
                    }
                }

                var vsixes = document.XPathSelectElements("/ExternalProject/VSIX");

                foreach (var vsix in vsixes)
                {
                    var vsixPath = Path.Combine(toolFolder, vsix.Attribute(XName.Get("Path")).Value);

                    if (Path.DirectorySeparatorChar == '\\')
                    {
                        vsixPath = vsixPath.Replace("/", "\\");
                    }
                    else if (Path.DirectorySeparatorChar == '/')
                    {
                        vsixPath = vsixPath.Replace("\\", "/");
                    }

                    if (_hostPlatformDetector.DetectPlatform() == "Windows")
                    {
                        this.InstallVSIXIntoVisualStudio(vsixPath, knownToolProvider);
                    }
                }

                var gacs = document.XPathSelectElements("/ExternalProject/GAC");

                foreach (var gac in gacs)
                {
                    var assemblyPath = Path.Combine(toolFolder, gac.Attribute(XName.Get("Path")).Value);

                    if (Path.DirectorySeparatorChar == '\\')
                    {
                        assemblyPath = assemblyPath.Replace("/", "\\");
                    }
                    else if (Path.DirectorySeparatorChar == '/')
                    {
                        assemblyPath = assemblyPath.Replace("\\", "/");
                    }

                    if (_hostPlatformDetector.DetectPlatform() == "Windows")
                    {
                        this.InstallAssemblyIntoGAC(assemblyPath);
                    }
                }
            }
        }
Example #11
0
        /// <summary>
        /// Performs a resynchronisation, synchronisation, generation or clean on the specified module.
        /// </summary>
        /// <returns><c>true</c>, if the action succeeded, <c>false</c> otherwise.</returns>
        /// <param name="module">The module to perform the action on.</param>
        /// <param name="action">The action to perform, either "resync", "sync", "generate" or "clean".</param>
        /// <param name="platform">The platform to perform the action for.</param>
        /// <param name="enabledServices">A list of enabled services.</param>
        /// <param name="disabledServices">A list of disabled services.</param>
        /// <param name="serviceSpecPath">The service specification path.</param>
        /// <param name="debugServiceResolution">Whether to enable debugging information during service resolution.</param>
        /// <param name="disablePackageResolution">Whether to disable package resolution.</param>
        /// <param name="disableHostPlatformGeneration">Whether to disable generation of the host platform projects.</param>
        /// <param name="taskParallelisation">Whether to enable or disable task generation, or null for the default behaviour.</param>
        public bool PerformAction(
            string workingDirectory,
            ModuleInfo module,
            string action,
            string platform,
            string[] enabledServices,
            string[] disabledServices,
            string serviceSpecPath,
            bool debugServiceResolution,
            bool disablePackageResolution,
            bool disableHostPlatformGeneration,
            bool?taskParallelisation,
            bool?safeResolve,
            bool debugProjectGeneration)
        {
            var platformSupplied = !string.IsNullOrWhiteSpace(platform);

            var hostPlatform = this.m_HostPlatformDetector.DetectPlatform();

            if (string.IsNullOrWhiteSpace(platform))
            {
                platform = hostPlatform;
            }

            var    originalPlatform  = platform;
            string primaryPlatform   = null;
            string multiplePlatforms = null;

            if (platform.Contains(","))
            {
                // The user requested multiple platforms; the first one
                // is the primary platform.
                var platforms = platform.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                if (platforms.Length == 0)
                {
                    RedirectableConsole.ErrorWriteLine("You supplied only commas where a list of platforms was expected.");
                    ExecEnvironment.Exit(1);
                    return(false);
                }
                else
                {
                    for (var i = 0; i < platforms.Length; i++)
                    {
                        var newPlatform = _moduleUtilities.NormalizePlatform(module, platforms[i]);
                        if (newPlatform == null)
                        {
                            ShowSupportedPlatformsError(module, platforms[i]);
                            return(false);
                        }
                        platforms[i] = newPlatform;
                    }

                    primaryPlatform   = platforms[0];
                    multiplePlatforms = platforms.Aggregate((a, b) => a + "," + b);
                }
            }
            else
            {
                platform = _moduleUtilities.NormalizePlatform(module, platform);

                if (platform == null && !platformSupplied)
                {
                    // The current host platform isn't supported, so we shouldn't try to
                    // operate on it.
                    string firstPlatform = null;
                    switch (this.m_HostPlatformDetector.DetectPlatform())
                    {
                    case "Windows":
                        firstPlatform = module.DefaultWindowsPlatforms.Split(',').FirstOrDefault();
                        break;

                    case "MacOS":
                        firstPlatform = module.DefaultMacOSPlatforms.Split(',').FirstOrDefault();
                        break;

                    case "Linux":
                        firstPlatform = module.DefaultLinuxPlatforms.Split(',').FirstOrDefault();
                        break;
                    }

                    if (firstPlatform != null)
                    {
                        // This will end up null if the first platform isn't supported
                        // either and hence throw the right message.
                        platform = _moduleUtilities.NormalizePlatform(module, firstPlatform);
                    }
                }

                if (platform == null)
                {
                    ShowSupportedPlatformsError(module, originalPlatform);
                    return(false);
                }

                primaryPlatform = platform;
            }

            // You can generate multiple targets by default by setting the <DefaultWindowsPlatforms>
            // <DefaultMacOSPlatforms> and <DefaultLinuxPlatforms> tags in Module.xml.  Note that
            // synchronisation will only be done for the primary platform, as there is no correct
            // synchronisation behaviour when dealing with multiple C# projects.
            //
            // We only trigger this behaviour when the platform is omitted; if you explicitly
            // specify "Windows" on the command line, we'll only generate / resync / sync
            // the Windows platform.
            if (!platformSupplied)
            {
                switch (platform)
                {
                case "Windows":
                    multiplePlatforms = module.DefaultWindowsPlatforms;
                    break;

                case "MacOS":
                    multiplePlatforms = module.DefaultMacOSPlatforms;
                    break;

                case "Linux":
                    multiplePlatforms = module.DefaultLinuxPlatforms;
                    break;
                }
            }

            // If no overrides are set, just use the current platform.
            if (string.IsNullOrEmpty(multiplePlatforms))
            {
                multiplePlatforms = platform;
            }

            // If running pure synchronisation or a project clean, we don't need to perform
            // package resolution.
            if (action.ToLower() == "sync" || action.ToLower() == "clean")
            {
                disablePackageResolution = true;
            }

            // Resolve submodules as needed.
            if (!disablePackageResolution)
            {
                this.m_PackageManager.ResolveAll(workingDirectory, module, primaryPlatform, taskParallelisation, false, safeResolve, null);
            }

            // Create the list of multiple platforms.
            var multiplePlatformsList =
                multiplePlatforms.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).ToList();

            // Remember whether or not we need to implicitly generate the host
            // platform.
            var    implicitlyGenerateHostPlatform = false;
            Action requiresHostPlatform           = () => implicitlyGenerateHostPlatform = true;

            // If we are already generating the host platform, then requiring the
            // host platform is already satisifed.
            if (platform == hostPlatform || multiplePlatformsList.Contains(hostPlatform))
            {
                requiresHostPlatform = () => {};
            }
            else if (!_featureManager.IsFeatureEnabled(Feature.HostPlatformGeneration))
            {
                requiresHostPlatform = () =>
                {
                    RedirectableConsole.ErrorWriteLine(
                        "WARNING: One or more projects requires host platforms to be generated, " +
                        "but the HostPlatformGeneration feature is not enabled.  Expect your " +
                        "build to fail.");
                };
            }

            // You can configure the default action for Protobuild in their project
            // with the <DefaultAction> tag in Module.xml.  If omitted, default to a resync.
            // Valid options for this tag are either "Generate", "Resync" or "Sync".

            // If the actions are "Resync" or "Sync", then we need to perform an initial
            // step against the primary platform.
            switch (action.ToLower())
            {
            case "generate":
                if (!this.GenerateProjectsForPlatform(
                        workingDirectory,
                        module,
                        primaryPlatform,
                        enabledServices,
                        disabledServices,
                        serviceSpecPath,
                        debugServiceResolution,
                        disablePackageResolution,
                        disableHostPlatformGeneration,
                        requiresHostPlatform,
                        debugProjectGeneration))
                {
                    return(false);
                }

                break;

            case "resync":
                if (!this.ResyncProjectsForPlatform(
                        workingDirectory,
                        module,
                        primaryPlatform,
                        enabledServices,
                        disabledServices,
                        serviceSpecPath,
                        debugServiceResolution,
                        disablePackageResolution,
                        disableHostPlatformGeneration,
                        requiresHostPlatform,
                        debugProjectGeneration))
                {
                    return(false);
                }

                break;

            case "sync":
                return(this.SyncProjectsForPlatform(module, primaryPlatform));

            case "clean":
                if (!this.CleanProjectsForPlatform(module, primaryPlatform))
                {
                    return(false);
                }

                break;

            default:
                RedirectableConsole.ErrorWriteLine("Unknown option in <DefaultAction> tag of Module.xml.  Defaulting to resync!");
                return(this.ResyncProjectsForPlatform(
                           workingDirectory,
                           module,
                           primaryPlatform,
                           enabledServices,
                           disabledServices,
                           serviceSpecPath,
                           debugServiceResolution,
                           disablePackageResolution,
                           disableHostPlatformGeneration,
                           requiresHostPlatform,
                           debugProjectGeneration));
            }

            // Now iterate through the multiple platforms specified.
            foreach (var platformIter in multiplePlatformsList.Distinct())
            {
                if (platformIter == primaryPlatform)
                {
                    // Already handled above.
                    continue;
                }

                // Resolve submodules as needed.
                if (!disablePackageResolution)
                {
                    this.m_PackageManager.ResolveAll(workingDirectory, module, platformIter, taskParallelisation, false, safeResolve, null);
                }

                switch (action.ToLower())
                {
                case "generate":
                case "resync":
                    // We do a generate under resync mode since we only want the primary platform
                    // to have synchronisation done (and it has had above).
                    if (!this.GenerateProjectsForPlatform(
                            workingDirectory,
                            module,
                            platformIter,
                            enabledServices,
                            disabledServices,
                            serviceSpecPath,
                            debugServiceResolution,
                            disablePackageResolution,
                            disableHostPlatformGeneration,
                            requiresHostPlatform,
                            debugProjectGeneration))
                    {
                        return(false);
                    }

                    break;

                case "clean":
                    if (!this.CleanProjectsForPlatform(module, platformIter))
                    {
                        return(false);
                    }

                    break;

                default:
                    throw new InvalidOperationException("Code should never reach this point");
                }
            }

            // If we implicitly require the host platform, generate that now (this variable can
            // only ever be set to true if the host platform is not already in the list of
            // platforms generated previously).
            if (implicitlyGenerateHostPlatform)
            {
                // Check to see if the host platform is supported.
                var hostPlatformNormalized = _moduleUtilities.NormalizePlatform(module, hostPlatform);
                if (hostPlatformNormalized == null)
                {
                    RedirectableConsole.WriteLine(
                        "WARNING: The current host platform is not a supported platform for the solution.  IDE editor " +
                        "projects and post-build hooks will not be available, and this may cause the project to be " +
                        "built incorrectly!");
                    return(true);
                }

                RedirectableConsole.WriteLine(
                    "One or more projects required the presence of host platform " +
                    "projects, implicitly starting generation for " + hostPlatform + "...");

                // Resolve submodules as needed.
                if (!disablePackageResolution)
                {
                    this.m_PackageManager.ResolveAll(workingDirectory, module, hostPlatform, taskParallelisation, false, safeResolve, null);
                }

                switch (action.ToLower())
                {
                case "generate":
                case "resync":
                    // We do a generate under resync mode since we only want the primary platform
                    // to have synchronisation done (and it has had above).
                    if (!this.GenerateProjectsForPlatform(
                            workingDirectory,
                            module,
                            hostPlatform,
                            enabledServices,
                            disabledServices,
                            serviceSpecPath,
                            debugServiceResolution,
                            disablePackageResolution,
                            disableHostPlatformGeneration,
                            requiresHostPlatform,
                            debugProjectGeneration))
                    {
                        return(false);
                    }

                    break;

                case "clean":
                    if (!this.CleanProjectsForPlatform(module, hostPlatform))
                    {
                        return(false);
                    }

                    break;

                default:
                    throw new InvalidOperationException("Code should never reach this point");
                }
            }

            // All the steps succeeded, so return true.
            return(true);
        }
        private void InstallVSIXIntoVisualStudio(string vsixPath, IKnownToolProvider knownToolProvider)
        {
            // This installation technique is for pre-2017 editions of Visual Studio.
            // We don't list 10.0 and 11.0 because they don't support all editions (you should
            // use GAC based installation for these editions instead).
            var vsVersions = new[]
            {
                "12.0",
                "14.0"
            };

            var editionRegistryKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32)
                                     ?.OpenSubKey("SOFTWARE")
                                     ?.OpenSubKey("Microsoft")
                                     ?.OpenSubKey("VisualStudio");

            if (editionRegistryKey != null)
            {
                foreach (var version in vsVersions)
                {
                    var installPath = (string)editionRegistryKey?.OpenSubKey(version)?.GetValue("InstallDir");

                    if (installPath != null)
                    {
                        var vsixInstallerPath = Path.Combine(installPath, "VSIXInstaller.exe");

                        if (Directory.Exists(installPath))
                        {
                            if (File.Exists(vsixInstallerPath))
                            {
                                try
                                {
                                    RedirectableConsole.WriteLine("Installing VSIX into Visual Studio " + version + "...");
                                    var processStartInfo = new ProcessStartInfo();
                                    processStartInfo.FileName        = vsixInstallerPath;
                                    processStartInfo.Arguments       = "/q \"" + vsixPath + "\"";
                                    processStartInfo.UseShellExecute = false;
                                    var process = Process.Start(processStartInfo);
                                    process.WaitForExit();

                                    if (process.ExitCode != 0)
                                    {
                                        RedirectableConsole.ErrorWriteLine("VSIX installation failed for Visual Studio " + version + " (non-zero exit code)");
                                    }
                                    else
                                    {
                                        RedirectableConsole.WriteLine("VSIX installation completed successfully for Visual Studio " + version);
                                    }
                                }
                                catch (Exception ex)
                                {
                                    RedirectableConsole.ErrorWriteLine("Failed to install VSIX for Visual Studio " + version + ": " + ex.Message);
                                }
                            }
                            else
                            {
                                RedirectableConsole.WriteLine("Visual Studio " + version + " does not provide VSIXInstaller.exe (checked for existance of " + vsixInstallerPath + ").");
                            }
                        }
                        else
                        {
                            RedirectableConsole.WriteLine("Visual Studio " + version + " is not installed (checked for existance of " + installPath + ").");
                        }
                    }
                }
            }

            // Now try and install in all editions of Visual Studio 2017 and later.  This
            // may install the vswhere global tool.
            var           vswhere       = knownToolProvider.GetToolExecutablePath("vswhere");
            List <string> installations = null;

            RedirectableConsole.WriteLine("Locating installations of Visual Studio 2017 and later...");
            try
            {
                var processStartInfo = new ProcessStartInfo();
                processStartInfo.FileName               = vswhere;
                processStartInfo.Arguments              = "-products * -property installationPath";
                processStartInfo.UseShellExecute        = false;
                processStartInfo.RedirectStandardOutput = true;
                var process             = Process.Start(processStartInfo);
                var installationsString = process.StandardOutput.ReadToEnd();
                installations = installationsString.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries).Where(x => !string.IsNullOrWhiteSpace(x)).ToList();
                process.WaitForExit();

                if (process.ExitCode != 0)
                {
                    RedirectableConsole.ErrorWriteLine("Unable to locate Visual Studio 2017 and later installations (non-zero exit code from vswhere)");
                }
            }
            catch (Exception ex)
            {
                RedirectableConsole.ErrorWriteLine("Unable to locate Visual Studio 2017 and later installations: " + ex.Message);
            }

            if (installations != null)
            {
                foreach (var installPath in installations)
                {
                    var vsixInstallerPath = Path.Combine(installPath,
                                                         "Common7",
                                                         "IDE",
                                                         "VSIXInstaller.exe");

                    if (Directory.Exists(installPath))
                    {
                        if (File.Exists(vsixInstallerPath))
                        {
                            try
                            {
                                RedirectableConsole.WriteLine("Installing VSIX into " + installPath + "...");
                                var processStartInfo = new ProcessStartInfo();
                                processStartInfo.FileName        = vsixInstallerPath;
                                processStartInfo.Arguments       = "/q \"" + vsixPath + "\"";
                                processStartInfo.UseShellExecute = false;
                                var process = Process.Start(processStartInfo);
                                process.WaitForExit();

                                if (process.ExitCode != 0)
                                {
                                    RedirectableConsole.ErrorWriteLine("VSIX installation failed for " + installPath + " (non-zero exit code)");
                                }
                                else
                                {
                                    RedirectableConsole.WriteLine("VSIX installation completed successfully for " + installPath);
                                }
                            }
                            catch (Exception ex)
                            {
                                RedirectableConsole.ErrorWriteLine("Failed to install VSIX for " + installPath + ": " + ex.Message);
                            }
                        }
                        else
                        {
                            RedirectableConsole.WriteLine("Visual Studio at " + installPath + " does not provide VSIXInstaller.exe (checked for existance of " + vsixInstallerPath + ").");
                        }
                    }
                    else
                    {
                        RedirectableConsole.WriteLine("Visual Studio at " + installPath + " is not installed (checked for existance of " + installPath + ").");
                    }
                }
            }
        }
        private void InstallToolIntoUserApplicationFolder(string toolName, string toolPath)
        {
            var appToolPath = toolPath.Replace(".exe", ".app");

            if (!Directory.Exists(appToolPath))
            {
                return;
            }

            var basename        = Path.GetFileName(appToolPath);
            var applicationPath = Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
                "Applications");

            Directory.CreateDirectory(applicationPath);
            var installPath = Path.Combine(applicationPath, basename);

            try
            {
                var stat = System.Diagnostics.Process.Start(new ProcessStartInfo
                {
                    FileName               = "/usr/bin/stat",
                    Arguments              = "-f %T '" + installPath + "'",
                    UseShellExecute        = false,
                    CreateNoWindow         = true,
                    RedirectStandardOutput = true
                });
                var type = stat.StandardOutput.ReadToEnd().Trim();
                if (type == "@")
                {
                    // The file is a symbolic link.
                    File.Delete(installPath);
                }
                else
                {
                    if (Directory.Exists(installPath))
                    {
                        // Recursive delete.
                        PathUtils.AggressiveDirectoryDelete(installPath);
                    }
                    else
                    {
                        File.Delete(installPath);
                    }
                }
            }
            catch
            {
            }

            // Make sure we don't create a symbolic link inside a symbolically linked directory.
            if (!File.Exists(installPath) && !Directory.Exists(installPath))
            {
                var install = System.Diagnostics.Process.Start("ln", "-s '" + appToolPath + "' '" + installPath + "'");
                if (install != null)
                {
                    install.WaitForExit();

                    RedirectableConsole.WriteLine("Global tool '" + toolName + "' is now available in the application menu");
                }
                else
                {
                    RedirectableConsole.WriteLine("Unable to install global tool '" + toolName + "' into the application menu (unable to create link)");
                }
            }
        }
Example #14
0
        public void MergeInReferencesAndPropertiesForIncludeProjects(List <LoadedDefinitionInfo> documents, XmlDocument projectDoc, string targetPlatform)
        {
            // While the <Files> section is handled explicitly in the XSLT (so that
            // synchronisation behaves correctly), the <References> and <Properties>
            // sections are handled here, because supporting them via XSLT would
            // make the XSLT drastically more complex.

            var documentsByName = documents.ToDictionarySafe(
                k => k.Definition.Name,
                v => v,
                (dict, x) =>
            {
                var existing = dict[x.Definition.Name];
                var tried    = x;

                RedirectableConsole.WriteLine("WARNING: There is more than one project with the name " +
                                              x.Definition.Name + " (first project loaded from " + tried.Definition.AbsolutePath + ", " +
                                              "skipped loading second project from " + existing.Definition.AbsolutePath + ")");
            })
                                  .ToDictionary(k => k.Key, v => v.Value.Project);

            var currentProjectReferences = projectDoc.SelectNodes("/Project/References/Reference").OfType <XmlElement>()
                                           .Select(k => k.GetAttribute("Include")).ToList();

            var referencesToAdd = new List <XmlNode>();
            var propertiesToAdd = new List <XmlNode>();

            foreach (var reference in currentProjectReferences)
            {
                if (!documentsByName.ContainsKey(reference))
                {
                    continue;
                }

                var referencedDocument = documentsByName[reference];

                if (referencedDocument.DocumentElement.LocalName == "IncludeProject")
                {
                    // Find references and copy them in.
                    var includeProjectReferences = referencedDocument.SelectNodes("/IncludeProject/References/Reference").OfType <XmlElement>().ToList();
                    foreach (var @ref in includeProjectReferences)
                    {
                        referencesToAdd.Add(projectDoc.ImportNode(@ref, true));
                    }

                    // Find all nodes under the <Properties> section and deep-copy them in.
                    var includeProjectProperties = referencedDocument.SelectNodes("/IncludeProject/Properties/*").OfType <XmlElement>().ToList();
                    foreach (var node in includeProjectProperties)
                    {
                        propertiesToAdd.Add(projectDoc.ImportNode(node, true));
                    }
                }
            }

            var references = projectDoc.DocumentElement.SelectSingleNode("References");

            if (references == null)
            {
                references = projectDoc.CreateElement("References");
                projectDoc.DocumentElement.AppendChild(references);
            }

            foreach (var @ref in referencesToAdd)
            {
                references.AppendChild(@ref);
            }

            var properties = projectDoc.DocumentElement.SelectSingleNode("Properties");

            if (properties == null)
            {
                properties = projectDoc.CreateElement("Properties");
                projectDoc.DocumentElement.AppendChild(properties);
            }

            foreach (var node in propertiesToAdd)
            {
                properties.AppendChild(node);
            }
        }
        public XmlDocument Generate(
            List <XmlDocument> definitions,
            string workingDirectory,
            string rootPath,
            string projectName,
            string platformName,
            string packagesPath,
            IEnumerable <XmlElement> properties,
            List <Service> services)
        {
            var doc = new XmlDocument();

            doc.AppendChild(doc.CreateXmlDeclaration("1.0", "UTF-8", null));
            var input = doc.CreateElement("Input");

            doc.AppendChild(input);

            input.AppendChild(this.m_ServiceInputGenerator.Generate(doc, projectName, services));

            var generation      = doc.CreateElement("Generation");
            var projectNameNode = doc.CreateElement("ProjectName");

            projectNameNode.AppendChild(doc.CreateTextNode(projectName));
            var platformNameNode = doc.CreateElement("Platform");

            platformNameNode.AppendChild(doc.CreateTextNode(platformName));
            var hostPlatformName = doc.CreateElement("HostPlatform");

            hostPlatformName.AppendChild(doc.CreateTextNode(this.m_HostPlatformDetector.DetectPlatform()));
            var workingDirectoryNode = doc.CreateElement("WorkingDirectory");

            workingDirectoryNode.AppendChild(doc.CreateTextNode(workingDirectory));

            if (string.Compare(platformName, "Web", StringComparison.InvariantCultureIgnoreCase) == 0)
            {
                // Add JSIL properties
                string jsilDirectory, jsilCompilerFile;
                if (!this.m_JSILProvider.GetJSIL(out jsilDirectory, out jsilCompilerFile))
                {
                    throw new InvalidOperationException("JSIL not found, but previous check passed.");
                }

                var jsilDirectoryNode = doc.CreateElement("JSILDirectory");
                jsilDirectoryNode.AppendChild(doc.CreateTextNode(jsilDirectory));
                generation.AppendChild(jsilDirectoryNode);
                var jsilCompilerPathNode = doc.CreateElement("JSILCompilerFile");
                jsilCompilerPathNode.AppendChild(doc.CreateTextNode(jsilCompilerFile));
                generation.AppendChild(jsilCompilerPathNode);

                var jsilLibrariesNode = doc.CreateElement("JSILLibraries");

                foreach (var entry in this.m_JSILProvider.GetJSILLibraries())
                {
                    var entryNode     = doc.CreateElement("Library");
                    var pathAttribute = doc.CreateAttribute("Path");
                    pathAttribute.Value = entry.Key;
                    var nameAttribute = doc.CreateAttribute("Name");
                    nameAttribute.Value = entry.Value;
                    entryNode.Attributes.Append(pathAttribute);
                    entryNode.Attributes.Append(nameAttribute);
                    jsilLibrariesNode.AppendChild(entryNode);
                }

                generation.AppendChild(jsilLibrariesNode);

                // Automatically extract the JSIL template if not already present.
                var currentProject =
                    definitions.Select(x => x.DocumentElement)
                    .Where(x => x.Attributes != null)
                    .Where(x => x.Attributes["Name"] != null)
                    .FirstOrDefault(x => x.Attributes["Name"].Value == projectName);
                if (currentProject != null)
                {
                    string type = null;
                    string path = null;
                    if (currentProject.Attributes != null && currentProject.Attributes["Type"] != null)
                    {
                        type = currentProject.Attributes["Type"].Value;
                    }
                    if (currentProject.Attributes != null && currentProject.Attributes["Path"] != null)
                    {
                        path = currentProject.Attributes["Path"].Value;
                    }

                    if (string.Compare(type, "App", StringComparison.InvariantCultureIgnoreCase) == 0 ||
                        string.Compare(type, "Console", StringComparison.InvariantCultureIgnoreCase) == 0 ||
                        string.Compare(type, "GUI", StringComparison.InvariantCultureIgnoreCase) == 0 ||
                        string.Compare(type, "GTK", StringComparison.InvariantCultureIgnoreCase) == 0)
                    {
                        if (path != null)
                        {
                            var srcDir = Path.Combine(rootPath, path);
                            if (Directory.Exists(srcDir))
                            {
                                if (!File.Exists(Path.Combine(srcDir, "index.htm")))
                                {
                                    RedirectableConsole.WriteLine("Extracting JSIL HTML template...");
                                    ResourceExtractor.ExtractJSILTemplate(projectName, Path.Combine(srcDir, "index.htm"));
                                }
                            }
                        }
                    }
                }
            }

            var rootName = doc.CreateElement("RootPath");

            rootName.AppendChild(doc.CreateTextNode(
                                     new DirectoryInfo(rootPath).FullName));
            generation.AppendChild(projectNameNode);
            generation.AppendChild(platformNameNode);
            generation.AppendChild(hostPlatformName);
            generation.AppendChild(workingDirectoryNode);
            generation.AppendChild(rootName);
            input.AppendChild(generation);

            var propertiesNode = doc.CreateElement("Properties");

            foreach (var property in properties)
            {
                if (property.Name.ToLower() == "property")
                {
                    var nodeName = doc.CreateElement(property.GetAttribute("Name"));
                    nodeName.AppendChild(doc.CreateTextNode(
                                             property.GetAttribute("Value")));
                    propertiesNode.AppendChild(nodeName);
                }
                else
                {
                    propertiesNode.AppendChild(
                        doc.ImportNode(property, true));
                }
            }
            input.AppendChild(propertiesNode);

            var featuresNode = doc.CreateElement("Features");

            foreach (var feature in _featureManager.GetAllEnabledFeatures())
            {
                var featureNode = doc.CreateElement(feature.ToString());
                featureNode.AppendChild(doc.CreateTextNode("True"));
                featuresNode.AppendChild(featureNode);
            }
            input.AppendChild(featuresNode);

            var nuget = doc.CreateElement("NuGet");

            input.AppendChild(nuget);

            var projects = doc.CreateElement("Projects");

            input.AppendChild(projects);
            foreach (var projectDoc in definitions)
            {
                var importedProject = this.m_ServiceReferenceTranslator.TranslateProjectWithServiceReferences(
                    doc.ImportNode(projectDoc.DocumentElement, true),
                    services);

                // Convert <Property> tags in projects other than the one we're currently
                // generating, so that we can lookup properties in other projects in the XSLT.
                var importedProjectProperties = importedProject.ChildNodes
                                                .OfType <XmlElement>()
                                                .FirstOrDefault(x => x.Name.ToLower() == "properties");
                if (importedProjectProperties != null)
                {
                    var existingProperties = importedProjectProperties.ChildNodes
                                             .OfType <XmlElement>().ToList();
                    foreach (var property in existingProperties)
                    {
                        if (property.Name.ToLower() == "property")
                        {
                            if (property.GetAttribute("Name") == null)
                            {
                                throw new Exception(
                                          "A property is missing the Name attribute in the '" +
                                          projectDoc.DocumentElement.GetAttribute("Name") +
                                          "' project.");
                            }

                            var nodeName = doc.CreateElement(property.GetAttribute("Name"));
                            nodeName.AppendChild(doc.CreateTextNode(
                                                     property.GetAttribute("Value")));
                            importedProjectProperties.AppendChild(nodeName);
                        }
                    }
                }

                projects.AppendChild(importedProject);
            }

            // Also check if there are NuGet packages.config file for
            // this project and if there is, include all of the relevant
            // NuGet package information for referencing the correct DLLs.
            if (File.Exists(packagesPath))
            {
                this.m_NuGetReferenceDetector.ApplyNuGetReferences(
                    rootPath,
                    packagesPath,
                    doc,
                    nuget);
            }

            return(doc);
        }
        private async Task <int> PushNuGetBinaryAsync(string targetUri, string apiKey, MemoryStream file, bool ignoreOnExisting)
        {
            byte[] fileBytes;
            fileBytes = new byte[(int)file.Length];
            file.Read(fileBytes, 0, fileBytes.Length);

            const string ApiKeyHeader = "X-NuGet-ApiKey";

            var boundary = Guid.NewGuid().ToString();

            byte[] boundaryBytes = Encoding.UTF8.GetBytes("--" + boundary + "\r\n");
            byte[] trailer       = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");
            byte[] header        =
                Encoding.UTF8.GetBytes(
                    string.Format(
                        "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\";\r\nContent-Type: {2}\r\n\r\n",
                        "package", "package.nupkg",
                        "application/octet-stream"));

            var requestLength   = boundaryBytes.Length + header.Length + trailer.Length + fileBytes.Length;
            var combinedContent = new byte[requestLength];

            if (combinedContent == null)
            {
                throw new InvalidOperationException("Unable to create byte array " + requestLength + " bytes long for upload!");
            }

            boundaryBytes.CopyTo(combinedContent, 0);
            header.CopyTo(combinedContent, boundaryBytes.Length);
            fileBytes.CopyTo(combinedContent, boundaryBytes.Length + header.Length);
            trailer.CopyTo(combinedContent, boundaryBytes.Length + header.Length + fileBytes.Length);

            using (var client = new RetryableWebClient())
            {
                var       done   = false;
                byte[]    result = null;
                Exception ex     = null;
                var       uploadProgressRenderer = new UploadProgressRenderer();
                client.UploadDataCompleted += (sender, e) => {
                    if (e.Error != null)
                    {
                        ex = e.Error;
                    }

                    try
                    {
                        result = e.Result;
                    }
                    catch { }
                    done = true;
                };
                client.UploadProgressChanged += (sender, e) => {
                    if (!done)
                    {
                        uploadProgressRenderer.Update(e.ProgressPercentage, e.BytesSent / 1024);
                    }
                };

                client.SetHeader("Content-Type", "multipart/form-data; boundary=\"" + boundary + "\"");
                if (!string.IsNullOrWhiteSpace(apiKey))
                {
                    client.SetHeader(ApiKeyHeader, apiKey);
                }

                client.SetHeader("X-NuGet-Protocol-Version", "4.1.0");
                client.SetHeader("User-Agent", "Protobuild");

                client.UploadDataAsync(new Uri(targetUri), "PUT", combinedContent);
                while (!done)
                {
                    System.Threading.Thread.Sleep(0);
                }

                uploadProgressRenderer.FinalizeRendering();

                if (ex != null)
                {
                    var webException = ex as WebException;
                    if (webException != null)
                    {
                        var httpResponse = webException.Response as HttpWebResponse;
                        if (httpResponse != null)
                        {
                            RedirectableConsole.ErrorWriteLine(httpResponse.StatusDescription);

                            if (httpResponse.StatusCode == HttpStatusCode.Conflict)
                            {
                                if (ignoreOnExisting)
                                {
                                    // This is okay - the user doesn't care if there's an existing package with the same version.
                                    return(0);
                                }
                                else
                                {
                                    return(1);
                                }
                            }

                            return(1);
                        }
                    }
                    else
                    {
                        throw new InvalidOperationException("Upload error", ex);
                    }
                }

                if (result != null)
                {
                    var resultDecoded = Encoding.UTF8.GetString(result);
                    if (!string.IsNullOrWhiteSpace(resultDecoded))
                    {
                        RedirectableConsole.WriteLine(Encoding.UTF8.GetString(result));
                    }
                    else
                    {
                        RedirectableConsole.WriteLine("Package uploaded successfully");
                    }
                }
                else
                {
                    RedirectableConsole.WriteLine("Package uploaded successfully");
                }

                return(0);
            }
        }
Example #17
0
        public int Execute(Execution execution)
        {
            var assemblyPath = Assembly.GetEntryAssembly().Location;
            var fileInfo     = new FileInfo(assemblyPath);
            var modulePath   = fileInfo.DirectoryName;

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

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

            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)
                {
                    RedirectableConsole.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)
                        {
                            RedirectableConsole.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)
                        {
                            RedirectableConsole.WriteLine(
                                "There is no output path for '" + execution.ExecuteProjectName + "'; has the project been built?");
                            return(1);
                        }
                        else
                        {
                            executablePath = globalToolPath;
                        }
                    }
                }
            }

            if (!File.Exists(executablePath))
            {
                RedirectableConsole.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);
        }
        private void InstallToolIntoLinuxApplicationMenu(string toolName, string toolPath)
        {
            RedirectableConsole.WriteLine("Installing global tool '" + toolName + "' into the application menu...");

            var menuPath = Path.Combine(GetToolsPath(), ".linux-menus");

            Directory.CreateDirectory(menuPath);

            // Extract the icon from the assembly.
            string iconPath = null;

            try
            {
                var     asm           = System.Reflection.Assembly.Load("System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
                var     iconType      = asm.GetType("System.Drawing.Icon");
                var     extractMethod = iconType.GetMethod("ExtractAssociatedIcon", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public);
                dynamic iconObject    = extractMethod.Invoke(null, new[] { toolPath });
                using (var bmp = iconObject.ToBitmap())
                {
                    var iconPathTemp = Path.Combine(menuPath, toolName + ".png");
                    var enumType     = asm.GetType("System.Drawing.Imaging.ImageFormat");
                    var saveMethod   = ((Type)bmp.GetType()).GetMethods().First(x => x.Name == "Save" && x.GetParameters().Length == 2);
                    saveMethod.Invoke(
                        bmp,
                        new object[] {
                        iconPathTemp,
                        enumType.GetProperty("Png").GetGetMethod().Invoke(null, null)
                    });
                    iconPath = iconPathTemp;
                }
            }
            catch (Exception)
            {
                // No icon to extract.
            }

            var menuItemPath = Path.Combine(menuPath, "protobuild-" + toolName + ".desktop");

            using (var writer = new StreamWriter(menuItemPath))
            {
                writer.WriteLine("[Desktop Entry]");
                writer.WriteLine("Type=Application");
                writer.WriteLine("Name=" + toolName);
                if (iconPath != null)
                {
                    writer.WriteLine("Icon=" + iconPath);
                }
                writer.WriteLine("Exec=/usr/bin/mono " + toolPath);
                writer.WriteLine("Categories=Development");
            }

            var install = System.Diagnostics.Process.Start("xdg-desktop-menu", "install '" + menuItemPath + "'");

            if (install != null)
            {
                install.WaitForExit();

                RedirectableConsole.WriteLine("Global tool '" + toolName + "' is now available in the application menu");
            }
            else
            {
                RedirectableConsole.WriteLine("Unable to install global tool '" + toolName + "' into the application menu (xdg-desktop-menu not found)");
            }
        }
        public Tuple <int, string, string> RunProtobuild(ModuleInfo module, string args, bool capture = false)
        {
            var invokeInline = false;
            var myHash       = ExecEnvironment.GetProgramHash();
            var targetHash   = ExecEnvironment.GetProgramHash(Path.Combine(module.Path, "Protobuild.exe"));

            if (myHash == targetHash)
            {
                invokeInline = true;
            }

            if (ExecEnvironment.RunProtobuildInProcess || invokeInline)
            {
                var oldBuffer = RedirectableConsole.TargetBuffer;
                var ourBuffer = new RedirectableBuffer();
                RedirectableConsole.TargetBuffer = ourBuffer;
                var needsEndSelfInvoke = true;
                try
                {
                    var exitCode = ExecEnvironment.InvokeSelf(module.Path, args.SplitCommandLine().ToArray());
                    RedirectableConsole.TargetBuffer = oldBuffer;
                    needsEndSelfInvoke = false;
                    if (capture)
                    {
                        return(new Tuple <int, string, string>(
                                   exitCode,
                                   ourBuffer.Stdout,
                                   ourBuffer.Stderr));
                    }
                    else
                    {
                        return(new Tuple <int, string, string>(
                                   exitCode,
                                   string.Empty,
                                   string.Empty));
                    }
                }
                finally
                {
                    if (needsEndSelfInvoke)
                    {
                        RedirectableConsole.TargetBuffer = oldBuffer;
                    }
                }
            }

            var protobuildPath = Path.Combine(module.Path, "Protobuild.exe");

            try
            {
                var chmodStartInfo = new ProcessStartInfo
                {
                    FileName         = "chmod",
                    Arguments        = "a+x Protobuild.exe",
                    WorkingDirectory = module.Path,
                    CreateNoWindow   = capture,
                    UseShellExecute  = false
                };
                Process.Start(chmodStartInfo);
            }
            catch (ExecEnvironment.SelfInvokeExitException)
            {
                throw;
            }
            catch
            {
            }

            var stdout = string.Empty;
            var stderr = string.Empty;

            for (var attempt = 0; attempt < 3; attempt++)
            {
                if (File.Exists(protobuildPath))
                {
                    var pi = new ProcessStartInfo
                    {
                        FileName               = protobuildPath,
                        Arguments              = args,
                        WorkingDirectory       = module.Path,
                        CreateNoWindow         = capture,
                        RedirectStandardError  = capture,
                        RedirectStandardInput  = capture,
                        RedirectStandardOutput = capture,
                        UseShellExecute        = false
                    };
                    var p = new Process {
                        StartInfo = pi
                    };
                    if (capture)
                    {
                        p.OutputDataReceived += (sender, eventArgs) =>
                        {
                            if (!string.IsNullOrEmpty(eventArgs.Data))
                            {
                                if (capture)
                                {
                                    stdout += eventArgs.Data + "\n";
                                }
                                else
                                {
                                    RedirectableConsole.WriteLine(eventArgs.Data);
                                }
                            }
                        };
                        p.ErrorDataReceived += (sender, eventArgs) =>
                        {
                            if (!string.IsNullOrEmpty(eventArgs.Data))
                            {
                                if (capture)
                                {
                                    stderr += eventArgs.Data + "\n";
                                }
                                else
                                {
                                    RedirectableConsole.ErrorWriteLine(eventArgs.Data);
                                }
                            }
                        };
                    }
                    try
                    {
                        p.Start();
                    }
                    catch (System.ComponentModel.Win32Exception ex)
                    {
                        if (ex.Message.Contains("Cannot find the specified file"))
                        {
                            // Mono sometimes throws this error even though the
                            // file does exist on disk.  The best guess is there's
                            // a race condition between performing chmod on the
                            // file and Mono actually seeing it as an executable file.
                            // Show a warning and sleep for a bit before retrying.
                            if (attempt != 2)
                            {
                                RedirectableConsole.WriteLine("WARNING: Unable to execute Protobuild.exe, will retry again...");
                                System.Threading.Thread.Sleep(2000);
                                continue;
                            }
                            else
                            {
                                RedirectableConsole.WriteLine("ERROR: Still unable to execute Protobuild.exe.");
                                throw;
                            }
                        }
                    }
                    if (capture)
                    {
                        p.BeginOutputReadLine();
                        p.BeginErrorReadLine();
                    }
                    p.WaitForExit();
                    return(new Tuple <int, string, string>(p.ExitCode, stdout, stderr));
                }
            }

            return(new Tuple <int, string, string>(1, string.Empty, string.Empty));
        }
Example #20
0
        public int Execute(Execution execution)
        {
            var    hostPlatform          = _hostPlatformDetector.DetectPlatform();
            string builderPathNativeArch = null;
            string builderPath64         = null;
            string builderPath32         = null;
            var    extraArgsNativeArch   = string.Empty;
            var    extraArgs64           = string.Empty;
            var    extraArgs32           = string.Empty;
            var    extraArgsGeneral      = string.Empty;

            if (hostPlatform == "Windows")
            {
                foreach (var arch in new[] { RegistryView.Default, RegistryView.Registry32, RegistryView.Registry64 })
                {
                    // Find latest version of MSBuild.
                    var registryKey =
                        RegistryKey.OpenBaseKey(
                            RegistryHive.LocalMachine,
                            arch)
                        .OpenSubKey("SOFTWARE")?
                        .OpenSubKey("Microsoft")?
                        .OpenSubKey("MSBuild")?
                        .OpenSubKey("ToolsVersions");
                    if (registryKey == null)
                    {
                        if (arch == RegistryView.Registry64)
                        {
                            continue;
                        }

                        RedirectableConsole.ErrorWriteLine(
                            "ERROR: No versions of MSBuild were available " +
                            "according to the registry (or they were not readable).");
                        return(1);
                    }

                    var subkeys         = registryKey.GetSubKeyNames();
                    var orderedVersions =
                        subkeys.OrderByDescending(x => int.Parse(x.Split('.').First(), CultureInfo.InvariantCulture));
                    var builderPath = (from version in orderedVersions
                                       let path = (string)registryKey.OpenSubKey(version)?.GetValue("MSBuildToolsPath")
                                                  where path != null && Directory.Exists(path)
                                                  let msbuild = Path.Combine(path, "MSBuild.exe")
                                                                where File.Exists(msbuild)
                                                                select msbuild).FirstOrDefault();

                    if (builderPath == null)
                    {
                        if (arch == RegistryView.Registry64)
                        {
                            continue;
                        }

                        RedirectableConsole.ErrorWriteLine(
                            "ERROR: Unable to find installed MSBuild in any installed tools version.");
                        return(1);
                    }

                    var extraArgs = string.Empty;
                    if (!builderPath.Contains("v2.0.50727"))
                    {
                        extraArgs = "/m /nodeReuse:false ";
                    }

                    switch (arch)
                    {
                    case RegistryView.Default:
                        builderPathNativeArch = builderPath;
                        extraArgsNativeArch   = extraArgs;
                        break;

                    case RegistryView.Registry32:
                        builderPath32 = builderPath;
                        extraArgs32   = extraArgs;
                        break;

                    case RegistryView.Registry64:
                        builderPath64 = builderPath;
                        extraArgs64   = extraArgs;
                        break;
                    }
                }
            }
            else
            {
                // Find path to xbuild.
                var whichPaths = new[] { "/bin/which", "/usr/bin/which" };
                foreach (var w in whichPaths)
                {
                    if (File.Exists(w))
                    {
                        var whichProcess = Process.Start(new ProcessStartInfo(w, "xbuild")
                        {
                            RedirectStandardOutput = true,
                            UseShellExecute        = false
                        });
                        if (whichProcess == null)
                        {
                            continue;
                        }
                        var result = whichProcess.StandardOutput.ReadToEnd().Trim();
                        if (!string.IsNullOrWhiteSpace(result) && File.Exists(result))
                        {
                            builderPathNativeArch = result;
                            break;
                        }
                    }
                }

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

                if (builderPathNativeArch == null)
                {
                    RedirectableConsole.ErrorWriteLine("ERROR: Unable to find xbuild on the current PATH.");
                    return(1);
                }

                builderPath32 = builderPathNativeArch;
                builderPath64 = builderPathNativeArch;
            }

            if (!string.IsNullOrWhiteSpace(execution.BuildTarget))
            {
                extraArgsGeneral += "/t:\"" + execution.BuildTarget + "\" ";
            }
            foreach (var prop in execution.BuildProperties)
            {
                extraArgsGeneral += "/p:\"" + prop.Key.Replace("\"", "\\\"") + "\"=\"" + (prop.Value ?? string.Empty).Replace("\"", "\\\"") + "\" ";
            }

            switch (execution.BuildProcessArchitecture)
            {
            case "x86":
                RedirectableConsole.WriteLine("INFO: Using " + builderPath32 + " (forced 32-bit) to perform this build.");
                break;

            case "x64":
                RedirectableConsole.WriteLine("INFO: Using " + builderPath64 + " (forced 64-bit) to perform this build.");
                break;

            case "Default":
            default:
                RedirectableConsole.WriteLine("INFO: Using " + builderPathNativeArch + " (32-bit: " + builderPath32 + ") to perform this build.");
                break;
            }

            var targetPlatforms = (execution.Platform ?? hostPlatform).Split(',');
            var module          = ModuleInfo.Load(Path.Combine(execution.WorkingDirectory, "Build", "Module.xml"));

            foreach (var platform in targetPlatforms)
            {
                string builderPath;
                string extraArgs;

                switch (execution.BuildProcessArchitecture)
                {
                case "x86":
                    builderPath = builderPath32;
                    extraArgs   = extraArgs32 + extraArgsGeneral;
                    break;

                case "x64":
                    builderPath = builderPath64;
                    extraArgs   = extraArgs64 + extraArgsGeneral;
                    break;

                case "Default":
                default:
                    builderPath = platform == "WindowsPhone" ? builderPath32 : builderPathNativeArch;
                    extraArgs   = (platform == "WindowsPhone" ? extraArgs32 : extraArgsNativeArch) + extraArgsGeneral;
                    break;
                }

                var fileToBuild = module.Name + "." + platform + ".sln";

                RedirectableConsole.WriteLine("INFO: Executing " + builderPath + " with arguments: " + extraArgs + fileToBuild);

                var process =
                    Process.Start(new ProcessStartInfo(builderPath, extraArgs + fileToBuild)
                {
                    UseShellExecute = false
                });
                if (process == null)
                {
                    RedirectableConsole.ErrorWriteLine("ERROR: Build process did not start successfully.");
                    return(1);
                }
                process.WaitForExit();

                if (process.ExitCode != 0)
                {
                    return(process.ExitCode);
                }
            }

            return(0);
        }
Example #21
0
        public int Execute(Execution execution)
        {
            var assemblyPath = Assembly.GetEntryAssembly().Location;
            var fileInfo     = new FileInfo(assemblyPath);
            var modulePath   = fileInfo.DirectoryName;

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

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

            string executablePath     = null;
            var    executableIsNative = false;

            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)
                {
                    RedirectableConsole.WriteLine(
                        "There is no global tool registered as '" + execution.ExecuteProjectName + "'");
                    return(1);
                }
                else
                {
                    executablePath     = globalToolPath;
                    executableIsNative = m_HostPlatformDetector.DetectPlatform() == "MacOS" && globalToolPath.EndsWith(".app");
                }
            }
            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)
                        {
                            RedirectableConsole.WriteLine(
                                "There is no project definition with name '" + execution.ExecuteProjectName + "'");
                            return(1);
                        }
                        else
                        {
                            executablePath     = globalToolPath;
                            executableIsNative = m_HostPlatformDetector.DetectPlatform() == "MacOS" && globalToolPath.EndsWith(".app");
                        }
                    }
                }
                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);
                        var    targetName         = assemblyName + ".exe";
                        string targetAppName      = null;
                        if (m_HostPlatformDetector.DetectPlatform() == "MacOS")
                        {
                            targetAppName = assemblyName + ".app/Contents/MacOS/" + assemblyName;
                        }
                        if (preferredDirectory != null && (File.Exists(Path.Combine(preferredDirectory.FullName, targetName)) || (targetAppName != null && File.Exists(Path.Combine(preferredDirectory.FullName, targetAppName)))))
                        {
                            if (targetAppName != null && File.Exists(Path.Combine(preferredDirectory.FullName, targetAppName)))
                            {
                                // We must use the 'defaults' tool on macOS to determine if the target is a
                                // graphical application.  We do this by checking for the presence of NSPrincipalClass
                                // in the Info.plist file, which must be present for graphical applications to
                                // work.  If it does not exist, we assume it is a command-line application and run
                                // it normally like on any other platform.  We have to do this because the native
                                // entry point is the only one that has access to the GUI, while the non-native
                                // entry point is the only one that has the correct working directory set on
                                // startup.
                                if (_graphicalAppDetection.TargetMacOSAppIsGraphical(Path.Combine(preferredDirectory.FullName, assemblyName + ".app")))
                                {
                                    executablePath     = Path.Combine(preferredDirectory.FullName, targetAppName);
                                    executableIsNative = true;
                                }
                            }
                            if (executablePath == null && File.Exists(Path.Combine(preferredDirectory.FullName, targetName)))
                            {
                                executablePath = Path.Combine(preferredDirectory.FullName, targetName);
                            }
                        }
                        else
                        {
                            foreach (var subdirectory in subdirectories)
                            {
                                var    tempPath    = Path.Combine(subdirectory.FullName, assemblyName + ".exe");
                                string tempAppName = null;
                                if (m_HostPlatformDetector.DetectPlatform() == "MacOS")
                                {
                                    tempAppName = Path.Combine(subdirectory.FullName, assemblyName + ".app/Contents/MacOS/" + assemblyName);
                                }

                                if (tempAppName != null && File.Exists(tempAppName))
                                {
                                    // We must use the 'defaults' tool on macOS to determine if the target is a
                                    // graphical application.  We do this by checking for the presence of NSPrincipalClass
                                    // in the Info.plist file, which must be present for graphical applications to
                                    // work.  If it does not exist, we assume it is a command-line application and run
                                    // it normally like on any other platform.  We have to do this because the native
                                    // entry point is the only one that has access to the GUI, while the non-native
                                    // entry point is the only one that has the correct working directory set on
                                    // startup.
                                    if (_graphicalAppDetection.TargetMacOSAppIsGraphical(Path.Combine(subdirectory.FullName, assemblyName + ".app")))
                                    {
                                        executablePath     = tempAppName;
                                        executableIsNative = true;
                                        break;
                                    }
                                }
                                if (File.Exists(tempPath))
                                {
                                    executablePath = tempPath;
                                    break;
                                }
                            }
                        }
                    }
                    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)
                        {
                            RedirectableConsole.WriteLine(
                                "There is no output path for '" + execution.ExecuteProjectName + "'; has the project been built?");
                            return(1);
                        }
                        else
                        {
                            executablePath     = globalToolPath;
                            executableIsNative = m_HostPlatformDetector.DetectPlatform() == "MacOS" && globalToolPath.EndsWith(".app");
                        }
                    }
                }
            }

            if (!(File.Exists(executablePath) || (executablePath.EndsWith(".app") && Directory.Exists(executablePath))))
            {
                RedirectableConsole.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 == '/' && !executableIsNative)
            {
                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
            {
                if (m_HostPlatformDetector.DetectPlatform() == "MacOS" && executablePath.EndsWith(".app"))
                {
                    // We must use 'open -a' to launch this application.
                    arguments      = "-a '" + executablePath.Replace("'", "'\"'\"'") + "' " + arguments;
                    executablePath = "/usr/bin/open";
                }

                startInfo = new ProcessStartInfo(
                    executablePath,
                    arguments);
            }
            startInfo.UseShellExecute = false;

            var process = Process.Start(startInfo);

            process.WaitForExit();
            return(process.ExitCode);
        }
        private void ResolveLibraryBinary(string workingDirectory, ICachableBinaryPackageMetadata protobuildMetadata, string folder, bool forceUpgrade, Func <byte[]> getBinaryPackage)
        {
            var platformFolder = Path.Combine(folder, protobuildMetadata.Platform);

            if (File.Exists(Path.Combine(platformFolder, ".pkg")))
            {
                if (!forceUpgrade)
                {
                    RedirectableConsole.WriteLine("Protobuild binary package already present at " + platformFolder);
                    return;
                }
            }

            RedirectableConsole.WriteLine("Creating and emptying " + platformFolder);

            if (File.Exists(Path.Combine(folder, ".pkg")))
            {
                if (Directory.Exists(platformFolder))
                {
                    // Only clear out the target's folder if the reference folder
                    // already contains binary packages (for other platforms)
                    PathUtils.AggressiveDirectoryDelete(platformFolder);
                }
            }
            else
            {
                // The reference folder is holding source code, so clear it
                // out entirely.
                PathUtils.AggressiveDirectoryDelete(folder);
            }

            Directory.CreateDirectory(platformFolder);

            RedirectableConsole.WriteLine("Marking " + folder + " as ignored for Git");
            GitUtils.MarkIgnored(folder);

            var package = getBinaryPackage();

            if (package == null)
            {
                return;
            }

            ExtractTo(workingDirectory, protobuildMetadata.PackageName, protobuildMetadata.BinaryFormat, package, platformFolder, protobuildMetadata.Platform);

            // Only copy ourselves to the binary folder if both "Build/Module.xml" and
            // "Build/Projects" exist in the binary package's folder.  This prevents us
            // from triggering the "create new module?" logic if the package hasn't been
            // setup correctly.
            if (Directory.Exists(Path.Combine(platformFolder, "Build", "Projects")) &&
                File.Exists(Path.Combine(platformFolder, "Build", "Module.xml")))
            {
                var sourceProtobuild = Assembly.GetEntryAssembly().Location;
                File.Copy(sourceProtobuild, Path.Combine(platformFolder, "Protobuild.exe"), true);

                try
                {
                    var chmodStartInfo = new ProcessStartInfo
                    {
                        FileName         = "chmod",
                        Arguments        = "a+x Protobuild.exe",
                        WorkingDirectory = platformFolder,
                        UseShellExecute  = false
                    };
                    Process.Start(chmodStartInfo);
                }
                catch (ExecEnvironment.SelfInvokeExitException)
                {
                    throw;
                }
                catch
                {
                }
            }

            var file = File.Create(Path.Combine(platformFolder, ".pkg"));

            file.Close();

            file = File.Create(Path.Combine(folder, ".pkg"));
            file.Close();

            RedirectableConsole.WriteLine("Binary resolution complete");
        }
        public int Execute(Execution execution)
        {
            if (!Directory.Exists(execution.PackageSourceFolder))
            {
                throw new InvalidOperationException("The source folder " + execution.PackageSourceFolder + " does not exist.");
            }

            if (execution.PackagePlatform == "Template" && execution.PackageFormat != PackageManager.ARCHIVE_FORMAT_NUGET_ZIP)
            {
                return(ExecuteForTemplate(execution));
            }

            var        allowAutopackage   = true;
            var        moduleExpectedPath = Path.Combine(execution.PackageSourceFolder, "Build", "Module.xml");
            ModuleInfo rootModule         = null;

            if (!File.Exists(moduleExpectedPath))
            {
                if (execution.PackageFilterFile == null)
                {
                    RedirectableConsole.WriteLine(
                        "There is no module in the path '" + execution.PackageSourceFolder + "' (expected to " +
                        "find a Build\\Module.xml file within that directory).");
                    return(1);
                }
                else
                {
                    // We allow this mode if the user has provided a filter file and are constructing
                    // the package manually.
                    allowAutopackage = false;
                }
            }
            else
            {
                rootModule = ModuleInfo.Load(moduleExpectedPath);
            }

            var temporaryFiles = new List <string>();

            try
            {
                var customDirectives = new Dictionary <string, Action <FileFilter> >()
                {
                    {
                        "autopackage",
                        f =>
                        {
                            if (allowAutopackage && rootModule != null)
                            {
                                this.m_AutomaticProjectPackager.Autopackage(
                                    execution.WorkingDirectory,
                                    f,
                                    execution,
                                    rootModule,
                                    execution.PackageSourceFolder,
                                    execution.PackagePlatform,
                                    execution.PackageFormat,
                                    temporaryFiles);
                            }
                            else
                            {
                                RedirectableConsole.WriteLine(
                                    "WARNING: There is no module in the path '" + execution.PackageSourceFolder +
                                    "' (expected to " +
                                    "find a Build\\Module.xml file within that directory).  Ignoring the 'autopackage' directive.");
                            }
                        }
                    }
                };

                RedirectableConsole.WriteLine("Starting package creation for " + execution.PackagePlatform);

                var filter =
                    new FileFilter(_getRecursiveUtilitiesInPath.GetRecursiveFilesInPath(execution.PackageSourceFolder));
                if (execution.PackageFilterFile != null)
                {
                    using (var reader = new StreamReader(execution.PackageFilterFile))
                    {
                        var contents = reader.ReadToEnd();
                        contents = contents.Replace("%PLATFORM%", execution.PackagePlatform);

                        using (var inputStream = new MemoryStream(Encoding.ASCII.GetBytes(contents)))
                        {
                            this.m_FileFilterParser.ParseAndApply(filter, inputStream, customDirectives);
                        }
                    }
                }
                else
                {
                    customDirectives["autopackage"](filter);
                }

                if (File.Exists(execution.PackageDestinationFile))
                {
                    RedirectableConsole.WriteLine("The destination file " + execution.PackageDestinationFile +
                                                  " already exists; it will be overwritten.");
                    File.Delete(execution.PackageDestinationFile);
                }

                filter.ImplyDirectories();

                if (execution.PackageFormat != PackageManager.ARCHIVE_FORMAT_NUGET_ZIP)
                {
                    if (!filter.ContainsTargetPath("Build/"))
                    {
                        RedirectableConsole.WriteLine("ERROR: The Build directory does not exist in the source folder.");
                        if (execution.PackageFilterFile != null)
                        {
                            this.PrintFilterMappings(filter);
                        }
                        return(1);
                    }

                    if (!filter.ContainsTargetPath("Build/Projects/"))
                    {
                        RedirectableConsole.WriteLine("ERROR: The Build\\Projects directory does not exist in the source folder.");
                        if (execution.PackageFilterFile != null)
                        {
                            this.PrintFilterMappings(filter);
                        }
                        return(1);
                    }

                    if (!filter.ContainsTargetPath("Build/Module.xml"))
                    {
                        RedirectableConsole.WriteLine("ERROR: The Build\\Module.xml file does not exist in the source folder.");
                        if (execution.PackageFilterFile != null)
                        {
                            this.PrintFilterMappings(filter);
                        }
                        return(1);
                    }
                }

                if (filter.ContainsTargetPath("Protobuild.exe"))
                {
                    RedirectableConsole.WriteLine("ERROR: The Protobuild.exe file should not be included in the package file.");
                    if (execution.PackageFilterFile != null)
                    {
                        this.PrintFilterMappings(filter);
                    }
                    return(1);
                }

                using (
                    var target = new FileStream(execution.PackageDestinationFile, FileMode.CreateNew, FileAccess.Write,
                                                FileShare.None))
                {
                    _packageCreator.Create(
                        target,
                        filter,
                        execution.PackageSourceFolder,
                        execution.PackageFormat,
                        execution.PackagePlatform,
                        execution.PackageDestinationFile);
                }

                RedirectableConsole.WriteLine("\rPackage written to " + execution.PackageDestinationFile + " successfully.");
                return(0);
            }
            finally
            {
                foreach (var file in temporaryFiles)
                {
                    File.Delete(file);
                }
            }
        }
        private byte[] GetBinaryPackage(ICachableBinaryPackageMetadata metadata)
        {
            if (metadata.BinaryFormat == null || metadata.BinaryUri == null)
            {
                // There is no binary format for this package.
                return(null);
            }

            var localFileExists = false;

            try
            {
                localFileExists = File.Exists(metadata.BinaryUri);
            }
            catch
            {
            }

            if (metadata.BinaryFormat != null && localFileExists)
            {
                // This is a local package file, read it directly.
                using (var stream = new FileStream(metadata.BinaryUri, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    var data = new byte[stream.Length];
                    stream.Read(data, 0, data.Length);
                    return(data);
                }
            }

            if (this.HasBinaryPackage(metadata))
            {
                // We have it already downloaded in the cache.
                var file = Path.Combine(
                    _packageCacheConfiguration.GetCacheDirectory(),
                    this.GetPackageName(metadata));
                using (var stream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    var data = new byte[stream.Length];
                    stream.Read(data, 0, data.Length);
                    return(data);
                }
            }

            // We must use the package retrieval interface to download a copy
            // of the package.
            var tempFile = Path.Combine(
                _packageCacheConfiguration.GetCacheDirectory(),
                this.GetPackageName(metadata) + ".tmp");

            if (!DownloadBinaryPackage(metadata, tempFile))
            {
                return(null);
            }

            var saveFile = Path.Combine(
                _packageCacheConfiguration.GetCacheDirectory(),
                this.GetPackageName(metadata));

            try
            {
                File.Move(tempFile, saveFile);
            }
            catch (Exception)
            {
                RedirectableConsole.WriteLine("WARNING: Unable to save package to cache.");
                saveFile = tempFile;
            }

            byte[] saveData;
            using (var stream = new FileStream(saveFile, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                saveData = new byte[stream.Length];
                stream.Read(saveData, 0, saveData.Length);
            }

            if (saveFile == tempFile)
            {
                File.Delete(tempFile);
            }

            return(saveData);
        }
Example #25
0
        public void ResolveAll(string workingDirectory, ModuleInfo module, string platform, bool?enableParallelisation, bool forceUpgrade, bool?safeResolve)
        {
            if (!_featureManager.IsFeatureEnabled(Feature.PackageManagement))
            {
                return;
            }

            RedirectableConsole.WriteLine("Starting resolution of packages for " + platform + "...");

            var parallelisation = enableParallelisation ?? _hostPlatformDetector.DetectPlatform() == "Windows";

            if (parallelisation)
            {
                RedirectableConsole.WriteLine("Enabled parallelisation; use --no-parallel to disable...");
            }

            if (module.Packages != null && module.Packages.Count > 0)
            {
                var taskList   = new List <Task <Tuple <string, Action> > >();
                var resultList = new List <Tuple <string, Action> >();
                foreach (var submodule in module.Packages)
                {
                    if (submodule.IsActiveForPlatform(platform))
                    {
                        RedirectableConsole.WriteLine("Querying: " + submodule.Uri);
                        var submodule1 = submodule;
                        if (parallelisation)
                        {
                            var task = new Func <Task <Tuple <string, Action> > >(async() =>
                            {
                                var metadata = await Task.Run(() =>
                                                              Lookup(workingDirectory, module, submodule1, platform, null, null, forceUpgrade, safeResolve));
                                if (metadata == null)
                                {
                                    return(new Tuple <string, Action>(submodule1.Uri, () => { }));
                                }
                                return(new Tuple <string, Action>(submodule1.Uri,
                                                                  () => { this.Resolve(workingDirectory, metadata, submodule1, null, null, forceUpgrade, safeResolve); }));
                            });
                            taskList.Add(task());
                        }
                        else
                        {
                            var metadata = Lookup(workingDirectory, module, submodule1, platform, null, null, forceUpgrade, safeResolve);
                            if (metadata == null)
                            {
                                resultList.Add(new Tuple <string, Action>(submodule1.Uri, () => { }));
                            }
                            else
                            {
                                resultList.Add(new Tuple <string, Action>(submodule1.Uri,
                                                                          () => { this.Resolve(workingDirectory, metadata, submodule1, null, null, forceUpgrade, safeResolve); }));
                            }
                        }
                    }
                    else
                    {
                        RedirectableConsole.WriteLine("Skipping resolution for " + submodule.Uri + " because it is not active for this target platform");
                    }
                }

                if (parallelisation)
                {
                    var taskArray = taskList.ToArray();
                    Task.WaitAll(taskArray);
                    foreach (var tuple in taskArray)
                    {
                        RedirectableConsole.WriteLine("Resolving: " + tuple.Result.Item1);
                        tuple.Result.Item2();
                    }
                }
                else
                {
                    foreach (var tuple in resultList)
                    {
                        RedirectableConsole.WriteLine("Resolving: " + tuple.Item1);
                        tuple.Item2();
                    }
                }
            }

            foreach (var submodule in module.GetSubmodules(platform))
            {
                if (submodule.Packages.Count == 0 && submodule.GetSubmodules(platform).Length == 0)
                {
                    if (_featureManager.IsFeatureEnabledInSubmodule(module, submodule, Feature.OptimizationSkipResolutionOnNoPackagesOrSubmodules))
                    {
                        RedirectableConsole.WriteLine(
                            "Skipping package resolution in submodule for " + submodule.Name + " (there are no submodule or packages)");
                        continue;
                    }
                }

                RedirectableConsole.WriteLine(
                    "Invoking package resolution in submodule for " + submodule.Name);
                string parallelMode = null;
                if (_featureManager.IsFeatureEnabledInSubmodule(module, submodule, Feature.TaskParallelisation))
                {
                    if (parallelisation)
                    {
                        parallelMode += "-parallel ";
                    }
                    else
                    {
                        parallelMode += "-no-parallel ";
                    }
                }
                _moduleExecution.RunProtobuild(
                    submodule,
                    _featureManager.GetFeatureArgumentToPassToSubmodule(module, submodule) + parallelMode +
                    "-resolve " + platform + " " + packageRedirector.GetRedirectionArguments());
                RedirectableConsole.WriteLine(
                    "Finished submodule package resolution for " + submodule.Name);
            }

            RedirectableConsole.WriteLine("Package resolution complete.");
        }
        private void ExtractTo(string workingDirectory, string packageName, string format, byte[] data, string path, string platform)
        {
            RedirectableConsole.WriteLine("Unpacking binary package from " + format + " archive");
            switch (format)
            {
            case PackageManager.ARCHIVE_FORMAT_TAR_GZIP:
            {
                using (var memory = new MemoryStream(data))
                {
                    using (var decompress = new GZipStream(memory, CompressionMode.Decompress))
                    {
                        using (var memory2 = new MemoryStream())
                        {
                            decompress.CopyTo(memory2);
                            memory2.Seek(0, SeekOrigin.Begin);
                            var reader       = new tar_cs.TarReader(memory2);
                            var reduplicator = new Reduplicator();
                            reduplicator.UnpackTarToFolder(reader, path);
                        }
                    }
                }
                break;
            }

            case PackageManager.ARCHIVE_FORMAT_TAR_LZMA:
            {
                using (var inMemory = new MemoryStream(data))
                {
                    using (var outMemory = new MemoryStream())
                    {
                        LZMA.LzmaHelper.Decompress(inMemory, outMemory);
                        outMemory.Seek(0, SeekOrigin.Begin);
                        var reader       = new tar_cs.TarReader(outMemory);
                        var reduplicator = new Reduplicator();
                        reduplicator.UnpackTarToFolder(reader, path);
                    }
                }
                break;
            }

            case PackageManager.ARCHIVE_FORMAT_NUGET_ZIP:
            {
                using (var inMemory = new MemoryStream(data))
                {
                    using (var zipStorer = ZipStorer.Open(inMemory, FileAccess.Read, true))
                    {
                        var reduplicator   = new Reduplicator();
                        var extractedFiles = reduplicator.UnpackZipToFolder(
                            zipStorer,
                            path,
                            candidatePath => candidatePath.Replace('\\', '/').StartsWith("protobuild/" + platform + "/"),
                            outputPath => outputPath.Replace('\\', '/').Substring(("protobuild/" + platform + "/").Length));

                        if (extractedFiles.Count == 0)
                        {
                            // There were no files that matched protobuild/ which means this is
                            // not a Protobuild-aware NuGet package.  We need to convert it on-the-fly
                            // to a compatible Protobuild format.
                            ConvertNuGetOnlyPackage(reduplicator, zipStorer, path, packageName, workingDirectory, platform);
                        }
                    }
                }
                break;
            }

            default:
                throw new InvalidOperationException(
                          "This version of Protobuild does not support the " +
                          format + " package format.");
            }
        }
Example #27
0
        /// <summary>
        /// The entry point for Protobuild.
        /// </summary>
        /// <param name="args">The arguments passed in on the command line.</param>
        public static void Main(string workingDirectory, string[] args)
        {
            // Ensure we always use the invariant culture in Protobuild.
            Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;

            // Set our SSL trust policy.  Because Mono doesn't ship with root certificates
            // on most Linux distributions, we have to be a little more insecure here than
            // I'd like.  For protobuild.org we always verify that the root of the certificate
            // chain matches what we expect (so people can't forge a certificate from a
            // *different CA*), but for other domains we just have to implicitly trust them
            // on Linux since we have no root store.
            if (Path.DirectorySeparatorChar == '/' && !Directory.Exists("/Library"))
            {
                ServicePointManager.ServerCertificateValidationCallback = SSLValidationForLinux;
            }

            var kernel = new LightweightKernel();

            kernel.BindCore();
            kernel.BindBuildResources();
            kernel.BindGeneration();
            kernel.BindJSIL();
            kernel.BindTargets();
            kernel.BindFileFilter();
            kernel.BindPackages();
            kernel.BindAutomatedBuild();

            var featureManager = kernel.Get <IFeatureManager>();

            featureManager.LoadFeaturesFromDirectory(workingDirectory);

            var commandMappings = new Dictionary <string, ICommand>
            {
                { "sync", kernel.Get <SyncCommand>() },
                { "resync", kernel.Get <ResyncCommand>() },
                { "generate", kernel.Get <GenerateCommand>() },
                { "build", kernel.Get <BuildCommand>() },
                { "build-target", kernel.Get <BuildTargetCommand>() },
                { "build-property", kernel.Get <BuildPropertyCommand>() },
                { "build-process-arch", kernel.Get <BuildProcessArchCommand>() },
                { "clean", kernel.Get <CleanCommand>() },
                { "automated-build", kernel.Get <AutomatedBuildCommand>() },
                { "extract-xslt", kernel.Get <ExtractXSLTCommand>() },
                { "enable", kernel.Get <EnableServiceCommand>() },
                { "disable", kernel.Get <DisableServiceCommand>() },
                { "debug-service-resolution", kernel.Get <DebugServiceResolutionCommand>() },
                { "debug-project-generation", kernel.Get <DebugProjectGenerationCommand>() },
                { "simulate-host-platform", kernel.Get <SimulateHostPlatformCommand>() },
                { "spec", kernel.Get <ServiceSpecificationCommand>() },
                { "query-features", kernel.Get <QueryFeaturesCommand>() },
                { "features", kernel.Get <FeaturesCommand>() },
                { "add", kernel.Get <AddPackageCommand>() },
                { "remove", kernel.Get <RemovePackageCommand>() },
                { "list", kernel.Get <ListPackagesCommand>() },
                { "install", kernel.Get <InstallPackageCommand>() },
                { "upgrade", kernel.Get <UpgradePackageCommand>() },
                { "upgrade-all", kernel.Get <UpgradeAllPackagesCommand>() },
                { "pack", kernel.Get <PackPackageCommand>() },
                { "format", kernel.Get <FormatPackageCommand>() },
                { "push", kernel.Get <PushPackageCommand>() },
                { "ignore-on-existing", kernel.Get <IgnoreOnExistingPackageCommand>() },
                { "repush", kernel.Get <RepushPackageCommand>() },
                { "resolve", kernel.Get <ResolveCommand>() },
                { "no-resolve", kernel.Get <NoResolveCommand>() },
                { "safe-resolve", kernel.Get <SafeResolveCommand>() },
                { "parallel", kernel.Get <ParallelCommand>() },
                { "no-parallel", kernel.Get <NoParallelCommand>() },
                { "redirect", kernel.Get <RedirectPackageCommand>() },
                { "swap-to-source", kernel.Get <SwapToSourceCommand>() },
                { "swap-to-binary", kernel.Get <SwapToBinaryCommand>() },
                { "start", kernel.Get <StartCommand>() },
                { "no-generate", kernel.Get <NoGenerateCommand>() },
                { "no-host-generate", kernel.Get <NoHostGenerateCommand>() },
                { "execute", kernel.Get <ExecuteCommand>() },
                { "execute-configuration", kernel.Get <ExecuteConfigurationCommand>() },
                { "package-id", kernel.Get <PackageIdCommand>() },
                { "package-git-repo", kernel.Get <PackageGitRepoCommand>() },
                { "package-git-commit", kernel.Get <PackageGitCommitCommand>() },
                { "package-type", kernel.Get <PackageTypeCommand>() },
            };

            var execution = new Execution();

            execution.WorkingDirectory = workingDirectory;
            execution.CommandToExecute = kernel.Get <DefaultCommand>();

            var options = new Options();

            foreach (var kv in commandMappings)
            {
                var key   = kv.Key;
                var value = kv.Value;

                Action <string[]> handle = x =>
                {
                    if (value.IsRecognised())
                    {
                        value.Encounter(execution, x);
                    }
                    else if (value.IsIgnored())
                    {
                    }
                    else
                    {
                        throw new InvalidOperationException("Unknown argument '" + key + "'");
                    }
                };

                if (value.GetArgCount() == 0)
                {
                    options[key] = handle;
                }
                else
                {
                    options[key + "@" + value.GetArgCount()] = handle;
                }
            }

            Action <string[]> helpAction = x =>
            {
                PrintHelp(commandMappings);
                ExecEnvironment.Exit(0);
            };

            options["help"] = helpAction;
            options["?"]    = helpAction;

            if (ExecEnvironment.DoNotWrapExecutionInTry)
            {
                options.Parse(args);
            }
            else
            {
                try
                {
                    options.Parse(args);
                }
                catch (InvalidOperationException ex)
                {
                    RedirectableConsole.WriteLine(ex.Message);
                    PrintHelp(commandMappings);
                    ExecEnvironment.Exit(1);
                }
            }

            featureManager.ValidateEnabledFeatures();

            if (ExecEnvironment.DoNotWrapExecutionInTry)
            {
                var exitCode = execution.CommandToExecute.Execute(execution);
                ExecEnvironment.Exit(exitCode);
            }
            else
            {
                try
                {
                    var exitCode = execution.CommandToExecute.Execute(execution);
                    ExecEnvironment.Exit(exitCode);
                }
                catch (ExecEnvironment.SelfInvokeExitException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    RedirectableConsole.WriteLine(ex);
                    ExecEnvironment.Exit(1);
                }
            }
        }
        private void ConvertNuGetOnlyPackage(Reduplicator reduplicator, ZipStorer zipStorer, string path, string packageName, string workingDirectory, string platform)
        {
            var folder = Path.GetTempFileName();

            File.Delete(folder);
            Directory.CreateDirectory(folder);

            try
            {
                reduplicator.UnpackZipToFolder(
                    zipStorer,
                    folder,
                    candidatePath => true,
                    outputPath => outputPath);

                var references          = new List <string>();
                var libraryReferences   = new Dictionary <string, string>();
                var packageDependencies = new Dictionary <string, string>();

                // Load NuGet specification file.
                var specFile = Directory.GetFiles(folder, "*.nuspec").FirstOrDefault();
                if (specFile != null)
                {
                    specFile = Path.Combine(folder, specFile);
                    if (File.Exists(specFile))
                    {
                        var packageDoc = new XmlDocument();
                        packageDoc.Load(specFile);

                        if (packageDoc?.DocumentElement != null)
                        {
                            // If we have an id in the package, that forms the package name.
                            if (packageDoc.DocumentElement.FirstChild.ChildNodes.OfType <XmlElement>()
                                .Count(x => x.Name == "id") > 0)
                            {
                                var newName = packageDoc.DocumentElement.FirstChild.ChildNodes.OfType <XmlElement>()
                                              .First(x => x.Name == "id").InnerText.Trim();
                                if (!string.IsNullOrWhiteSpace(newName))
                                {
                                    packageName = newName;
                                }
                            }

                            // If the references are explicitly provided in the nuspec, use
                            // those as to what files should be referenced by the projects.
                            if (packageDoc.DocumentElement.FirstChild.ChildNodes.OfType <XmlElement>()
                                .Count(x => x.Name == "references") > 0)
                            {
                                references =
                                    packageDoc.DocumentElement.FirstChild.ChildNodes.OfType <XmlElement>()
                                    .First(x => x.Name == "references")
                                    .ChildNodes.OfType <XmlElement>()
                                    .Where(x => x.Name == "reference")
                                    .Select(x => x.Attributes["file"].Value)
                                    .ToList();
                            }

                            // If there are dependencies specified, store them and convert them to
                            // Protobuild references, and reference them in the Module.xml file.
                            if (packageDoc.DocumentElement.FirstChild.ChildNodes.OfType <XmlElement>()
                                .Count(x => x.Name == "dependencies") > 0)
                            {
                                packageDependencies =
                                    packageDoc.DocumentElement.FirstChild.ChildNodes.OfType <XmlElement>()
                                    .First(x => x.Name == "dependencies")
                                    .ChildNodes.OfType <XmlElement>()
                                    .Where(x => x.Name == "dependency")
                                    .ToDictionarySafe(
                                        k => k.Attributes["id"].Value,
                                        v => v.Attributes["version"].Value,
                                        (dict, c) =>
                                        RedirectableConsole.WriteLine("WARNING: More than one dependency on " +
                                                                      c +
                                                                      " in NuGet package."));
                            }
                        }
                    }
                }

                if (string.IsNullOrWhiteSpace(packageName))
                {
                    throw new InvalidOperationException("Expected package name when converting NuGet-only package!");
                }

                // Determine the priority of the frameworks that we want to target
                // out of the available versions.
                string[] clrNames = _nugetPlatformMapping.GetFrameworkNamesForRead(workingDirectory, platform);

                var referenceDirectories = new string[] { "ref", "lib" };

                foreach (var directory in referenceDirectories)
                {
                    // Determine the base path for all references; that is, the lib/ folder.
                    var referenceBasePath = Path.Combine(
                        folder,
                        directory);

                    if (Directory.Exists(referenceBasePath))
                    {
                        // If no references are in nuspec, reference all of the libraries that
                        // are on disk.
                        if (references.Count == 0)
                        {
                            // Search through all of the target frameworks until we find one that
                            // has at least one file in it.
                            foreach (var clrNameOriginal in clrNames)
                            {
                                var clrName  = clrNameOriginal;
                                var foundClr = false;

                                if (clrName[0] == '=')
                                {
                                    // Exact match (strip the equals).
                                    clrName = clrName.Substring(1);

                                    // If this target framework doesn't exist for this library, skip it.
                                    var dirPath = Path.Combine(
                                        referenceBasePath,
                                        clrName);
                                    if (!Directory.Exists(dirPath))
                                    {
                                        continue;
                                    }
                                }
                                else if (clrName[0] == '?')
                                {
                                    // Substring, search the reference base path for any folders
                                    // with a matching substring.
                                    clrName = clrName.Substring(1);

                                    var baseDirPath = referenceBasePath;
                                    var found       = false;
                                    foreach (var subdir in new DirectoryInfo(baseDirPath).GetDirectories())
                                    {
                                        if (subdir.Name.Contains(clrName))
                                        {
                                            clrName = subdir.Name;
                                            found   = true;
                                            break;
                                        }
                                    }

                                    if (!found)
                                    {
                                        continue;
                                    }
                                }
                                else
                                {
                                    throw new InvalidOperationException("Unknown CLR name match type with '" + clrName +
                                                                        "'");
                                }

                                // Otherwise enumerate through all of the libraries in this folder.
                                foreach (var dll in Directory.EnumerateFiles(
                                             Path.Combine(
                                                 referenceBasePath, clrName),
                                             "*.dll"))
                                {
                                    // Determine the relative path to the library.
                                    var packageDll = Path.Combine(
                                        referenceBasePath,
                                        clrName,
                                        Path.GetFileName(dll));

                                    // Confirm again that the file actually exists on disk when
                                    // combined with the root path.
                                    if (File.Exists(
                                            Path.Combine(
                                                packageDll)))
                                    {
                                        // Create the library reference.
                                        if (!libraryReferences.ContainsKey(Path.GetFileNameWithoutExtension(dll)))
                                        {
                                            libraryReferences.Add(
                                                Path.GetFileNameWithoutExtension(dll),
                                                packageDll);
                                        }

                                        // Mark this target framework as having provided at least
                                        // one reference.
                                        foundClr = true;
                                    }
                                }

                                // Break if we have found at least one reference.
                                if (foundClr)
                                {
                                    break;
                                }
                            }
                        }

                        // For all of the references that were found in the original nuspec file,
                        // add those references.
                        foreach (var reference in references)
                        {
                            // Search through all of the target frameworks until we find the one
                            // that has the reference in it.
                            foreach (var clrName in clrNames)
                            {
                                // If this target framework doesn't exist for this library, skip it.
                                var packageDll = Path.Combine(
                                    referenceBasePath,
                                    clrName,
                                    reference);

                                if (File.Exists(
                                        Path.Combine(
                                            packageDll)))
                                {
                                    if (!libraryReferences.ContainsKey(Path.GetFileNameWithoutExtension(packageDll)))
                                    {
                                        libraryReferences.Add(
                                            Path.GetFileNameWithoutExtension(packageDll),
                                            packageDll);
                                    }
                                    break;
                                }
                            }
                        }
                    }
                }

                foreach (var kv in libraryReferences)
                {
                    RedirectableConsole.WriteLine("Found library to reference: " + kv.Key + " (at " + kv.Value + ")");
                }

                RedirectableConsole.WriteLine("Generating external project reference...");
                var document        = new XmlDocument();
                var externalProject = document.CreateElement("ExternalProject");
                externalProject.SetAttribute("Name", packageName);
                document.AppendChild(externalProject);
                foreach (var kv in libraryReferences)
                {
                    var binaryReference = document.CreateElement("Binary");
                    binaryReference.SetAttribute("Name", kv.Key);
                    binaryReference.SetAttribute("Path",
                                                 kv.Value.Substring(folder.Length).TrimStart(new[] { '/', '\\' }).Replace("%2B", "-"));
                    externalProject.AppendChild(binaryReference);
                }
                foreach (var package in packageDependencies)
                {
                    var externalReference = document.CreateElement("Reference");
                    externalReference.SetAttribute("Include", package.Key);
                    externalProject.AppendChild(externalReference);
                }
                Directory.CreateDirectory(Path.Combine(path, "Build", "Projects"));
                document.Save(Path.Combine(path, "Build", "Projects", packageName + ".definition"));

                RedirectableConsole.WriteLine("Generating module...");
                var generatedModule = new ModuleInfo();
                generatedModule.Name     = packageName;
                generatedModule.Packages = new List <PackageRef>();

                foreach (var package in packageDependencies)
                {
                    generatedModule.Packages.Add(new PackageRef
                    {
                        Uri    = "https-nuget-v3://api.nuget.org/v3/index.json|" + package.Key,
                        GitRef = package.Value.TrimStart('[').TrimEnd(']'),
                        Folder = package.Key
                    });
                }

                generatedModule.Save(Path.Combine(path, "Build", "Module.xml"));

                foreach (var kv in libraryReferences)
                {
                    var targetFile =
                        new FileInfo(Path.Combine(path,
                                                  kv.Value.Substring(folder.Length).Replace('\\', '/').TrimStart('/').Replace("%2B", "-")));
                    targetFile.Directory.Create();
                    File.Copy(kv.Value, targetFile.FullName);
                }
            }
            finally
            {
                PathUtils.AggressiveDirectoryDelete(folder);
            }
        }
Example #29
0
        private static void PrintHelp(Dictionary <string, ICommand> commandMappings, bool extendedHelp = false)
        {
            RedirectableConsole.WriteLine("Protobuild v" + ProtobuildVersion.SemanticVersion);
            RedirectableConsole.WriteLine("  built from " + ProtobuildVersion.BuildCommit);
            RedirectableConsole.WriteLine("  built at " + ProtobuildVersion.BuildDate);
            if (ProtobuildVersion.BuiltWithPendingChanges)
            {
                RedirectableConsole.WriteLine("  working directory had pending changes when built!");
            }
            RedirectableConsole.WriteLine();
            RedirectableConsole.WriteLine("Usage: Protobuild.exe [options]");
            RedirectableConsole.WriteLine();
            RedirectableConsole.WriteLine("By default Protobuild resynchronises or generates projects for the current platform, depending on the module configuration.");

            var shortDescs = new List <Tuple <string, string, string> >();

            foreach (var kv in commandMappings)
            {
                if (kv.Value.IsInternal() || !kv.Value.IsRecognised() || kv.Value.IsIgnored())
                {
                    continue;
                }

                if (!extendedHelp)
                {
                    if (kv.Value.GetShortCategory() == "Internal use")
                    {
                        continue;
                    }

                    var shortDescription = kv.Value.GetShortDescription();
                    var argDesc          = string.Empty;
                    foreach (var arg in kv.Value.GetShortArgNames())
                    {
                        if (arg.EndsWith("?"))
                        {
                            argDesc += " [" + arg.TrimEnd('?') + "]";
                        }
                        else
                        {
                            argDesc += " " + arg;
                        }
                    }

                    shortDescs.Add(new Tuple <string, string, string>(kv.Value.GetShortCategory(), "--" + kv.Key + argDesc, shortDescription));
                }
                else
                {
                    var description = kv.Value.GetDescription();
                    description = description.Replace("\n", " ");
                    description = description.Replace("\r", "");

                    var lines      = new List <string>();
                    var wordBuffer = string.Empty;
                    var lineBuffer = string.Empty;
                    var count      = 0;
                    var last       = false;
                    for (var i = 0; i < description.Length || wordBuffer.Length > 0; i++)
                    {
                        if (i < description.Length)
                        {
                            if (description[i] == ' ')
                            {
                                if (wordBuffer.Length > 0)
                                {
                                    lineBuffer += wordBuffer + " ";
                                }

                                wordBuffer = string.Empty;
                            }
                            else
                            {
                                wordBuffer += description[i];
                                count++;
                            }
                        }
                        else
                        {
                            lineBuffer += wordBuffer + " ";
                            count++;
                            last = true;
                        }

                        if (count >= 74)
                        {
                            lines.Add(lineBuffer);
                            lineBuffer = string.Empty;
                            count      = 0;
                        }

                        if (last)
                        {
                            break;
                        }
                    }

                    if (count > 0)
                    {
                        lines.Add(lineBuffer);
                        lineBuffer = string.Empty;
                    }

                    var argDesc = string.Empty;
                    foreach (var arg in kv.Value.GetArgNames())
                    {
                        if (arg.EndsWith("?"))
                        {
                            argDesc += " [" + arg.TrimEnd('?') + "]";
                        }
                        else
                        {
                            argDesc += " " + arg;
                        }
                    }

                    RedirectableConsole.WriteLine("  -" + kv.Key + argDesc);
                    RedirectableConsole.WriteLine();

                    foreach (var line in lines)
                    {
                        RedirectableConsole.WriteLine("  " + line);
                    }

                    RedirectableConsole.WriteLine();
                }
            }

            if (!extendedHelp)
            {
                var bufferWidth = 120;
                try
                {
                    // This won't work if input is redirected or running under Git Bash on Windows.
                    bufferWidth = Console.BufferWidth;
                }
                catch { }

                var maxArgs = shortDescs.Max(x => x.Item2.Length);

                if (bufferWidth - (maxArgs + 6) - 6 <= 43)
                {
                    // Use the format where the description is underneath each command.
                    RedirectableConsole.WriteLine();
                    foreach (var kvg in shortDescs.GroupBy(x => x.Item1))
                    {
                        RedirectableConsole.WriteLine(("____ " + kvg.Key + " ").PadRight(bufferWidth - 4, '_'));
                        RedirectableConsole.WriteLine();

                        foreach (var kv in kvg)
                        {
                            var description = kv.Item3;

                            var lines      = new List <string>();
                            var wordBuffer = string.Empty;
                            var lineBuffer = string.Empty;
                            var last       = false;
                            for (var i = 0; i < description.Length || wordBuffer.Length > 0; i++)
                            {
                                if (i < description.Length)
                                {
                                    if (description[i] == ' ')
                                    {
                                        if (wordBuffer.Length > 0)
                                        {
                                            lineBuffer += wordBuffer + " ";
                                        }

                                        wordBuffer = string.Empty;
                                    }
                                    else
                                    {
                                        wordBuffer += description[i];
                                    }
                                }
                                else
                                {
                                    lineBuffer += wordBuffer + " ";
                                    last        = true;
                                }

                                if (lineBuffer.Length + 1 + wordBuffer.Length >= bufferWidth - 8)
                                {
                                    lines.Add(lineBuffer);
                                    lineBuffer = string.Empty;
                                }

                                if (last)
                                {
                                    break;
                                }
                            }

                            if (lineBuffer.Length > 0)
                            {
                                lines.Add(lineBuffer);
                                lineBuffer = string.Empty;
                            }

                            RedirectableConsole.WriteLine("  " + kv.Item2.PadRight(maxArgs + 4));
                            RedirectableConsole.WriteLine();
                            for (var i = 0; i < lines.Count; i++)
                            {
                                RedirectableConsole.WriteLine("    " + lines[i]);
                            }
                            RedirectableConsole.WriteLine();
                            RedirectableConsole.WriteLine();
                        }
                    }
                }
                else
                {
                    // Use the format where the description is side-by-side with each command.
                    foreach (var kvg in shortDescs.GroupBy(x => x.Item1))
                    {
                        RedirectableConsole.WriteLine();
                        RedirectableConsole.WriteLine(kvg.Key + ":");

                        foreach (var kv in kvg)
                        {
                            var description = kv.Item3;

                            var lines      = new List <string>();
                            var wordBuffer = string.Empty;
                            var lineBuffer = string.Empty;
                            var last       = false;
                            for (var i = 0; i < description.Length || wordBuffer.Length > 0; i++)
                            {
                                if (i < description.Length)
                                {
                                    if (description[i] == ' ')
                                    {
                                        if (wordBuffer.Length > 0)
                                        {
                                            lineBuffer += wordBuffer + " ";
                                        }

                                        wordBuffer = string.Empty;
                                    }
                                    else
                                    {
                                        wordBuffer += description[i];
                                    }
                                }
                                else
                                {
                                    lineBuffer += wordBuffer + " ";
                                    last        = true;
                                }

                                if (lineBuffer.Length + 1 + wordBuffer.Length >= bufferWidth - (maxArgs + 6) - 6)
                                {
                                    lines.Add(lineBuffer);
                                    lineBuffer = string.Empty;
                                }

                                if (last)
                                {
                                    break;
                                }
                            }

                            if (lineBuffer.Length > 0)
                            {
                                lines.Add(lineBuffer);
                                lineBuffer = string.Empty;
                            }

                            RedirectableConsole.WriteLine("  " + kv.Item2.PadRight(maxArgs + 4) + (lines.Count > 0 ? lines[0] : ""));
                            for (var i = 1; i < lines.Count; i++)
                            {
                                RedirectableConsole.WriteLine("    " + "".PadRight(maxArgs + 4) + lines[i]);
                            }
                        }
                    }
                }
            }
        }
        public void GenerateInfoPListIfNeeded(List <LoadedDefinitionInfo> definitions, DefinitionInfo definition, XmlDocument project, string platform)
        {
            if (platform == "iOS" || platform == "MacOS")
            {
                var documentsByName = definitions.ToDictionarySafe(
                    k => k.Definition.Name,
                    v => v,
                    (dict, x) =>
                {
                    var existing = dict[x.Definition.Name];
                    var tried    = x;

                    RedirectableConsole.WriteLine("WARNING: There is more than one project with the name " +
                                                  x.Definition.Name + " (first project loaded from " + tried.Definition.AbsolutePath + ", " +
                                                  "skipped loading second project from " + existing.Definition.AbsolutePath + ")");
                })
                                      .ToDictionary(k => k.Key, v => v.Value.Project);

                var type = project.DocumentElement.GetAttribute("Type");
                if (type == "Console" || type == "App")
                {
                    var references      = project.DocumentElement.SelectNodes("References/*").OfType <XmlElement>();
                    var referencesArray = references.Select(x => x.GetAttribute("Include")).ToArray();
                    foreach (var reference in references)
                    {
                        var lookup = definitions.FirstOrDefault(x => x.Definition.Name == reference.GetAttribute("Include"));
                        if (lookup != null)
                        {
                            if (lookup.Definition.Type == "Include")
                            {
                                if (project.DocumentElement.SelectSingleNode("Files/*[@Include='Info.plist']") == null)
                                {
                                    return;
                                }
                            }
                            else if (lookup.Definition.Type == "External")
                            {
                                var referencedDocument = documentsByName[lookup.Definition.Name];

                                if (referencedDocument.DocumentElement.LocalName == "ExternalProject")
                                {
                                    // Find all top-level references in the external project.
                                    var externalDocumentReferences = referencedDocument.SelectNodes("/ExternalProject/Reference").OfType <XmlElement>().Concat(
                                        referencedDocument.SelectNodes("/ExternalProject/Platform[@Type='" + platform + "']/Reference").OfType <XmlElement>()).ToList();
                                    foreach (var externalReference in externalDocumentReferences)
                                    {
                                        lookup = definitions.FirstOrDefault(x => x.Definition.Name == externalReference.GetAttribute("Include"));
                                        if (lookup != null)
                                        {
                                            if (lookup.Definition.Type == "Include")
                                            {
                                                if (project.DocumentElement.SelectSingleNode("Files/*[@Include='Info.plist']") == null)
                                                {
                                                    return;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    if (project.DocumentElement.SelectSingleNode("Files/*[@Include='Info.plist']") == null)
                    {
                        // We need to generate an Info.plist file for iOS and Mac; we do this
                        // just with a default Info.plist file which is enough for projects
                        // to compile.
                        var infoPListPath = Path.Combine(definition.AbsolutePath, "Info.plist").Replace(Path.DirectorySeparatorChar == '/' ? '\\' : '/', Path.DirectorySeparatorChar);
                        if (!File.Exists(infoPListPath))
                        {
                            var contents = @"
<?xml version=""1.0"" encoding=""UTF-8""?>
<!DOCTYPE plist PUBLIC ""-//Apple//DTD PLIST 1.0//EN"" ""http://www.apple.com/DTDs/PropertyList-1.0.dtd"">
<plist version=""1.0"">
<dict>
	<key>CFBundleDisplayName</key>
	<string></string>
	<key>CFBundleIdentifier</key>
	<string></string>
	<key>MinimumOSVersion</key>
	<string>10.2</string>
	<key>UIDeviceFamily</key>
	<array>
		<integer>1</integer>
	</array>
	<key>CFBundleShortVersionString</key>
	<string></string>
	<key>CFBundleVersion</key>
	<string></string>
	<key>UISupportedInterfaceOrientations</key>
	<array/>
</dict>
</plist>
".Trim();
                            using (var writer = new StreamWriter(infoPListPath))
                            {
                                writer.Write(contents);
                            }
                        }

                        var files     = project.DocumentElement.SelectSingleNode("Files");
                        var infoPList = project.CreateElement("None");
                        infoPList.SetAttribute("Include", "Info.plist");
                        var platforms = project.CreateElement("Platforms");
                        platforms.InnerText = "iOS,MacOS";
                        infoPList.AppendChild(platforms);
                        files.AppendChild(infoPList);
                    }
                }
            }
            else if (platform == "Android" || platform == "Ouya")
            {
                var type  = project.DocumentElement.GetAttribute("Type");
                var files = project.DocumentElement.SelectSingleNode("Files");

                Directory.CreateDirectory(
                    Path.Combine(definition.AbsolutePath, "Resources")
                    .Replace(Path.DirectorySeparatorChar == '/' ? '\\' : '/', Path.DirectorySeparatorChar));

                if (type == "Console" || type == "App")
                {
                    Directory.CreateDirectory(
                        Path.Combine(definition.AbsolutePath, "Properties")
                        .Replace(Path.DirectorySeparatorChar == '/' ? '\\' : '/', Path.DirectorySeparatorChar));

                    // We need to generate an AndroidManifest.xml file; we do this just with
                    // a default AndroidManifest file which is enough for projects to compile.
                    var manifestPath =
                        Path.Combine(definition.AbsolutePath, "Properties\\AndroidManifest.xml")
                        .Replace(Path.DirectorySeparatorChar == '/' ? '\\' : '/', Path.DirectorySeparatorChar);
                    if (!File.Exists(manifestPath))
                    {
                        var contents = (@"
<?xml version=""1.0"" encoding=""utf-8""?>
<manifest xmlns:android=""http://schemas.android.com/apk/res/android"" package=""" + definition.Name +
                                        @""" android:versionCode=""1"" android:versionName=""1.0"">
    <uses-sdk />
	<application android:label="""     + definition.Name + @"""></application>
</manifest>
").Trim();
                        using (var writer = new StreamWriter(manifestPath))
                        {
                            writer.Write(contents);
                        }
                    }

                    if (files != null)
                    {
                        var manifestNode =
                            project.DocumentElement.SelectSingleNode(
                                "Files/*[@Include='Properties\\AndroidManifest.xml']");
                        if (manifestNode != null && manifestNode.Name != "Content" && manifestNode.ParentNode != null)
                        {
                            manifestNode.ParentNode.RemoveChild(manifestNode);
                            manifestNode = null;
                        }
                        if (manifestNode == null)
                        {
                            var manifest = project.CreateElement("Content");
                            manifest.SetAttribute("Include", "Properties\\AndroidManifest.xml");
                            var platforms = project.CreateElement("Platforms");
                            platforms.InnerText = "Android,Ouya";
                            manifest.AppendChild(platforms);
                            files.AppendChild(manifest);
                        }
                    }
                }

                // We need to generate an empty Resources\Resource.Designer.cs file; we do this just with
                // a default Resource.Designer.cs file which is enough for projects to compile.
                var resourcePath = Path.Combine(definition.AbsolutePath, "Resources\\Resource.Designer.cs").Replace(Path.DirectorySeparatorChar == '/' ? '\\' : '/', Path.DirectorySeparatorChar);
                if (!File.Exists(resourcePath))
                {
                    var contents = string.Empty;
                    using (var writer = new StreamWriter(resourcePath))
                    {
                        writer.Write(contents);
                    }
                }

                if (files != null)
                {
                    var resourceNode =
                        project.DocumentElement.SelectSingleNode(
                            "Files/*[@Include='Resources\\Resource.Designer.cs']");
                    if (resourceNode != null && resourceNode.Name != "Compile" && resourceNode.ParentNode != null)
                    {
                        resourceNode.ParentNode.RemoveChild(resourceNode);
                        resourceNode = null;
                    }
                    if (resourceNode == null)
                    {
                        var resource = project.CreateElement("Compile");
                        resource.SetAttribute("Include", "Resources\\Resource.Designer.cs");
                        var platforms = project.CreateElement("Platforms");
                        platforms.InnerText = "Android,Ouya";
                        resource.AppendChild(platforms);
                        files.AppendChild(resource);
                    }
                }
            }
        }