internal List <Service> ResolveServices(List <Service> services) { var pass = 1; if (this.m_ShowDebugInformation) { RedirectableConsole.WriteLine("Performing service resolution pass " + pass + ":"); } while (this.PerformResolutionPass(services)) { // Returns true if it made any modifications. ++pass; if (this.m_ShowDebugInformation) { RedirectableConsole.WriteLine("Performing service resolution pass " + pass + ":"); } } if (this.m_ShowDebugInformation) { RedirectableConsole.WriteLine("Service resolution passes complete."); } return(services.Where(x => x.DesiredLevel != ServiceDesiredLevel.Disabled && x.DesiredLevel != ServiceDesiredLevel.Unused).ToList()); }
internal void EnableDefaultAndExplicitServices(List <Service> services) { if (this.m_ShowDebugInformation) { RedirectableConsole.WriteLine("Enabling default services, and services enabled / disabled by the user:"******" set to Default, because it is marked DefaultForRoot"); } service.DesiredLevel = ServiceDesiredLevel.Default; } } if (this.m_EnabledServices.Any(x => x == service.ServiceName || x == service.FullName)) { if (this.m_ShowDebugInformation) { RedirectableConsole.WriteLine(service.FullName + " set to Required, because it is explicitly enabled by the user"); } service.DesiredLevel = ServiceDesiredLevel.Required; } if (this.m_DisabledServices.Any(x => x == service.ServiceName || x == service.FullName)) { if (this.m_ShowDebugInformation) { RedirectableConsole.WriteLine(service.FullName + " set to Disabled, because it is explicitly disabled by the user"); } service.DesiredLevel = ServiceDesiredLevel.Disabled; } } }
private void EnableReferencedProjects(List <XmlDocument> definitions, List <Service> services) { if (this.m_ShowDebugInformation) { RedirectableConsole.WriteLine("Enabling services in explicitly referenced projects:"); } var lookup = services.ToDictionarySafe( k => k.FullName, v => v, (dict, d) => RedirectableConsole.WriteLine("WARNING: There is more than one service with the full name " + d.FullName)); var references = from definition in definitions where definition.DocumentElement.Name == "Project" select definition.DocumentElement.ChildNodes.OfType <XmlElement>().FirstOrDefault(x => x.Name == "References") into referencesElement where referencesElement != null select referencesElement.ChildNodes.OfType <XmlElement>() .Where(x => x.Name == "Reference") .Select(x => x.GetAttribute("Include")) .ToList() into referencesList from reference in referencesList.Where(lookup.ContainsKey) select reference; foreach (var reference in references) { if (this.m_ShowDebugInformation) { RedirectableConsole.WriteLine(lookup[reference].FullName + " set to Required, because there is an explicit reference to the project"); } lookup[reference].DesiredLevel = ServiceDesiredLevel.Required; } }
private void EnableRootProjects(List <Service> services) { if (this.m_ShowDebugInformation) { RedirectableConsole.WriteLine("Enabling project root services:"); } foreach (var definition in this.m_RootDefinitions) { var defaultService = services.FirstOrDefault( x => x.ProjectName == definition.Name && string.IsNullOrEmpty(x.ServiceName)); if (defaultService != null) { if (this.m_ShowDebugInformation) { RedirectableConsole.WriteLine(defaultService.FullName + " set to Default, because it is a project root service"); } defaultService.DesiredLevel = ServiceDesiredLevel.Default; } } }
public IPackageMetadata ResolveSource(string workingDirectory, PackageRequestRef request) { var baseUri = new Uri(request.Uri); var apiUri = new Uri(baseUri.ToString().TrimEnd('/') + "/api"); dynamic apiData = null; var performOnlineLookup = true; if (!request.ForceUpgrade && request.IsStaticReference) { performOnlineLookup = false; if (_packageRequestCache.IsCached(request.Uri)) { try { apiData = _packageRequestCache.GetCachedJsonObject(request.Uri); } catch (ExecEnvironment.SelfInvokeExitException) { throw; } catch { performOnlineLookup = true; } } else { performOnlineLookup = true; } } if (performOnlineLookup) { try { string jsonString; apiData = this.GetJSON(apiUri, out jsonString); if (apiData.has_error) { throw new InvalidOperationException((string)apiData.error); } try { _packageRequestCache.StoreCachedData(request.Uri, jsonString); } catch (IOException) { RedirectableConsole.WriteLine("WARNING: Unable to save cached result of request."); } } catch (Exception) { // Attempt to retrieve it from the lookup cache. if (_packageRequestCache.IsCached(request.Uri)) { var shouldThrow = false; try { apiData = _packageRequestCache.GetCachedJsonObject(request.Uri); } catch (ExecEnvironment.SelfInvokeExitException) { throw; } catch { shouldThrow = true; } if (shouldThrow) { throw; } } else { throw; } } } if (apiData == null) { throw new InvalidOperationException("apiData is null"); } var sourceUri = (string)apiData.result.package.gitUrl; var type = (string)apiData.result.package.type; if (!string.IsNullOrWhiteSpace(sourceUri)) { try { new Uri(sourceUri); } catch (ExecEnvironment.SelfInvokeExitException) { throw; } catch { throw new InvalidOperationException( "Received invalid Git URL when loading package from " + apiUri); } } else { RedirectableConsole.WriteLine("WARNING: This package does not have a source repository set."); } var downloadMap = new Dictionary <string, string>(); var archiveTypeMap = new Dictionary <string, string>(); var resolvedHash = new Dictionary <string, string>(); foreach (var ver in apiData.result.versions) { if (ver.platformName != request.Platform) { continue; } if (!downloadMap.ContainsKey(ver.versionName)) { downloadMap.Add(ver.versionName, ver.downloadUrl); archiveTypeMap.Add(ver.versionName, ver.archiveType); resolvedHash.Add(ver.versionName, ver.versionName); } } foreach (var branch in apiData.result.branches) { if (!downloadMap.ContainsKey(branch.versionName)) { continue; } if (!downloadMap.ContainsKey(branch.branchName)) { downloadMap.Add(branch.branchName, downloadMap[branch.versionName]); archiveTypeMap.Add(branch.branchName, archiveTypeMap[branch.versionName]); resolvedHash.Add(branch.branchName, branch.versionName); } } // Resolve Git reference to Git commit hash. var gitCommit = resolvedHash.ContainsKey(request.GitRef) ? resolvedHash[request.GitRef] : request.GitRef; if (string.IsNullOrWhiteSpace(sourceUri)) { // Normalize source URI value. sourceUri = null; } string fileUri, archiveType; if (!downloadMap.ContainsKey(gitCommit)) { if (string.IsNullOrWhiteSpace(sourceUri)) { throw new InvalidOperationException("Unable to resolve binary package for version \"" + request.GitRef + "\" and platform \"" + request.Platform + "\" and this package does not have a source repository"); } else { RedirectableConsole.WriteLine("Unable to resolve binary package for version \"" + request.GitRef + "\" and platform \"" + request.Platform + "\", falling back to source version"); fileUri = null; archiveType = null; } } else { fileUri = downloadMap[gitCommit]; archiveType = archiveTypeMap[gitCommit]; } return(new ProtobuildPackageMetadata( request.Uri, type, sourceUri, request.Platform, gitCommit, archiveType, fileUri, (workingDirectoryAlt, metadata, folder, name, upgrade, source) => { if (source == true) { _sourcePackageResolve.Resolve(workingDirectoryAlt, metadata, folder, name, upgrade); } else { _binaryPackageResolve.Resolve(workingDirectoryAlt, metadata, folder, name, upgrade); } }, _binaryPackageResolve.GetProtobuildPackageBinary)); }
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); } })); }
private bool PerformResolutionPass(List <Service> services) { var lookup = services.ToDictionarySafe( k => k.FullName, v => v, (dict, d) => { /* We have already warned about this previously */ }); var modified = false; foreach (var service in services) { if (service.DesiredLevel == ServiceDesiredLevel.Disabled || service.DesiredLevel == ServiceDesiredLevel.Unused) { continue; } foreach (var require in service.Requires) { if (!lookup.ContainsKey(require)) { throw new InvalidOperationException( service.FullName + " requires " + require + ", but it does not exist."); } if (lookup[require].DesiredLevel == ServiceDesiredLevel.Disabled) { if (service.DesiredLevel == ServiceDesiredLevel.Required || service.ServiceName == null) { throw new InvalidOperationException( service.FullName + " requires " + require + ", but you have explicitly requested it be disabled."); } else if (service.DesiredLevel == ServiceDesiredLevel.Recommended || service.DesiredLevel == ServiceDesiredLevel.Default) { if (this.m_ShowDebugInformation) { RedirectableConsole.WriteLine(service.FullName + " set to Disabled, because it's dependency " + lookup[require].FullName + " is set to Disabled"); } service.DesiredLevel = ServiceDesiredLevel.Disabled; modified = true; } } else if (service.DesiredLevel == ServiceDesiredLevel.Required) { if (lookup[require].DesiredLevel != ServiceDesiredLevel.Required) { if (this.m_ShowDebugInformation) { RedirectableConsole.WriteLine(lookup[require].FullName + " set to Required, because it's dependency " + service.FullName + " is set to Required"); } lookup[require].DesiredLevel = ServiceDesiredLevel.Required; modified = true; } } else if (service.DesiredLevel == ServiceDesiredLevel.Recommended) { if (lookup[require].DesiredLevel != ServiceDesiredLevel.Required && lookup[require].DesiredLevel != ServiceDesiredLevel.Recommended) { if (this.m_ShowDebugInformation) { RedirectableConsole.WriteLine(lookup[require].FullName + " set to Recommended, because it's dependency " + service.FullName + " is set to Recommended"); } lookup[require].DesiredLevel = ServiceDesiredLevel.Recommended; modified = true; } } else if (service.DesiredLevel == ServiceDesiredLevel.Default) { if (lookup[require].DesiredLevel != ServiceDesiredLevel.Required && lookup[require].DesiredLevel != ServiceDesiredLevel.Recommended && lookup[require].DesiredLevel != ServiceDesiredLevel.Default) { if (this.m_ShowDebugInformation) { RedirectableConsole.WriteLine(lookup[require].FullName + " set to Default, because it's dependency " + service.FullName + " is set to Default"); } lookup[require].DesiredLevel = ServiceDesiredLevel.Default; modified = true; } } } foreach (var recommend in service.Recommends) { if (!lookup.ContainsKey(recommend)) { throw new InvalidOperationException( service.FullName + " recommends " + recommend + ", but it does not exist."); } if (lookup[recommend].DesiredLevel != ServiceDesiredLevel.Disabled && lookup[recommend].DesiredLevel != ServiceDesiredLevel.Recommended && lookup[recommend].DesiredLevel != ServiceDesiredLevel.Required) { if (this.m_ShowDebugInformation) { RedirectableConsole.WriteLine(lookup[recommend].FullName + " set to Recommended, because it's dependency " + service.FullName + " recommends it"); } lookup[recommend].DesiredLevel = ServiceDesiredLevel.Recommended; modified = true; } } foreach (var conflict in service.Conflicts) { if (!lookup.ContainsKey(conflict)) { // The service that the conflict is declared with may // not exist because it's not available on the current // platform, in which case it can't be enabled anyway. continue; } if (lookup[conflict].DesiredLevel == ServiceDesiredLevel.Required && service.DesiredLevel == ServiceDesiredLevel.Required) { throw new InvalidOperationException( service.FullName + " conflicts with " + lookup[conflict].FullName + ", but both are enabled (and required)."); } if (lookup[conflict].DesiredLevel == ServiceDesiredLevel.Recommended) { if (this.m_ShowDebugInformation) { RedirectableConsole.WriteLine(lookup[conflict].FullName + " set to Disabled, because " + service.FullName + " conflicts with it"); } // The service this conflicts with is only recommended, so we can // safely disable it. lookup[conflict].DesiredLevel = ServiceDesiredLevel.Disabled; modified = true; } } } return(modified); }