public XmlDocument GenerateForSelectSolution(List <XmlDocument> definitions, string platform, 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, null, services)); var generation = doc.CreateElement("Generation"); var platformName = doc.CreateElement("Platform"); platformName.AppendChild(doc.CreateTextNode(platform)); var hostPlatformName = doc.CreateElement("HostPlatform"); hostPlatformName.AppendChild(doc.CreateTextNode(_hostPlatformDetector.DetectPlatform())); generation.AppendChild(platformName); generation.AppendChild(hostPlatformName); input.AppendChild(generation); 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 projects = doc.CreateElement("Projects"); input.AppendChild(projects); foreach (var projectDoc in definitions) { if (this.m_ExcludedServiceAwareProjectDetector.IsExcludedServiceAwareProject( projectDoc.DocumentElement.GetAttribute("Name"), projectDoc, services)) { continue; } projects.AppendChild(doc.ImportNode( projectDoc.DocumentElement, true)); } return(doc); }
public int Execute(Execution execution) { var module = ModuleInfo.Load(Path.Combine(execution.WorkingDirectory, "Build", "Module.xml")); if (module.Packages == null) { throw new InvalidOperationException("No such package has been added"); } var package = _packageUrlParser.Parse(execution.PackageUrl); var packageRef = _packageNameLookup.LookupPackageByName(module, package.Uri); _packageManager.Resolve( execution.WorkingDirectory, module, packageRef, execution.Platform ?? _hostPlatformDetector.DetectPlatform(), null, null, true, execution.SafePackageResolution); return(0); }
public int Execute(Execution execution) { var module = ModuleInfo.Load(Path.Combine(execution.WorkingDirectory, "Build", "Module.xml")); if (module.Packages == null) { return(0); } var platform = execution.Platform ?? _hostPlatformDetector.DetectPlatform(); foreach (var package in module.Packages) { _packageManager.Resolve( execution.WorkingDirectory, module, package, platform, null, null, true, execution.SafePackageResolution); } return(0); }
public int Execute(Execution execution) { var url = execution.PackageUrl; var module = ModuleInfo.Load(Path.Combine("Build", "Module.xml")); if (module.Packages == null) { throw new InvalidOperationException("No such package has been added"); } var branch = "master"; if (url.LastIndexOf('@') > url.LastIndexOf('/')) { // A branch / commit ref is specified. branch = url.Substring(url.LastIndexOf('@') + 1); url = url.Substring(0, url.LastIndexOf('@')); } var packageRef = _packageNameLookup.LookupPackageByName(module, url); _packageManager.Resolve( module, packageRef, execution.Platform ?? _hostPlatformDetector.DetectPlatform(), null, null, true); return(0); }
public void ScanPackageForToolsAndInstall(string toolFolder) { 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); } Console.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); } } } }
public string GetFileSuffix(Language language) { switch (language) { case Language.CSharp: return("CSharp"); case Language.CPlusPlus: if (_hostPlatformDetector.DetectPlatform() == "Windows") { return("CPlusPlus.VisualStudio"); } else { return("CPlusPlus.MonoDevelop"); } default: throw new NotSupportedException(); } }
public string GetToolExecutablePath(string toolName) { var executableFile = _packageGlobalTool.ResolveGlobalToolIfPresent(toolName); if (executableFile == null && _knownTools.ContainsKey(toolName.ToLowerInvariant())) { var package = new PackageRef { Uri = _knownTools[toolName.ToLowerInvariant()], GitRef = "master", Folder = null }; RedirectableConsole.WriteLine("Installing {0}...", _knownTools[toolName.ToLowerInvariant()]); _packageManager.Resolve(Environment.CurrentDirectory, null, package, _hostPlatformDetector.DetectPlatform(), null, false, true, false); } else { return(executableFile); } return(_packageGlobalTool.ResolveGlobalToolIfPresent(toolName)); }
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 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."); }
/// <summary> /// Generates a project at the target path. /// </summary> /// <param name="current">The current project to generate.</param> /// <param name="definitions">A list of all loaded project definitions.</param> /// <param name="workingDirectory"></param> /// <param name="rootPath">The module root path, with directory seperator appended.</param> /// <param name="projectName">The project name.</param> /// <param name="platformName">The platform name.</param> /// <param name="services">A list of services.</param> /// <param name="packagesFilePath"> /// Either the full path to the packages.config for the /// generated project if it exists, or an empty string. /// </param> /// <param name="onActualGeneration"></param> /// <param name="debugProjectGeneration">Whether to emit a .input file for XSLT debugging.</param> public void Generate( DefinitionInfo current, List <LoadedDefinitionInfo> definitions, string workingDirectory, string rootPath, string projectName, string platformName, List <Service> services, out string packagesFilePath, Action onActualGeneration, bool debugProjectGeneration) { packagesFilePath = string.Empty; // Work out what document this is. var projectDoc = definitions.First( x => x.Project.DocumentElement.Attributes["Name"].Value == projectName)?.Project; // Check to see if we have a Project node; don't process it. if (projectDoc?.DocumentElement == null) { return; } // If this is a custom project, run any custom generation commands for // the current host and target platform. if (projectDoc.DocumentElement.Name == "CustomProject") { onActualGeneration(); var onGenerateElements = projectDoc.DocumentElement.SelectNodes("OnGenerate"); if (onGenerateElements != null) { foreach (var onGenerateElement in onGenerateElements.OfType <XmlElement>()) { var matches = true; var hostName = onGenerateElement.GetAttribute("HostName"); var targetName = onGenerateElement.GetAttribute("TargetName"); if (!string.IsNullOrWhiteSpace(hostName)) { if (hostName != _hostPlatformDetector.DetectPlatform()) { matches = false; } } if (!string.IsNullOrWhiteSpace(targetName)) { if (targetName != platformName) { matches = false; } } if (matches) { var command = onGenerateElement.SelectSingleNode("Command")?.InnerText.Trim(); var arguments = onGenerateElement.SelectSingleNode("Arguments")?.InnerText.Trim() ?? string.Empty; if (!string.IsNullOrWhiteSpace(command)) { var workingPath = Path.Combine( rootPath, projectDoc.DocumentElement.Attributes["Path"].Value); var resolvedCommandPath = Path.Combine( workingPath, command); if (File.Exists(resolvedCommandPath)) { var process = Process.Start(new ProcessStartInfo(resolvedCommandPath, arguments) { WorkingDirectory = workingPath, UseShellExecute = false }); if (process == null) { RedirectableConsole.ErrorWriteLine("ERROR: Process did not start when running " + resolvedCommandPath + " " + arguments); ExecEnvironment.Exit(1); return; } process.WaitForExit(); if (process.ExitCode != 0) { RedirectableConsole.ErrorWriteLine( "ERROR: Non-zero exit code " + process.ExitCode); ExecEnvironment.Exit(1); return; } } } } } } } // If this is not a normal project at this point, don't process it. if (projectDoc.DocumentElement.Name != "Project") { return; } // Load the appropriate project transformation XSLT. var languageAttribute = projectDoc.DocumentElement.Attributes["Language"]; var languageText = languageAttribute != null ? languageAttribute.Value : "C#"; var language = this.m_LanguageStringProvider.GetLanguageFromConfigurationName(languageText); var projectTransform = this.m_ResourceProvider.LoadXSLT(workingDirectory, ResourceType.GenerateProject, language, platformName); // Work out what platforms this project should be generated for. var platformAttribute = projectDoc.DocumentElement.Attributes["Platforms"]; string[] allowedPlatforms = null; if (platformAttribute != null) { allowedPlatforms = platformAttribute.Value .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .Select(x => x.Trim()) .ToArray(); } // Filter on allowed platforms. if (allowedPlatforms != null) { var allowed = false; foreach (var platform in allowedPlatforms) { if (string.Compare(platformName, platform, StringComparison.InvariantCultureIgnoreCase) == 0) { allowed = true; break; } } if (!allowed) { return; } } // If the project has a <Services> node, but there are no entries in /Input/Services, // then nothing depends on this service (if there is a <Reference> to this project, it will // use the default service). So for service-aware projects without any services being // referenced, we exclude them from the generation. if (this.m_ExcludedServiceAwareProjectDetector.IsExcludedServiceAwareProject( projectDoc.DocumentElement.Attributes["Name"].Value, projectDoc, services)) { return; } // Inform the user we're generating this project. onActualGeneration(); // Add include projects if they have an AppliesTo tag that matches this project's name. this._includeProjectAppliesToUpdater.UpdateProjectReferences(definitions.Select(x => x.Project).ToList(), projectDoc); // Add references and properties from include projects. _includeProjectMerger.MergeInReferencesAndPropertiesForIncludeProjects(definitions, projectDoc, platformName); // Imply external project references from other external projects. We do // this so that external projects can reference other external projects (which // we can't reasonably handle at the XSLT level since it's recursive). this.m_ExternalProjectReferenceResolver.ResolveExternalProjectReferences(definitions, projectDoc, platformName); // Generate Info.plist files if necessary (for Mac / iOS). this._mPlatformResourcesGenerator.GenerateInfoPListIfNeeded(definitions, current, projectDoc, platformName); // Work out what path to save at. var path = Path.Combine( rootPath, projectDoc.DocumentElement.Attributes["Path"].Value .Replace('\\', Path.DirectorySeparatorChar) .Replace('/', Path.DirectorySeparatorChar), projectDoc.DocumentElement.Attributes["Name"].Value + "." + platformName + "." + this.m_LanguageStringProvider.GetProjectExtension(language)); // Make sure that the directory exists where the file will be stored. var targetFile = new FileInfo(path); if (!targetFile.Directory.Exists) { targetFile.Directory.Create(); } path = targetFile.FullName; // Handle NuGet packages.config early so that it'll be in place // when the generator automatically determined dependencies. this.m_NuGetConfigMover.Move(rootPath, platformName, projectDoc); // Work out what path the NuGet packages.config might be at. var packagesFile = new FileInfo( Path.Combine( rootPath, projectDoc.DocumentElement.Attributes["Path"].Value .Replace('\\', Path.DirectorySeparatorChar) .Replace('/', Path.DirectorySeparatorChar), "packages.config")); // Generate the input document. var input = this.m_ProjectInputGenerator.Generate( definitions.Select(x => x.Project).ToList(), workingDirectory, rootPath, projectName, platformName, packagesFile.FullName, projectDoc.DocumentElement.ChildNodes .OfType <XmlElement>() .Where(x => x.Name.ToLower() == "properties") .SelectMany(x => x.ChildNodes .OfType <XmlElement>()), services); var settings = new XmlWriterSettings(); settings.Indent = true; if (debugProjectGeneration) { using (var writer = XmlWriter.Create(path + ".input", settings)) { input.Save(writer); } } // Transform the input document using the XSLT transform. using (var writer = XmlWriter.Create(path, settings)) { projectTransform.Transform(input, writer); } // Also remove any left over .sln or .userprefs files. var slnPath = Path.Combine( rootPath, projectDoc.DocumentElement.Attributes["Path"].Value, projectDoc.DocumentElement.Attributes["Name"].Value + "." + platformName + ".sln"); var userprefsPath = Path.Combine( rootPath, projectDoc.DocumentElement.Attributes["Path"].Value, projectDoc.DocumentElement.Attributes["Name"].Value + "." + platformName + ".userprefs"); if (File.Exists(slnPath)) { File.Delete(slnPath); } if (File.Exists(userprefsPath)) { File.Delete(userprefsPath); } // Only return the package file path if it exists. if (packagesFile.Exists) { packagesFilePath = packagesFile.FullName; } }
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); }
public int Execute(Execution execution) { var assemblyPath = Assembly.GetEntryAssembly().Location; var fileInfo = new FileInfo(assemblyPath); var modulePath = fileInfo.DirectoryName; if (modulePath == null) { Console.WriteLine( "Unable to determine the location of Protobuild."); return(1); } if (!File.Exists(Path.Combine(modulePath, "Build", "Module.xml"))) { modulePath = _workingDirectoryProvider.GetPath(); } string executablePath = null; if (!File.Exists(Path.Combine(modulePath, "Build", "Module.xml"))) { // We can only run global tools. var globalToolPath = this.m_PackageGlobalTool.ResolveGlobalToolIfPresent(execution.ExecuteProjectName); if (globalToolPath == null) { Console.WriteLine( "There is no global tool registered as '" + execution.ExecuteProjectName + "'"); return(1); } else { executablePath = globalToolPath; } } else { var platform = this.m_HostPlatformDetector.DetectPlatform(); var module = ModuleInfo.Load(Path.Combine(modulePath, "Build", "Module.xml")); var definitions = module.GetDefinitionsRecursively(platform).ToList(); var target = definitions.FirstOrDefault(x => x.Name == execution.ExecuteProjectName); if (target == null) { // Check to see if there is any external project definition that provides the tool. foreach (var definition in definitions) { var document = XDocument.Load(definition.DefinitionPath); if (document.Root.Name.LocalName == "ExternalProject") { foreach (var node in document.Root.Elements().Where(x => x.Name.LocalName == "Tool")) { var name = node.Attribute(XName.Get("Name")).Value; var path = node.Attribute(XName.Get("Path")).Value; if (name == execution.ExecuteProjectName) { executablePath = Path.Combine(definition.ModulePath, path.Replace('\\', Path.DirectorySeparatorChar).Replace('/', Path.DirectorySeparatorChar)); break; } } } } if (executablePath == null) { var globalToolPath = this.m_PackageGlobalTool.ResolveGlobalToolIfPresent(execution.ExecuteProjectName); if (globalToolPath == null) { Console.WriteLine( "There is no project definition with name '" + execution.ExecuteProjectName + "'"); return(1); } else { executablePath = globalToolPath; } } } else { var document = XDocument.Load(target.DefinitionPath); if (document.Root.Name.LocalName == "Project") { var assemblyName = this.m_ProjectOutputPathCalculator.GetProjectAssemblyName(platform, target, document); var prefixPath = this.m_ProjectOutputPathCalculator.GetProjectOutputPathPrefix(platform, target, document, false); var directory = new DirectoryInfo(Path.Combine(modulePath, prefixPath)); var subdirectories = directory.GetDirectories(); var preferredName = (execution.ExecuteProjectConfiguration ?? "Debug").ToLowerInvariant(); var preferredDirectory = subdirectories.FirstOrDefault(x => x.Name.ToLowerInvariant() == preferredName); if (preferredDirectory != null && File.Exists(Path.Combine(preferredDirectory.FullName, assemblyName + ".exe"))) { executablePath = Path.Combine(preferredDirectory.FullName, assemblyName + ".exe"); } else { string tempPath = null; foreach (var subdirectory in subdirectories) { tempPath = Path.Combine(subdirectory.FullName, assemblyName + ".exe"); if (File.Exists(tempPath)) { break; } } if (tempPath != null && File.Exists(tempPath)) { executablePath = tempPath; } } } else if (document.Root.Name.LocalName == "ExternalProject") { foreach (var node in document.Root.Elements().Where(x => x.Name.LocalName == "Tool")) { var name = node.Attribute(XName.Get("Name")).Value; var path = node.Attribute(XName.Get("Path")).Value; if (name == execution.ExecuteProjectName) { executablePath = Path.Combine(target.ModulePath, path.Replace('\\', Path.DirectorySeparatorChar).Replace('/', Path.DirectorySeparatorChar)); break; } } } if (executablePath == null) { var globalToolPath = this.m_PackageGlobalTool.ResolveGlobalToolIfPresent(execution.ExecuteProjectName); if (globalToolPath == null) { Console.WriteLine( "There is no output path for '" + execution.ExecuteProjectName + "'; has the project been built?"); return(1); } else { executablePath = globalToolPath; } } } } if (!File.Exists(executablePath)) { Console.WriteLine( "There is no executable for '" + execution.ExecuteProjectName + "'; has the project been built?"); return(1); } var arguments = string.Empty; if (execution.ExecuteProjectArguments.Length > 0) { arguments = execution.ExecuteProjectArguments .Select(x => "\"" + x.Replace("\"", "\\\"") + "\"") .Aggregate((a, b) => a + " " + b); } ProcessStartInfo startInfo; if (Path.DirectorySeparatorChar == '/') { var mono = "mono"; if (m_HostPlatformDetector.DetectPlatform() == "MacOS" && File.Exists("/usr/local/bin/mono")) { // After upgrading to OSX El Capitan, the /usr/local/bin folder is no longer in // the system PATH. If we can't find Mono with the which tool, manually set the // path here in an attempt to find it. mono = "/usr/local/bin/mono"; } startInfo = new ProcessStartInfo( mono, "--debug \"" + executablePath + "\" " + arguments); } else { startInfo = new ProcessStartInfo( executablePath, arguments); } startInfo.UseShellExecute = false; var process = Process.Start(startInfo); process.WaitForExit(); return(process.ExitCode); }
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; } Console.Error.WriteLine( "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; } Console.Error.WriteLine( "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 "; } 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) { Console.Error.WriteLine("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": Console.WriteLine("INFO: Using " + builderPath32 + " (forced 32-bit) to perform this build."); break; case "x64": Console.WriteLine("INFO: Using " + builderPath64 + " (forced 64-bit) to perform this build."); break; case "Default": default: Console.WriteLine("INFO: Using " + builderPathNativeArch + " (32-bit: " + builderPath32 + ") to perform this build."); break; } var targetPlatforms = (execution.Platform ?? hostPlatform).Split(','); var module = ModuleInfo.Load(Path.Combine("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"; Console.WriteLine("INFO: Executing " + builderPath + " with arguments: " + extraArgs + fileToBuild); var process = Process.Start(new ProcessStartInfo(builderPath, extraArgs + fileToBuild) { UseShellExecute = false }); if (process == null) { Console.Error.WriteLine("ERROR: Build process did not start successfully."); return(1); } process.WaitForExit(); if (process.ExitCode != 0) { return(process.ExitCode); } } return(0); }
public override bool Execute() { if (string.Compare(Platform, "Web", StringComparison.InvariantCultureIgnoreCase) == 0) { // Trigger JSIL provider download if needed. string jsilDirectory, jsilCompilerFile; if (!m_JSILProvider.GetJSIL(out jsilDirectory, out jsilCompilerFile)) { return(false); } } var module = ModuleInfo.Load(Path.Combine(RootPath, "Build", "Module.xml")); LogMessage( "Starting generation of projects for " + Platform); var definitions = module.GetDefinitionsRecursively(Platform).ToArray(); var loadedProjects = new List <LoadedDefinitionInfo>(); if (_hostPlatformDetector.DetectPlatform() == "Windows") { var concurrentProjects = new ConcurrentBag <LoadedDefinitionInfo>(); Parallel.ForEach(definitions, definition => { LogMessage("Loading: " + definition.Name); concurrentProjects.Add( m_ProjectLoader.Load( Platform, module, definition)); }); // Do this so we maintain order with the original definitions list. foreach (var definition in definitions) { var loadedProject = concurrentProjects.FirstOrDefault(x => x.Definition == definition); if (loadedProject != null) { loadedProjects.Add(loadedProject); } } } else { foreach (var definition in definitions) { LogMessage("Loading: " + definition.Name); loadedProjects.Add( m_ProjectLoader.Load( Platform, module, definition)); } } var serviceManager = new ServiceManager(Platform); List <Service> services; TemporaryServiceSpec serviceSpecPath; if (ServiceSpecPath == null) { serviceManager.SetRootDefinitions(module.GetDefinitions()); if (EnableServices == null) { EnableServices = new string[0]; } if (DisableServices == null) { DisableServices = new string[0]; } foreach (var service in EnableServices) { serviceManager.EnableService(service); } foreach (var service in DisableServices) { serviceManager.DisableService(service); } if (DebugServiceResolution) { serviceManager.EnableDebugInformation(); } try { services = serviceManager.CalculateDependencyGraph(loadedProjects.Select(x => x.Project).ToList()); } catch (InvalidOperationException ex) { RedirectableConsole.WriteLine("Error during service resolution: " + ex.Message); return(false); } serviceSpecPath = serviceManager.SaveServiceSpec(services); foreach (var service in services) { if (service.ServiceName != null) { LogMessage("Enabled service: " + service.FullName); } } } else { services = serviceManager.LoadServiceSpec(ServiceSpecPath); serviceSpecPath = new TemporaryServiceSpec(ServiceSpecPath, true); } using (serviceSpecPath) { var submodulesToProcess = new List <ModuleInfo>(); var allSubmodules = module.GetSubmodules(Platform); if (_hostPlatformDetector.DetectPlatform() == "Windows") { var concurrentSubmodulesToProcess = new ConcurrentBag <ModuleInfo>(); Parallel.ForEach(allSubmodules, submodule => { if (_featureManager.IsFeatureEnabledInSubmodule(module, submodule, Feature.OptimizationSkipInvocationOnNoStandardProjects)) { if (submodule.GetDefinitionsRecursively(Platform).All(x => !x.IsStandardProject)) { // Do not invoke this submodule. LogMessage( "Skipping submodule generation for " + submodule.Name + " (there are no projects to generate)"); } else { concurrentSubmodulesToProcess.Add(submodule); } } }); // Do this so we maintain order with the original GetSubmodules list. foreach (var submodule in allSubmodules) { if (concurrentSubmodulesToProcess.Contains(submodule)) { submodulesToProcess.Add(submodule); } } } else { foreach (var submodule in module.GetSubmodules(Platform)) { if (_featureManager.IsFeatureEnabledInSubmodule(module, submodule, Feature.OptimizationSkipInvocationOnNoStandardProjects)) { if (submodule.GetDefinitionsRecursively(Platform).All(x => !x.IsStandardProject)) { // Do not invoke this submodule. LogMessage( "Skipping submodule generation for " + submodule.Name + " (there are no projects to generate)"); } else { submodulesToProcess.Add(submodule); } } } } // Run Protobuild in batch mode in each of the submodules // where it is present. foreach (var submodule in submodulesToProcess) { LogMessage( "Invoking submodule generation for " + submodule.Name); var noResolve = _featureManager.IsFeatureEnabledInSubmodule(module, submodule, Feature.PackageManagementNoResolve) ? " -no-resolve" : string.Empty; var noHostPlatform = DisableHostPlatformGeneration && _featureManager.IsFeatureEnabledInSubmodule(module, submodule, Feature.NoHostGenerate) ? " -no-host-generate" : string.Empty; _moduleExecution.RunProtobuild( submodule, _featureManager.GetFeatureArgumentToPassToSubmodule(module, submodule) + "-generate " + Platform + " -spec " + serviceSpecPath + " " + m_PackageRedirector.GetRedirectionArguments() + noResolve + noHostPlatform); LogMessage( "Finished submodule generation for " + submodule.Name); } var repositoryPaths = new List <string>(); if (_hostPlatformDetector.DetectPlatform() == "Windows") { var concurrentRepositoryPaths = new ConcurrentBag <string>(); Parallel.ForEach(definitions.Where(x => x.ModulePath == module.Path), definition => { if (definition.PostBuildHook && RequiresHostPlatform != null) { // We require the host platform projects at this point. RequiresHostPlatform(); } string repositoryPath; var definitionCopy = definition; m_ProjectGenerator.Generate( definition, loadedProjects, WorkingDirectory, RootPath, definition.Name, Platform, services, out repositoryPath, () => LogMessage("Generating: " + definitionCopy.Name), DebugProjectGeneration); // Only add repository paths if they should be generated. if (module.GenerateNuGetRepositories && !string.IsNullOrEmpty(repositoryPath)) { concurrentRepositoryPaths.Add(repositoryPath); } }); repositoryPaths = concurrentRepositoryPaths.ToList(); } else { foreach (var definition in definitions.Where(x => x.ModulePath == module.Path)) { if (definition.PostBuildHook && RequiresHostPlatform != null) { // We require the host platform projects at this point. RequiresHostPlatform(); } string repositoryPath; var definitionCopy = definition; m_ProjectGenerator.Generate( definition, loadedProjects, WorkingDirectory, RootPath, definition.Name, Platform, services, out repositoryPath, () => LogMessage("Generating: " + definitionCopy.Name), DebugProjectGeneration); // Only add repository paths if they should be generated. if (module.GenerateNuGetRepositories && !string.IsNullOrEmpty(repositoryPath)) { repositoryPaths.Add(repositoryPath); } } } var solution = Path.Combine( RootPath, ModuleName + "." + Platform + ".sln"); LogMessage("Generating: (solution)"); m_SolutionGenerator.Generate( WorkingDirectory, module, loadedProjects.Select(x => x.Project).ToList(), Platform, solution, services, repositoryPaths, DebugProjectGeneration); // Only save the specification cache if we allow synchronisation if (module.DisableSynchronisation == null || !module.DisableSynchronisation.Value) { var serviceCache = Path.Combine(RootPath, ModuleName + "." + Platform + ".speccache"); LogMessage("Saving service specification"); File.Copy(serviceSpecPath.Path, serviceCache, true); } LogMessage( "Generation complete."); } return(true); }
public IPackageMetadata ResolveSource(string workingDirectory, PackageRequestRef request) { var components = request.Uri.Split(new[] { '|' }, 2); var repository = NormalizeScheme(components[0]); var packageName = components[1]; var version = request.GitRef; var semVerRegex = new Regex("^[0-9]\\.[0-9]\\.[0-9](\\-.*)?$"); var gitHashRegex = new Regex("^[0-9a-fA-F]{40}$"); var shouldQuerySourceRepository = false; if (semVerRegex.IsMatch(version)) { // This is a semantic version; leave as-is. } else if (gitHashRegex.IsMatch(version)) { // This is a Git hash, convert it to NuGet's semantic version. version = NuGetVersionHelper.CreateNuGetPackageVersion(version, request.Platform); } else { // This is a branch, or other kind of source reference. We need // to query the source repository to resolve it to a Git hash. shouldQuerySourceRepository = true; } string serviceJson; var serviceIndex = _packageRequestCache.TryGetOptionallyCachedJsonObject( repository, !request.ForceUpgrade, out serviceJson, id => GetData(new Uri(id))); string registrationsBaseUrl = null; foreach (var entry in serviceIndex.resources) { var entryType = (string)entry["@type"]; if (entryType == "RegistrationsBaseUrl") { registrationsBaseUrl = (string)entry["@id"]; } } if (registrationsBaseUrl == null) { throw new InvalidOperationException("Unable to locate RegistrationsBaseUrl service."); } var packageMetadataUrl = $"{registrationsBaseUrl.TrimEnd(new[] {'/'})}/{packageName.ToLowerInvariant()}/index.json"; string packageMetadataJson; var packageMetadata = _packageRequestCache.TryGetOptionallyCachedJsonObject( packageMetadataUrl, !request.ForceUpgrade && request.IsStaticReference, out packageMetadataJson, id => GetData(new Uri(id))); string latestPackageVersion = null; foreach (var item in packageMetadata.items) { if (latestPackageVersion == null || string.CompareOrdinal((string)item.upper, latestPackageVersion) > 0) { latestPackageVersion = item.upper; } } var packagesByVersionLock = new object(); var packagesByVersion = new Dictionary <string, dynamic>(); if (_hostPlatformDetector.DetectPlatform() == "Windows") { // Do this in parallel as we may need to make multiple HTTPS requests. Parallel.ForEach((IEnumerable <object>)packageMetadata.items, item => PopulatePackagesByVersion(packagesByVersionLock, packagesByVersion, (dynamic)item, request)); } else { // Parallelisation is not safe on this platform, do it sequentually. foreach (var item in packageMetadata.items) { PopulatePackagesByVersion(packagesByVersionLock, packagesByVersion, item, request); } } string packageType = PackageManager.PACKAGE_TYPE_LIBRARY; string sourceCodeUrl = null; string commitHashForSourceResolve = null; if (shouldQuerySourceRepository) { var lookupVersion = latestPackageVersion; if (!packagesByVersion.ContainsKey(lookupVersion) && packagesByVersion.ContainsKey(lookupVersion + "+git.unspecified")) { lookupVersion += "+git.unspecified"; } sourceCodeUrl = ExtractSourceRepository(packagesByVersion[lookupVersion]); packageType = ExtractPackageType(packagesByVersion[lookupVersion]); if (!string.IsNullOrWhiteSpace(sourceCodeUrl)) { if (sourceCodeUrl.StartsWith("git=")) { sourceCodeUrl = sourceCodeUrl.Substring("git=".Length); var performGitLsRemote = true; if (sourceCodeUrl.StartsWith("https://github.com/")) { try { // This is a GitHub repository. During the installation of Protobuild Manager (hosted on GitHub), we need // to resolve the latest version on NuGet, but we can't do this because Git may not be in the PATH or may // not be available. We still want developers to be able to install Protobuild Manager without Git on // their PATH (as they may have dedicated shells to use it), so we attempt to use the GitHub API to resolve // the commit hash first. string gitHubJsonInfo; var gitHubComponents = sourceCodeUrl.Substring("https://github.com/".Length).Split('/'); var gitHubOwner = gitHubComponents[0]; var gitHubRepo = gitHubComponents[1]; var gitHubApiUrl = "https://api.github.com/repos/" + gitHubOwner + "/" + gitHubRepo + "/branches/" + version; var gitHubJson = _packageRequestCache.TryGetOptionallyCachedJsonObject( gitHubApiUrl, !request.ForceUpgrade && request.IsStaticReference, out packageMetadataJson, id => { using (var client = new RetryableWebClient()) { client.SilentOnError = true; client.SetHeader("User-Agent", "Protobuild NuGet Lookup/v1.0"); client.SetHeader("Accept", "application/vnd.github.v3+json"); return(client.DownloadString(gitHubApiUrl)); } }); var commitHash = gitHubJson.commit.sha; if (!string.IsNullOrWhiteSpace(commitHash)) { // This is a match and we've found our Git hash to use. version = NuGetVersionHelper.CreateNuGetPackageVersion(commitHash.Trim(), request.Platform); commitHashForSourceResolve = commitHash.Trim(); performGitLsRemote = false; } } catch (Exception) { Console.WriteLine("NOTICE: Unable to lookup version information via GitHub API; falling back to 'git ls-remote'"); } } if (performGitLsRemote) { var heads = _packageRequestCache.TryGetOptionallyCachedData( "git:" + sourceCodeUrl, !request.ForceUpgrade && request.IsStaticReference, id => GitUtils.RunGitAndCapture( workingDirectory, null, "ls-remote --heads " + new Uri(sourceCodeUrl))); var lines = heads.Split(new string[] { "\r\n", "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries); foreach (var line in lines) { var sourceEntryComponents = line.Split('\t'); if (sourceEntryComponents.Length >= 2) { var branchName = sourceEntryComponents[1].Trim(); if (branchName.StartsWith("refs/heads/")) { branchName = branchName.Substring("refs/heads/".Length); } else { continue; } if (string.Equals(version, branchName, StringComparison.InvariantCulture)) { // This is a match and we've found our Git hash to use. version = NuGetVersionHelper.CreateNuGetPackageVersion( sourceEntryComponents[0].Trim(), request.Platform); commitHashForSourceResolve = sourceEntryComponents[0].Trim(); break; } } } } } else { throw new InvalidOperationException("Unknown source code repository type '" + sourceCodeUrl + "'"); } // If we fall out of this loop, we'll hit the next if statement and most likely fail. } } string binaryUri = null; string binaryFormat = null; if (!packagesByVersion.ContainsKey(version)) { if (string.IsNullOrWhiteSpace(sourceCodeUrl)) { throw new InvalidOperationException( "Unable to resolve binary package for version \"" + version + "\" and platform \"" + request.Platform + "\" and this package does not have a source repository"); } else { RedirectableConsole.WriteLine("Unable to resolve binary package for version \"" + version + "\" and platform \"" + request.Platform + "\", falling back to source version"); } } else { sourceCodeUrl = ExtractSourceRepository(packagesByVersion[version]); packageType = ExtractPackageType(packagesByVersion[version]); if (!string.IsNullOrWhiteSpace(sourceCodeUrl)) { if (sourceCodeUrl.StartsWith("git=")) { sourceCodeUrl = sourceCodeUrl.Substring("git=".Length); } else { throw new InvalidOperationException("Unknown source code repository type '" + sourceCodeUrl + "'"); } } if (commitHashForSourceResolve == null) { commitHashForSourceResolve = ExtractCommitHash(packagesByVersion[version]); } // packageContent may not be under catalogEntry; our best guess is that NuGet // moved it from the root to catalogEntry at some point in the past, but not // all of the registrations are updated with it under catalogEntry, e.g. RestSharp try { binaryUri = packagesByVersion[version].catalogEntry.packageContent; } catch { binaryUri = packagesByVersion[version].packageContent; } binaryFormat = PackageManager.ARCHIVE_FORMAT_NUGET_ZIP; } return(new NuGet3PackageMetadata( repository, packageName, packageType, sourceCodeUrl, request.Platform, version, binaryFormat, binaryUri, commitHashForSourceResolve, (workingDirectoryAlt, metadata, folder, name, upgrade, source) => { if (source == true) { _sourcePackageResolve.Resolve(workingDirectoryAlt, metadata, folder, name, upgrade); } else { _binaryPackageResolve.Resolve(workingDirectoryAlt, metadata, folder, name, upgrade); } })); }