public PackageRef LookupPackageByName(ModuleInfo module, string url) { var packages = module.Packages.Where(x => x.Uri.Contains(url)).ToArray(); PackageRef packageRef; if (packages.Length == 1) { packageRef = packages[0]; } else if (packages.Length == 0) { throw new InvalidOperationException("No such package has been added"); } else { if (packages.Any(x => x.Uri == url)) { packageRef = packages.First(x => x.Uri == url); } else { throw new InvalidOperationException("Package reference is ambigious"); } } return packageRef; }
/// <summary> /// Normalizes the platform string from user input, automatically correcting case /// and validating against a list of supported platforms. /// </summary> /// <returns>The platform string.</returns> /// <param name="platform">The normalized platform string.</param> public string NormalizePlatform(ModuleInfo module, string platform) { var supportedPlatforms = ModuleInfo.GetSupportedPlatformsDefault(); var defaultPlatforms = true; if (!string.IsNullOrEmpty(module.SupportedPlatforms)) { supportedPlatforms = module.SupportedPlatforms; defaultPlatforms = false; } var supportedPlatformsArray = supportedPlatforms.Split(new[] { ',' }) .Select(x => x.Trim()) .Where(x => !string.IsNullOrWhiteSpace(x)) .ToArray(); var allowWeb = _featureManager.IsFeatureEnabled(Feature.PackageManagement); // Search the array to find a platform that matches case insensitively // to the specified platform. If we are using the default list, then we allow // other platforms to be specified (in case the developer has modified the XSLT to // support others but is not using <SupportedPlatforms>). If the developer has // explicitly set the supported platforms, then we return null if the user passes // an unknown platform (the caller is expected to exit at this point). foreach (var supportedPlatform in supportedPlatformsArray) { if (string.Compare(supportedPlatform, platform, StringComparison.InvariantCultureIgnoreCase) == 0) { if (supportedPlatform == "Web" && !allowWeb) { // We don't permit the web platform when package management // is disabled, as we can't install JSIL properly. return null; } return supportedPlatform; } } if (defaultPlatforms) { if (string.Compare("Web", platform, StringComparison.InvariantCultureIgnoreCase) == 0 && !allowWeb) { // We don't permit the web platform when package management // is disabled, as we can't install JSIL properly. return null; } return platform; } else { return null; } }
/// <summary> /// Performs the default action on the specified module. /// </summary> /// <returns><c>true</c>, if the default action succeeded, <c>false</c> otherwise.</returns> /// <param name="module">The module to perform the action on.</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> public bool DefaultAction( ModuleInfo module, string platform = null, string[] enabledServices = null, string[] disabledServices = null, string serviceSpecPath = null, bool debugServiceResolution = false, bool disablePackageResolution = false, bool disableHostPlatformGeneration = false) { return PerformAction( module, module.DefaultAction, platform, enabledServices, disabledServices, serviceSpecPath, debugServiceResolution, disablePackageResolution, disableHostPlatformGeneration); }
/// <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> public bool PerformAction( ModuleInfo module, string action, string platform = null, string[] enabledServices = null, string[] disabledServices = null, string serviceSpecPath = null, bool debugServiceResolution = false, bool disablePackageResolution = false, bool disableHostPlatformGeneration = false) { 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) { Console.Error.WriteLine("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; } // Resolve submodules as needed. if (!disablePackageResolution) { this.m_PackageManager.ResolveAll(module, primaryPlatform); } // 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 = () => { Console.Error.WriteLine( "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( module, primaryPlatform, enabledServices, disabledServices, serviceSpecPath, debugServiceResolution, disablePackageResolution, disableHostPlatformGeneration, requiresHostPlatform)) { return(false); } break; case "resync": if (!this.ResyncProjectsForPlatform( module, primaryPlatform, enabledServices, disabledServices, serviceSpecPath, debugServiceResolution, disablePackageResolution, disableHostPlatformGeneration, requiresHostPlatform)) { return(false); } break; case "sync": return(this.SyncProjectsForPlatform(module, primaryPlatform)); case "clean": if (!this.CleanProjectsForPlatform(module, primaryPlatform)) { return(false); } break; default: Console.Error.WriteLine("Unknown option in <DefaultAction> tag of Module.xml. Defaulting to resync!"); return(this.ResyncProjectsForPlatform( module, primaryPlatform, enabledServices, disabledServices, serviceSpecPath, debugServiceResolution, disablePackageResolution, disableHostPlatformGeneration, requiresHostPlatform)); } // 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(module, platformIter); } 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( module, platformIter, enabledServices, disabledServices, serviceSpecPath, debugServiceResolution, disablePackageResolution, disableHostPlatformGeneration, requiresHostPlatform)) { 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) { Console.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); } Console.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(module, hostPlatform); } 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( module, hostPlatform, enabledServices, disabledServices, serviceSpecPath, debugServiceResolution, disablePackageResolution, disableHostPlatformGeneration, requiresHostPlatform)) { 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); }
public LoadedDefinitionInfo Load(string targetPlatform, ModuleInfo module, DefinitionInfo definition) { var doc = new XmlDocument(); doc.Load(definition.DefinitionPath); // If this is a ContentProject, we actually need to generate the // full project node from the files that are in the Source folder. XmlDocument newDoc = null; if (doc.DocumentElement.Name == "ContentProject") newDoc = this.m_ContentProjectGenerator.Generate(targetPlatform, doc, definition.ModulePath); else newDoc = doc; if (module.Path != null && definition.ModulePath != null) { var additionalPath = PathUtils.GetRelativePath( module.Path.TrimEnd(System.IO.Path.DirectorySeparatorChar) + System.IO.Path.DirectorySeparatorChar, definition.ModulePath.TrimEnd(System.IO.Path.DirectorySeparatorChar) + System.IO.Path.DirectorySeparatorChar); if (newDoc.DocumentElement != null && newDoc.DocumentElement.Attributes["Path"] != null && additionalPath != null) { newDoc.DocumentElement.Attributes["Path"].Value = (additionalPath.Trim('\\') + '\\' + newDoc.DocumentElement.Attributes["Path"].Value).Replace('/', '\\').Trim('\\'); } if (newDoc.DocumentElement.Name == "ExternalProject") { // Need to find all descendant Binary and Project tags // and update their paths as well. var xDoc = newDoc.ToXDocument(); var projectsToUpdate = xDoc.Descendants().Where(x => x.Name == "Project"); var binariesToUpdate = xDoc.Descendants().Where(x => x.Name == "Binary"); var nativeBinariesToUpdate = xDoc.Descendants().Where(x => x.Name == "NativeBinary"); var toolsToUpdate = xDoc.Descendants().Where(x => x.Name == "Tool"); foreach (var pathToUpdate in projectsToUpdate.Concat(binariesToUpdate).Concat(nativeBinariesToUpdate).Concat(toolsToUpdate) .Where(x => x.Attribute("Path") != null)) { pathToUpdate.Attribute("Path").Value = (additionalPath.Trim('\\') + '\\' + pathToUpdate.Attribute("Path").Value).Replace('/', '\\').Trim('\\'); } newDoc = xDoc.ToXmlDocument(); } } // If the ProjectGuids element doesn't exist, create it. var projectGuids = doc.DocumentElement.ChildNodes.OfType<XmlElement>().FirstOrDefault(x => x.Name == "ProjectGuids"); if (projectGuids == null) { projectGuids = doc.CreateElement("ProjectGuids"); doc.DocumentElement.AppendChild(projectGuids); } // For all the supported platforms of this project, or all the // supported platforms of the module, generate GUIDs for any platform // that doesn't already exist. var platforms = doc.DocumentElement.GetAttribute("Platforms"); if (string.IsNullOrWhiteSpace(platforms)) { platforms = module.SupportedPlatforms; } if (string.IsNullOrWhiteSpace(platforms)) { platforms = ModuleInfo.GetSupportedPlatformsDefault(); } var platformsList = platforms.Split(',').ToList(); if (!platformsList.Contains(targetPlatform)) { platformsList.Add(targetPlatform); } foreach (var platform in platformsList) { var existing = projectGuids.ChildNodes.OfType<XmlElement>().FirstOrDefault(x => x.Name == "Platform" && x.HasAttribute("Name") && x.GetAttribute("Name") == platform); if (existing == null) { var platformElement = doc.CreateElement("Platform"); platformElement.SetAttribute("Name", platform); var name = doc.DocumentElement.GetAttribute("Name") + "." + platform; var guidBytes = new byte[16]; for (var i = 0; i < guidBytes.Length; i++) guidBytes[i] = (byte)0; var nameBytes = Encoding.ASCII.GetBytes(name); unchecked { for (var i = 0; i < nameBytes.Length; i++) guidBytes[i % 16] += nameBytes[i]; for (var i = nameBytes.Length; i < 16; i++) guidBytes[i] += nameBytes[i % nameBytes.Length]; } var guid = new Guid(guidBytes); platformElement.InnerText = guid.ToString().ToUpper(); projectGuids.AppendChild(platformElement); } } // If the Language property doesn't exist, set it to the default of "C#" if (doc.DocumentElement.Attributes["Language"] == null) { doc.DocumentElement.SetAttribute("Language", "C#"); } // Normalize the project type for backwards compatibility. var projectType = doc.DocumentElement.Attributes["Type"]; if (projectType == null) { doc.DocumentElement.SetAttribute("Type", "Library"); } else { switch (projectType.Value) { case "Library": case "App": case "Console": case "Website": break; case "GUI": case "XNA": case "GTK": doc.DocumentElement.SetAttribute("Type", "App"); break; } } return new LoadedDefinitionInfo { Definition = definition, Project = newDoc, }; }
public void LoadFeaturesFromSpecificModule(ModuleInfo module) { if (module.FeatureSet == null) { _featuresEnabledFromModules = null; } else { _featuresEnabledFromModules = module.FeatureSet.ToList(); } }
public virtual void FinalizeNewProject(ModuleInfo module, DefinitionInfo definition) { }
public void Generate( ModuleInfo moduleInfo, List <XmlDocument> definitions, string platformName, string solutionPath, List <Service> services, IEnumerable <string> repositoryPaths) { var generateSolutionTransform = this.m_ResourceProvider.LoadXSLT(ResourceType.GenerateSolution, Language.CSharp); var selectSolutionTransform = this.m_ResourceProvider.LoadXSLT(ResourceType.SelectSolution, Language.CSharp); var input = this.m_SolutionInputGenerator.GenerateForSelectSolution(definitions, platformName, services); using (var memory = new MemoryStream()) { selectSolutionTransform.Transform(input, null, memory); memory.Seek(0, SeekOrigin.Begin); var document = new XmlDocument(); document.Load(memory); var defaultProject = (XmlElement)null; var existingGuids = new List <string>(); foreach (var element in document.DocumentElement.SelectNodes("/Projects/Project").OfType <XmlElement>().ToList()) { var f = element.SelectNodes("Guid").OfType <XmlElement>().FirstOrDefault(); if (f != null) { if (existingGuids.Contains(f.InnerText.Trim())) { element.ParentNode.RemoveChild(element); continue; } else { existingGuids.Add(f.InnerText.Trim()); } } var n = element.SelectNodes("RawName").OfType <XmlElement>().FirstOrDefault(); if (n != null) { if (n.InnerText.Trim() == moduleInfo.DefaultStartupProject) { defaultProject = element; } } } if (defaultProject != null) { // Move the default project to the first element of it's parent. The first project // in the solution is the default startup project. var parent = defaultProject.ParentNode; parent.RemoveChild(defaultProject); parent.InsertBefore(defaultProject, parent.FirstChild); } var documentInput = this.m_SolutionInputGenerator.GenerateForGenerateSolution( platformName, document.DocumentElement.SelectNodes("/Projects/Project").OfType <XmlElement>()); using (var writer = new StreamWriter(solutionPath)) { generateSolutionTransform.Transform(documentInput, null, writer); } } if (repositoryPaths != null && repositoryPaths.Any()) { this.m_NuGetRepositoriesConfigGenerator.Generate(solutionPath, repositoryPaths); } }
/// <summary> /// Loads all of the submodules present in this module. /// </summary> /// <returns>The loaded submodules.</returns> public ModuleInfo[] GetSubmodules(string platform = null) { if (!_cachedSubmodules.ContainsKey(platform ?? "<null>")) { var modules = new List <ModuleInfo>(); foreach (var directoryInit in new DirectoryInfo(this.Path).GetDirectories()) { var directory = directoryInit; if (File.Exists(System.IO.Path.Combine(directory.FullName, ".redirect"))) { // This is a redirected submodule (due to package resolution). Load the // module from it's actual path. using (var reader = new StreamReader(System.IO.Path.Combine(directory.FullName, ".redirect"))) { var targetPath = reader.ReadToEnd().Trim(); directory = new DirectoryInfo(targetPath); } } var build = directory.GetDirectories().FirstOrDefault(x => x.Name == "Build"); if (build == null) { continue; } var module = build.GetFiles().FirstOrDefault(x => x.Name == "Module.xml"); if (module == null) { continue; } modules.Add(ModuleInfo.Load(module.FullName)); } if (platform != null) { foreach (var directoryInit in new DirectoryInfo(this.Path).GetDirectories()) { var directory = directoryInit; if (File.Exists(System.IO.Path.Combine(directory.FullName, ".redirect"))) { // This is a redirected submodule (due to package resolution). Load the // module from it's actual path. using ( var reader = new StreamReader(System.IO.Path.Combine(directory.FullName, ".redirect"))) { var targetPath = reader.ReadToEnd().Trim(); directory = new DirectoryInfo(targetPath); } } var platformDirectory = new DirectoryInfo(System.IO.Path.Combine(directory.FullName, platform)); if (!platformDirectory.Exists) { continue; } var build = platformDirectory.GetDirectories().FirstOrDefault(x => x.Name == "Build"); if (build == null) { continue; } var module = build.GetFiles().FirstOrDefault(x => x.Name == "Module.xml"); if (module == null) { continue; } modules.Add(ModuleInfo.Load(module.FullName)); } } _cachedSubmodules[platform ?? "<null>"] = modules.ToArray(); } return(_cachedSubmodules[platform ?? "<null>"]); }
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); }
private void ShowSupportedPlatformsError(ModuleInfo module, string requestedPlatform) { Console.Error.WriteLine("The platform '" + requestedPlatform + "' is not supported."); Console.Error.WriteLine("The following platforms are supported by this module:"); foreach ( var supportedPlatform in module.SupportedPlatforms.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .Select(x => x.Trim()) .Where(x => !string.IsNullOrWhiteSpace(x))) { Console.Error.WriteLine(" * " + supportedPlatform); } ExecEnvironment.Exit(1); }
/// <summary> /// Generates the projects for the specified platform. /// </summary> /// <returns><c>true</c>, if the generation succeeded, <c>false</c> otherwise.</returns> /// <param name="module">The module whose projects should be generated.</param> /// <param name="platform">The platform to generate 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="requiresHostPlatform">A callback which indicates the generation requires host platform projects in the same solution.</param> private bool GenerateProjectsForPlatform( ModuleInfo module, string platform, string[] enabledServices, string[] disabledServices, string serviceSpecPath, bool debugServiceResolution, bool disablePackageResolution, bool disableHostPlatformGeneration, Action requiresHostPlatform) { if (string.IsNullOrWhiteSpace(platform)) { platform = this.m_HostPlatformDetector.DetectPlatform(); } var task = this.m_LightweightKernel.Get<GenerateProjectsTask>(); task.SourcePath = Path.Combine(module.Path, "Build", "Projects"); task.RootPath = module.Path + Path.DirectorySeparatorChar; task.Platform = platform; task.ModuleName = module.Name; task.EnableServices = enabledServices; task.DisableServices = disabledServices; task.ServiceSpecPath = serviceSpecPath; task.DebugServiceResolution = debugServiceResolution; task.DisablePackageResolution = disablePackageResolution; task.DisableHostPlatformGeneration = disableHostPlatformGeneration; task.RequiresHostPlatform = requiresHostPlatform; return task.Execute(); }
/// <summary> /// Resynchronises the projects for the specified platform. /// </summary> /// <returns><c>true</c>, if the resynchronisation succeeded, <c>false</c> otherwise.</returns> /// <param name="module">The module to resynchronise.</param> /// <param name="platform">The platform to resynchronise 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="requiresHostPlatform">A callback which indicates the generation requires host platform projects in the same solution.</param> private bool ResyncProjectsForPlatform( ModuleInfo module, string platform, string[] enabledServices, string[] disabledServices, string serviceSpecPath, bool debugServiceResolution, bool disablePackageResolution, bool disableHostPlatformGeneration, Action requiresHostPlatform) { if (module.DisableSynchronisation ?? false) { Console.WriteLine("Synchronisation is disabled for " + module.Name + "."); Console.WriteLine("To generate projects, use the --generate option instead."); return false; } else { if (!SyncProjectsForPlatform(module, platform)) { return false; } return GenerateProjectsForPlatform( module, platform, enabledServices, disabledServices, serviceSpecPath, debugServiceResolution, disablePackageResolution, disableHostPlatformGeneration, requiresHostPlatform); } }
/// <summary> /// Cleans the projects for the specified platform. /// </summary> /// <returns><c>true</c>, if projects were cleaned successfully, <c>false</c> otherwise.</returns> /// <param name="module">The module to clean projects in.</param> /// <param name="platform">The platform to clean for.</param> private bool CleanProjectsForPlatform(ModuleInfo module, string platform) { if (string.IsNullOrWhiteSpace(platform)) { platform = this.m_HostPlatformDetector.DetectPlatform(); } var task = this.m_LightweightKernel.Get<CleanProjectsTask>(); task.SourcePath = Path.Combine(module.Path, "Build", "Projects"); task.RootPath = module.Path + Path.DirectorySeparatorChar; task.Platform = platform; task.ModuleName = module.Name; return task.Execute(); }
public void Autopackage(string workingDirectory, FileFilter fileFilter, Execution execution, ModuleInfo module, string rootPath, string platform, string packageFormat, List <string> temporaryFiles) { switch (packageFormat) { case PackageManager.ARCHIVE_FORMAT_NUGET_ZIP: _nuGetAutomaticModulePackager.Autopackage( workingDirectory, fileFilter, execution, module, rootPath, platform, packageFormat, temporaryFiles); break; case PackageManager.ARCHIVE_FORMAT_TAR_GZIP: case PackageManager.ARCHIVE_FORMAT_TAR_LZMA: default: _protobuildAutomaticModulePackager.Autopackage( workingDirectory, fileFilter, execution, module, rootPath, platform, packageFormat, temporaryFiles); break; } }
public virtual void StartNewProject(ModuleInfo module, string name) { }
/// <summary> /// Synchronises the projects for the specified platform. /// </summary> /// <returns><c>true</c>, if the synchronisation succeeded, <c>false</c> otherwise.</returns> /// <param name="module">The module to synchronise.</param> /// <param name="platform">The platform to synchronise for.</param> private bool SyncProjectsForPlatform(ModuleInfo module, string platform) { if (module.DisableSynchronisation ?? false) { Console.WriteLine("Synchronisation is disabled for " + module.Name + "."); return false; } if (string.IsNullOrWhiteSpace(platform)) { platform = this.m_HostPlatformDetector.DetectPlatform(); } var task = this.m_LightweightKernel.Get<SyncProjectsTask>(); task.SourcePath = Path.Combine(module.Path, "Build", "Projects"); task.RootPath = module.Path + Path.DirectorySeparatorChar; task.Platform = platform; task.ModuleName = module.Name; return task.Execute(); }
/// <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> public bool PerformAction( ModuleInfo module, string action, string platform = null, string[] enabledServices = null, string[] disabledServices = null, string serviceSpecPath = null) { var platformSupplied = !string.IsNullOrWhiteSpace(platform); if (string.IsNullOrWhiteSpace(platform)) { platform = this.m_HostPlatformDetector.DetectPlatform(); } var originalPlatform = platform; platform = module.NormalizePlatform(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 = module.NormalizePlatform(firstPlatform); } } if (platform == null) { Console.Error.WriteLine("The platform '" + originalPlatform + "' is not supported."); Console.Error.WriteLine("The following platforms are supported by this module:"); foreach ( var supportedPlatform in module.SupportedPlatforms.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .Select(x => x.Trim()) .Where(x => !string.IsNullOrWhiteSpace(x))) { Console.Error.WriteLine(" * " + supportedPlatform); } ExecEnvironment.Exit(1); return(false); } var 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. string multiplePlatforms = null; 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; } // Resolve submodules as needed. this.m_PackageManager.ResolveAll(module, primaryPlatform); // 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(module, primaryPlatform, enabledServices, disabledServices, serviceSpecPath)) { return(false); } break; case "resync": if (!this.ResyncProjectsForPlatform(module, primaryPlatform, enabledServices, disabledServices, serviceSpecPath)) { return(false); } break; case "sync": return(this.SyncProjectsForPlatform(module, primaryPlatform)); case "clean": if (!this.CleanProjectsForPlatform(module, primaryPlatform)) { return(false); } break; default: Console.Error.WriteLine("Unknown option in <DefaultAction> tag of Module.xml. Defaulting to resync!"); return(this.ResyncProjectsForPlatform(module, primaryPlatform, enabledServices, disabledServices, serviceSpecPath)); } // Now iterate through the multiple platforms specified. var multiplePlatformsArray = multiplePlatforms.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()); foreach (var platformIter in multiplePlatformsArray) { if (platformIter == primaryPlatform) { // Already handled above. continue; } // Resolve submodules as needed. this.m_PackageManager.ResolveAll(module, platformIter); 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(module, platformIter, enabledServices, disabledServices, serviceSpecPath)) { return(false); } break; case "clean": if (!this.CleanProjectsForPlatform(module, platformIter)) { return(false); } break; default: throw new InvalidOperationException("Code should never reach this point"); } } // All the steps succeeded, so return true. return(true); }
/// <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> public bool PerformAction( ModuleInfo module, string action, string platform = null, string[] enabledServices = null, string[] disabledServices = null, string serviceSpecPath = null, bool debugServiceResolution = false, bool disablePackageResolution = false, bool disableHostPlatformGeneration = false) { 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) { Console.Error.WriteLine("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; } // Resolve submodules as needed. if (!disablePackageResolution) { this.m_PackageManager.ResolveAll(module, primaryPlatform); } // 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 = () => { Console.Error.WriteLine( "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( module, primaryPlatform, enabledServices, disabledServices, serviceSpecPath, debugServiceResolution, disablePackageResolution, disableHostPlatformGeneration, requiresHostPlatform)) { return false; } break; case "resync": if (!this.ResyncProjectsForPlatform( module, primaryPlatform, enabledServices, disabledServices, serviceSpecPath, debugServiceResolution, disablePackageResolution, disableHostPlatformGeneration, requiresHostPlatform)) { return false; } break; case "sync": return this.SyncProjectsForPlatform(module, primaryPlatform); case "clean": if (!this.CleanProjectsForPlatform(module, primaryPlatform)) { return false; } break; default: Console.Error.WriteLine("Unknown option in <DefaultAction> tag of Module.xml. Defaulting to resync!"); return this.ResyncProjectsForPlatform( module, primaryPlatform, enabledServices, disabledServices, serviceSpecPath, debugServiceResolution, disablePackageResolution, disableHostPlatformGeneration, requiresHostPlatform); } // 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(module, platformIter); } 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( module, platformIter, enabledServices, disabledServices, serviceSpecPath, debugServiceResolution, disablePackageResolution, disableHostPlatformGeneration, requiresHostPlatform)) { 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) { Console.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; } Console.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(module, hostPlatform); } 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( module, hostPlatform, enabledServices, disabledServices, serviceSpecPath, debugServiceResolution, disablePackageResolution, disableHostPlatformGeneration, requiresHostPlatform)) { 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 static ModuleInfo LoadInternal(XDocument doc, string modulePath, Func <ModuleInfo> fallback) { var def = new ModuleInfo(); var xsi = doc.Root == null ? null : doc.Root.Attribute(XName.Get("xsi", "http://www.w3.org/2000/xmlns/")); if (xsi != null && xsi.Value == "http://www.w3.org/2001/XMLSchema-instance") { return(fallback()); } Func <string, string> getStringValue = name => { if (doc.Root == null) { return(null); } var elem = doc.Root.Element(XName.Get(name)); if (elem == null) { return(null); } return(elem.Value); }; def.Name = getStringValue("Name"); def.Authors = getStringValue("Authors"); def.Description = getStringValue("Description"); def.ProjectUrl = getStringValue("ProjectUrl"); def.LicenseUrl = getStringValue("LicenseUrl"); def.IconUrl = getStringValue("IconUrl"); def.GitRepositoryUrl = getStringValue("GitRepositoryUrl"); def.SemanticVersion = getStringValue("SemanticVersion"); def.Path = modulePath; def.DefaultAction = getStringValue("DefaultAction"); def.DefaultLinuxPlatforms = getStringValue("DefaultLinuxPlatforms"); def.DefaultMacOSPlatforms = getStringValue("DefaultMacOSPlatforms"); def.DefaultWindowsPlatforms = getStringValue("DefaultWindowsPlatforms"); def.DefaultStartupProject = getStringValue("DefaultStartupProject"); def.SupportedPlatforms = getStringValue("SupportedPlatforms"); def.DisableSynchronisation = getStringValue("DisableSynchronisation") == "true"; def.GenerateNuGetRepositories = getStringValue("GenerateNuGetRepositories") == "true"; def.Packages = new List <PackageRef>(); if (doc.Root != null) { var packagesElem = doc.Root.Element(XName.Get("Packages")); if (packagesElem != null) { var packages = packagesElem.Elements(); foreach (var package in packages) { var folder = package.Attribute(XName.Get("Folder"))?.Value; var gitRef = package.Attribute(XName.Get("GitRef"))?.Value; var uri = package.Attribute(XName.Get("Uri"))?.Value; var repository = package.Attribute(XName.Get("Repository"))?.Value; var packageName = package.Attribute(XName.Get("Package"))?.Value; var version = package.Attribute(XName.Get("Version"))?.Value; if (!string.IsNullOrWhiteSpace(repository) && !string.IsNullOrWhiteSpace(packageName) && !string.IsNullOrWhiteSpace(version)) { // This is NuGet v3 package. Rather than writing a different interface, // we just automatically form a URI that complies with the rest of the // package resolution system. uri = repository; if (!string.IsNullOrWhiteSpace(uri)) { uri = uri.Replace("https://", "https-nuget-v3://"); uri = uri.Replace("http://", "http-nuget-v3://"); uri += $"|{packageName}"; } gitRef = version; } if (string.IsNullOrWhiteSpace(folder) && !string.IsNullOrWhiteSpace(packageName)) { folder = packageName; } if (string.IsNullOrWhiteSpace(folder) || string.IsNullOrWhiteSpace(gitRef) || string.IsNullOrWhiteSpace(uri)) { RedirectableConsole.ErrorWriteLine("WARNING: Invalid package declaration in module; skipping package."); continue; } var packageRef = new PackageRef { Folder = folder, GitRef = gitRef, Uri = uri, Platforms = null, }; var platforms = package.Attribute(XName.Get("Platforms")); var platformsArray = platforms?.Value.Split(','); if (platformsArray?.Length > 0) { packageRef.Platforms = platformsArray; } def.Packages.Add(packageRef); } } var featureSetElem = doc.Root.Element(XName.Get("FeatureSet")); if (featureSetElem != null) { def.FeatureSet = new List <Feature>(); var features = featureSetElem.Elements(); foreach (var feature in features) { try { def.FeatureSet.Add((Feature)Enum.Parse(typeof(Feature), feature.Value)); } catch { RedirectableConsole.ErrorWriteLine("Unknown feature in Module.xml; ignoring: " + feature.Value); } } } else { def.FeatureSet = null; } // Check if the feature set is present and if it does not contain // the PackageManagement feature. If that feature isn't there, we // ignore any of the data in Packages and just set the value to // an empty list. if (def.FeatureSet != null && !def.FeatureSet.Contains(Feature.PackageManagement)) { def.Packages.Clear(); } } return(def); }
public DefinitionSynchroniser(ModuleInfo moduleInfo, DefinitionInfo info, CSharpProject project) { this.m_ModuleInfo = moduleInfo; this.m_DefinitionInfo = info; this.m_CSharpProject = project; }
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); }
public void Generate( ModuleInfo moduleInfo, List<XmlDocument> definitions, string platformName, string solutionPath, List<Service> services, IEnumerable<string> repositoryPaths) { var generateSolutionTransform = this.m_ResourceProvider.LoadXSLT(ResourceType.GenerateSolution, Language.CSharp, platformName); var selectSolutionTransform = this.m_ResourceProvider.LoadXSLT(ResourceType.SelectSolution, Language.CSharp, platformName); var input = this.m_SolutionInputGenerator.GenerateForSelectSolution(definitions, platformName, services); using (var memory = new MemoryStream()) { selectSolutionTransform.Transform(input, null, memory); memory.Seek(0, SeekOrigin.Begin); var document = new XmlDocument(); document.Load(memory); var defaultProject = (XmlElement)null; var existingGuids = new List<string>(); foreach (var element in document.DocumentElement.SelectNodes("/Projects/Project").OfType<XmlElement>().ToList()) { var f = element.SelectNodes("ProjectGuids/Platform[@Name='" + platformName + "']").OfType<XmlElement>().FirstOrDefault(); if (f != null) { if (existingGuids.Contains(f.InnerText.Trim())) { element.ParentNode.RemoveChild(element); continue; } else { existingGuids.Add(f.InnerText.Trim()); } } var s = element.SelectNodes("Guid").OfType<XmlElement>().FirstOrDefault(); if (s != null) { if (existingGuids.Contains(s.InnerText.Trim())) { element.ParentNode.RemoveChild(element); continue; } else { existingGuids.Add(s.InnerText.Trim()); } } var n = element.SelectNodes("RawName").OfType<XmlElement>().FirstOrDefault(); if (n != null) { if (n.InnerText.Trim() == moduleInfo.DefaultStartupProject) { defaultProject = element; } } } if (defaultProject != null) { // Move the default project to the first element of it's parent. The first project // in the solution is the default startup project. var parent = defaultProject.ParentNode; parent.RemoveChild(defaultProject); parent.InsertBefore(defaultProject, parent.FirstChild); } var documentInput = this.m_SolutionInputGenerator.GenerateForGenerateSolution( platformName, document.DocumentElement.SelectNodes("/Projects/Project").OfType<XmlElement>()); using (var writer = new StreamWriter(solutionPath)) { generateSolutionTransform.Transform(documentInput, null, writer); } } if (repositoryPaths != null && repositoryPaths.Any()) { this.m_NuGetRepositoriesConfigGenerator.Generate(solutionPath, repositoryPaths); } }
public void ResolveAll(string workingDirectory, ModuleInfo module, string platform, bool?enableParallelisation, bool forceUpgrade, bool?safeResolve, bool?overrideSourcePreference) { 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, overrideSourcePreference, 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, overrideSourcePreference, forceUpgrade, safeResolve); })); }); taskList.Add(task()); } else { var metadata = Lookup(workingDirectory, module, submodule1, platform, null, overrideSourcePreference, 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, overrideSourcePreference, 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."); }
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); } } }
public void Autopackage( FileFilter fileFilter, Execution execution, ModuleInfo module, string rootPath, string platform, List<string> temporaryFiles) { var definitions = module.GetDefinitionsRecursively(platform).ToArray(); var loadedProjects = new List<LoadedDefinitionInfo>(); foreach (var definition in definitions) { Console.WriteLine("Loading: " + definition.Name); loadedProjects.Add( this.m_ProjectLoader.Load( platform, module, definition)); } var serviceManager = new ServiceManager(platform); List<Service> services; serviceManager.SetRootDefinitions(module.GetDefinitions()); var enabledServices = execution.EnabledServices.ToArray(); var disabledServices = execution.DisabledServices.ToArray(); foreach (var service in enabledServices) { serviceManager.EnableService(service); } foreach (var service in disabledServices) { serviceManager.DisableService(service); } if (execution.DebugServiceResolution) { serviceManager.EnableDebugInformation(); } services = serviceManager.CalculateDependencyGraph(loadedProjects.Select(x => x.Project).ToList()); foreach (var service in services) { if (service.ServiceName != null) { Console.WriteLine("Enabled service: " + service.FullName); } } var packagePaths = module.Packages .Select(x => new DirectoryInfo(System.IO.Path.Combine(module.Path, x.Folder)).FullName) .ToArray(); foreach (var definition in definitions) { if (definition.SkipAutopackage) { Console.WriteLine("Skipping: " + definition.Name); continue; } var definitionNormalizedPath = new FileInfo(definition.AbsolutePath).FullName; if (packagePaths.Any(definitionNormalizedPath.StartsWith)) { Console.WriteLine("Skipping: " + definition.Name + " (part of another package)"); continue; } switch (definition.Type) { case "External": Console.WriteLine("Packaging: " + definition.Name); this.AutomaticallyPackageExternalProject(definitions, services, fileFilter, rootPath, platform, definition, temporaryFiles); break; case "Include": Console.WriteLine("Packaging: " + definition.Name); this.AutomaticallyPackageIncludeProject(definitions, services, fileFilter, rootPath, platform, definition); break; case "Content": Console.WriteLine("Content project definition skipped: " + definition.Name); break; default: Console.WriteLine("Packaging: " + definition.Name); this.AutomaticallyPackageNormalProject(definitions, services, fileFilter, rootPath, platform, definition, temporaryFiles); break; } } // If there is no Module.xml in the source mappings already, then copy the current module. var filterDictionary = fileFilter.ToDictionarySafe( k => k.Key, v => v.Value, (dict, d) => Console.WriteLine ("WARNING: More than one file maps to " + d.Key)); if (!filterDictionary.ContainsValue("Build/Module.xml")) { fileFilter.AddManualMapping(Path.Combine(module.Path, "Build", "Module.xml"), "Build/Module.xml"); } }
public byte[] Transform(string url, string gitReference, string platform, string format) { var urlAndPackageName = url.Split(new[] { '|' }, 2); if (urlAndPackageName.Length != 2) { Console.Error.WriteLine( "ERROR: Malformed NuGet package reference '" + url + "'. Make sure you split the NuGet server URL and the package name with a pipe character (|)."); ExecEnvironment.Exit(1); } var repoUrl = urlAndPackageName[0]; var packageName = urlAndPackageName[1]; var originalFolder = DownloadOrUseExistingNuGetPackage(repoUrl.TrimEnd('/'), packageName, gitReference); var folder = Path.GetTempFileName(); File.Delete(folder); Directory.CreateDirectory(folder); byte[] bytes; try { Console.WriteLine("Copying directory for package transformation..."); CopyFolder(new DirectoryInfo(originalFolder), new DirectoryInfo(folder)); Console.WriteLine("Auto-detecting libraries to reference from NuGet package..."); var packagePath = new DirectoryInfo(folder).GetFiles("*.nuspec").First().FullName; var libraryReferences = new Dictionary <string, string>(); var packageDependencies = new Dictionary <string, string>(); // Use the nuspec file if it exists. List <string> references = new List <string>(); if (File.Exists(packagePath)) { var packageDoc = new XmlDocument(); packageDoc.Load(packagePath); // 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) => Console.WriteLine("WARNING: More than one dependency on " + c + " in NuGet package.")); } } // Determine the priority of the frameworks that we want to target // out of the available versions. string[] clrNames = new[] { // Exact matches "=net40-client", "=Net40-client", "=net40", "=Net40", "=net35", "=Net35", "=net20", "=Net20", "=20", "=11", "=", "=net45", "=Net45", // Substring matches "?net4", "?Net4", "?MonoAndroid", }; if (platform == "WindowsUniversal") { // This is the priority list for Windows Universal Apps. clrNames = new[] { "=uap10.0", "=uap", "=netcore451", "=netcore", "=dotnet" }; } 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) { Console.WriteLine("Found library to reference: " + kv.Key + " (at " + kv.Value + ")"); } Console.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); } document.Save(Path.Combine(folder, "_ProtobuildExternalProject.xml")); Console.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 = repoUrl.Replace("http://", "http-nuget://").Replace("https://", "https-nuget://") + "|" + package.Key, GitRef = package.Value.TrimStart('[').TrimEnd(']'), Folder = package.Key }); } generatedModule.Save(Path.Combine(folder, "_ProtobuildModule.xml")); Console.WriteLine("Converting to a Protobuild package..."); var target = new MemoryStream(); var filter = new FileFilter(_getRecursiveUtilitiesInPath.GetRecursiveFilesInPath(folder)); foreach (var kv in libraryReferences) { filter.ApplyInclude( Regex.Escape(kv.Value.Substring(folder.Length).Replace('\\', '/').TrimStart('/'))); filter.ApplyRewrite( Regex.Escape(kv.Value.Substring(folder.Length).Replace('\\', '/').TrimStart('/')), kv.Value.Substring(folder.Length).Replace('\\', '/').TrimStart('/').Replace("%2B", "-")); } filter.ApplyInclude("_ProtobuildExternalProject\\.xml"); filter.ApplyRewrite("_ProtobuildExternalProject\\.xml", "Build/Projects/" + packageName + ".definition"); filter.ApplyInclude("_ProtobuildModule\\.xml"); filter.ApplyRewrite("_ProtobuildModule\\.xml", "Build/Module.xml"); filter.ImplyDirectories(); _packageCreator.Create( target, filter, folder, format); Console.WriteLine("Package conversion complete."); bytes = new byte[target.Position]; target.Seek(0, SeekOrigin.Begin); target.Read(bytes, 0, bytes.Length); } finally { Console.WriteLine("Cleaning up temporary data..."); PathUtils.AggressiveDirectoryDelete(folder); } return(bytes); }
public bool IsFeatureEnabledInSubmodule(ModuleInfo module, ModuleInfo submodule, Feature feature) { if (submodule.CachedInternalFeatures == null) { var result = _moduleExecution.RunProtobuild(submodule, "-query-features", true); var exitCode = result.Item1; var stdout = result.Item2 + result.Item3; if (exitCode != 0 || stdout.Contains("Protobuild.exe [options]") || stdout.Contains("Unknown argument")) { submodule.CachedInternalFeatures = new Feature[0]; } submodule.CachedInternalFeatures = ParseFeaturesFromStdout(stdout); if (submodule.CachedInternalFeatures.Contains(Feature.PropagateFeatures)) { // If we have a limited feature set, we need to query again with // only our features propagated. result = _moduleExecution.RunProtobuild(submodule, GetFeatureArgumentToPassToSubmodule(module, submodule) + "-query-features", true); exitCode = result.Item1; stdout = result.Item2 + result.Item3; if (!(exitCode != 0 || stdout.Contains("Protobuild.exe [options]") || stdout.Contains("Unknown argument"))) { submodule.CachedInternalFeatures = ParseFeaturesFromStdout(stdout); } } } return submodule.CachedInternalFeatures.Contains(feature); }
public int Execute(Execution execution) { if (!Directory.Exists(execution.PackageSourceFolder)) { throw new InvalidOperationException("The source folder " + execution.PackageSourceFolder + " does not exist."); } var allowAutopackage = true; var moduleExpectedPath = Path.Combine(execution.PackageSourceFolder, "Build", "Module.xml"); ModuleInfo rootModule = null; if (!File.Exists(moduleExpectedPath)) { if (execution.PackageFilterFile == null) { Console.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 customDirectives = new Dictionary <string, Action <FileFilter> >() { { "autopackage", f => { if (allowAutopackage && rootModule != null) { this.m_AutomaticProjectPackager.Autopackage( f, execution, rootModule, execution.PackageSourceFolder, execution.PackagePlatform); } else { Console.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."); } } } }; Console.WriteLine("Starting package creation for " + execution.PackagePlatform); var filter = new FileFilter(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)) { Console.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 (!filterDictionary.ContainsValue("Build/")) { Console.WriteLine("ERROR: The Build directory does not exist in the source folder."); if (execution.PackageFilterFile != null) { this.PrintFilterMappings(filterDictionary); } return(1); } if (!filterDictionary.ContainsValue("Build/Projects/")) { Console.WriteLine("ERROR: The Build\\Projects directory does not exist in the source folder."); if (execution.PackageFilterFile != null) { this.PrintFilterMappings(filterDictionary); } return(1); } if (!filterDictionary.ContainsValue("Build/Module.xml")) { Console.WriteLine("ERROR: The Build\\Module.xml file does not exist in the source folder."); if (execution.PackageFilterFile != null) { this.PrintFilterMappings(filterDictionary); } return(1); } if (filterDictionary.ContainsValue("Protobuild.exe")) { Console.WriteLine("ERROR: The Protobuild.exe file should not be included in the package file."); if (execution.PackageFilterFile != null) { this.PrintFilterMappings(filterDictionary); } return(1); } using (var target = new FileStream(execution.PackageDestinationFile, FileMode.CreateNew, FileAccess.Write, FileShare.None)) { var archive = new MemoryStream(); switch (execution.PackageFormat) { case PackageManager.ARCHIVE_FORMAT_TAR_GZIP: { Console.WriteLine("Writing package in tar/gzip format..."); break; } case PackageManager.ARCHIVE_FORMAT_TAR_LZMA: default: { Console.WriteLine("Writing package in tar/lzma format..."); break; } } switch (execution.PackageFormat) { case PackageManager.ARCHIVE_FORMAT_TAR_GZIP: case PackageManager.ARCHIVE_FORMAT_TAR_LZMA: default: { var state = this.m_Deduplicator.CreateState(); Console.Write("Deduplicating files in package..."); var progressHelper = new DedupProgressRenderer(filter.Count()); var current = 0; foreach (var kv in filter.OrderBy(kv => kv.Value)) { if (kv.Value.EndsWith("/")) { // Directory this.m_Deduplicator.AddDirectory(state, kv.Value); } else { // File var realFile = Path.Combine(execution.PackageSourceFolder, kv.Key); var realFileInfo = new FileInfo(realFile); this.m_Deduplicator.AddFile(state, realFileInfo, kv.Value); } current++; progressHelper.SetProgress(current); } Console.WriteLine(); Console.WriteLine("Adding files to package..."); using (var writer = new tar_cs.TarWriter(archive)) { this.m_Deduplicator.PushToTar(state, writer); } break; } } archive.Seek(0, SeekOrigin.Begin); switch (execution.PackageFormat) { case PackageManager.ARCHIVE_FORMAT_TAR_GZIP: { Console.WriteLine("Compressing package..."); using (var compress = new GZipStream(target, CompressionMode.Compress)) { archive.CopyTo(compress); } break; } case PackageManager.ARCHIVE_FORMAT_TAR_LZMA: default: { Console.Write("Compressing package..."); var progressHelper = new CompressProgressRenderer(archive.Length); LZMA.LzmaHelper.Compress(archive, target, progressHelper); Console.WriteLine(); break; } } } Console.WriteLine("\rPackage written to " + execution.PackageDestinationFile + " successfully."); return(0); }
public string GetFeatureArgumentToPassToSubmodule(ModuleInfo module, ModuleInfo submodule) { if (!IsFeatureEnabledInSubmodule(module, submodule, Feature.PropagateFeatures)) { // This submodule doesn't support feature propagation, so we pass no arguments. return string.Empty; } if ((_featuresEnabledFromCommandLine == null && _featuresEnabledFromModules == null) || _parentPropagatesFullFeatureSet) { return "--features full "; } var features = GetAllEnabledFeatures(); if (features.Length == 0) { return "--features \"\" "; } return "--features \"" + features.Select(x => x.ToString()).Aggregate((a, b) => a + "," + b) + "\" "; }
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"); PathUtils.MakePathExecutable(protobuildPath, true); 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)); }