public override SdkResult ResolveSdk(int submissionId, SdkReference sdk, LoggingContext loggingContext, ElementLocation sdkReferenceLocation, string solutionPath, string projectPath, bool interactive, bool isRunningInVisualStudio) { bool wasResultCached = true; MSBuildEventSource.Log.OutOfProcSdkResolverServiceRequestSdkPathFromMainNodeStart(submissionId, sdk.Name, solutionPath, projectPath); // Get a cached response if possible, otherwise send the request Lazy <SdkResult> sdkResultLazy = _responseCache.GetOrAdd( sdk.Name, key => new Lazy <SdkResult>(() => { wasResultCached = false; return(RequestSdkPathFromMainNode(submissionId, sdk, loggingContext, sdkReferenceLocation, solutionPath, projectPath, interactive, isRunningInVisualStudio)); })); SdkResult sdkResult = sdkResultLazy.Value; if (sdkResult.Version != null && !SdkResolverService.IsReferenceSameVersion(sdk, sdkResult.Version)) { // MSB4240: Multiple versions of the same SDK "{0}" cannot be specified. The SDK version "{1}" already specified by "{2}" will be used and the version "{3}" will be ignored. loggingContext.LogWarning(null, new BuildEventFileInfo(sdkReferenceLocation), "ReferencingMultipleVersionsOfTheSameSdk", sdk.Name, sdkResult.Version, sdkResult.ElementLocation, sdk.Version); } MSBuildEventSource.Log.OutOfProcSdkResolverServiceRequestSdkPathFromMainNodeStop(submissionId, sdk.Name, solutionPath, projectPath, _lastResponse.Success, wasResultCached); return(sdkResult); }
/// <summary> /// Processes all requests that are currently in the queue. /// </summary> private void ProcessRequests() { // Store a list of threads which are resolving SDKs List <Task> tasks = new List <Task>(_requests.Count); SdkResolverRequest item; while (_requests.TryDequeue(out item)) { SdkResolverRequest request = item; // Start a thread to resolve an SDK and add it to the list of threads tasks.Add(Task.Run(() => { // Create an SdkReference from the request SdkReference sdkReference = new SdkReference(request.Name, request.Version, request.MinimumVersion); ILoggingService loggingService = Host.GetComponent(BuildComponentType.LoggingService) as ILoggingService; // This call is usually cached so is very fast but can take longer for a new SDK that is downloaded. Other queued threads for different SDKs will complete sooner and continue on which unblocks evaluations SdkResult result = GetSdkResultAndCache(request.SubmissionId, sdkReference, new EvaluationLoggingContext(loggingService, request.BuildEventContext, request.ProjectPath), request.ElementLocation, request.SolutionPath, request.ProjectPath); // Create a response SdkResolverResponse response = new SdkResolverResponse(result.Path, result.Version); // Get the node manager and send the response back to the node that requested the SDK INodeManager nodeManager = Host.GetComponent(BuildComponentType.NodeManager) as INodeManager; nodeManager.SendData(request.NodeId, response); })); } // Wait for all tasks to complete Task.WaitAll(tasks.ToArray()); }
/// <summary> /// Handles a response from the main node. /// </summary> /// <param name="response"></param> private void HandleResponse(SdkResult response) { // Store the last response so the awaiting thread can use it _lastResponse = response; // Signal that a response has been received _responseReceivedEvent.Set(); }
private SdkResult CloneSdkResult(SdkResult sdkResult) { if (!sdkResult.Success) { return(new SdkResult(sdkResult.SdkReference, sdkResult.Warnings, sdkResult.Errors)); } IEnumerable <string> sdkResultPaths; if (sdkResult.Path == null) { sdkResultPaths = Enumerable.Empty <string>(); } else { List <string> pathList = new List <string>(); pathList.Add(sdkResult.Path); if (sdkResult.AdditionalPaths != null) { pathList.AddRange(sdkResult.AdditionalPaths); } sdkResultPaths = pathList; } Dictionary <string, SdkResultItem> sdkResultItems; if (sdkResult.ItemsToAdd == null) { sdkResultItems = null; } else { sdkResultItems = new Dictionary <string, SdkResultItem>(StringComparer.OrdinalIgnoreCase); foreach (var item in sdkResult.ItemsToAdd) { Dictionary <string, string> newMetadata = null; if (item.Value.Metadata != null) { newMetadata = new Dictionary <string, string>(item.Value.Metadata, StringComparer.OrdinalIgnoreCase); } sdkResultItems.Add(item.Key, new SdkResultItem(item.Value.ItemSpec, newMetadata)); } } return(new SdkResult(sdkResult.SdkReference, sdkResultPaths, version: sdkResult.Version, sdkResult.PropertiesToAdd == null ? null : new Dictionary <string, string>(sdkResult.PropertiesToAdd, StringComparer.OrdinalIgnoreCase), sdkResultItems, sdkResult.Warnings)); }
/// <summary> /// Resolves the specified SDK without caching the result. /// </summary> /// <param name="submissionId">The current build submission ID that is resolving an SDK.</param> /// <param name="sdk">The <see cref="SdkReference"/> containing information about the SDK to resolve.</param> /// <param name="loggingContext">The <see cref="LoggingContext"/> to use when logging messages during resolution.</param> /// <param name="sdkReferenceLocation">The <see cref="ElementLocation"/> of the element that referenced the SDK.</param> /// <param name="solutionPath">The full path to the solution, if any, that is being built.</param> /// <param name="projectPath">The full path to the project that referenced the SDK.</param> /// <returns>An <see cref="SdkResult"/> containing information about the SDK if one was resolved, otherwise <code>null</code>.</returns> private SdkResult GetSdkResult(int submissionId, SdkReference sdk, LoggingContext loggingContext, ElementLocation sdkReferenceLocation, string solutionPath, string projectPath) { SdkResult sdkResult = SdkResolverService.Instance.GetSdkResult(submissionId, sdk, loggingContext, sdkReferenceLocation, solutionPath, projectPath); if (sdkResult != null) { if (!SdkResolverService.IsReferenceSameVersion(sdk, sdkResult.Version)) { // MSB4241: The SDK reference "{0}" version "{1}" was resolved to version "{2}" instead. You could be using a different version than expected if you do not update the referenced version to match. loggingContext.LogWarning(null, new BuildEventFileInfo(sdkReferenceLocation), "SdkResultVersionDifferentThanReference", sdk.Name, sdk.Version, sdkResult.Version); } // Associate the element location of the resolved SDK reference sdkResult.ElementLocation = sdkReferenceLocation; } return(sdkResult); }
private SdkResult RequestSdkPathFromMainNode(int submissionId, SdkReference sdk, LoggingContext loggingContext, ElementLocation sdkReferenceLocation, string solutionPath, string projectPath, bool interactive) { // Clear out the last response for good measure _lastResponse = null; // Create the SdkResolverRequest packet to send INodePacket packet = SdkResolverRequest.Create(submissionId, sdk, loggingContext.BuildEventContext, sdkReferenceLocation, solutionPath, projectPath, interactive); SendPacket(packet); // Wait for either the response or a shutdown event. Either event means this thread should return WaitHandle.WaitAny(new WaitHandle[] { _responseReceivedEvent, ShutdownEvent }); // Keep track of the element location of the reference _lastResponse.ElementLocation = sdkReferenceLocation; // Return the response which was set by another thread. In the case of shutdown, it should be null. return(_lastResponse); }
public override void PacketReceived(int node, INodePacket packet) { if (packet is not SdkResolverRequest request) { return; } // Associate the node with the request request.NodeId = node; SdkResult response = null; try { // Create an SdkReference from the request SdkReference sdkReference = new SdkReference(request.Name, request.Version, request.MinimumVersion); ILoggingService loggingService = Host.GetComponent(BuildComponentType.LoggingService) as ILoggingService; // This call is usually cached so is very fast but can take longer for a new SDK that is downloaded. Other queued threads for different SDKs will complete sooner and continue on which unblocks evaluations response = ResolveSdk(request.SubmissionId, sdkReference, new EvaluationLoggingContext(loggingService, request.BuildEventContext, request.ProjectPath), request.ElementLocation, request.SolutionPath, request.ProjectPath, request.Interactive, request.IsRunningInVisualStudio); } catch (Exception e) { ILoggingService loggingService = Host.GetComponent(BuildComponentType.LoggingService) as ILoggingService; EvaluationLoggingContext loggingContext = new EvaluationLoggingContext(loggingService, request.BuildEventContext, request.ProjectPath); loggingService.LogFatalBuildError(loggingContext.BuildEventContext, e, new BuildEventFileInfo(request.ElementLocation)); } finally { // Get the node manager and send the response back to the node that requested the SDK INodeManager nodeManager = Host.GetComponent(BuildComponentType.NodeManager) as INodeManager; nodeManager.SendData(request.NodeId, response); } }
private static void LogWarnings(LoggingContext loggingContext, ElementLocation location, SdkResult result) { if (result.Warnings == null) { return; } foreach (string warning in result.Warnings) { loggingContext.LogWarningFromText(null, null, null, new BuildEventFileInfo(location), warning); } }
/// <inheritdoc cref="ISdkResolverService.ResolveSdk"/> public override string ResolveSdk(int submissionId, SdkReference sdk, LoggingContext loggingContext, ElementLocation sdkReferenceLocation, string solutionPath, string projectPath) { SdkResult result = GetSdkResultAndCache(submissionId, sdk, loggingContext, sdkReferenceLocation, solutionPath, projectPath); return(result?.Path); }
public ConfigurableMockSdkResolver(SdkResult result) { _resultMap = new Dictionary <string, SdkResult> { [result.SdkReference.Name] = result }; }
private bool TryResolveSdkUsingSpecifiedResolvers(IList <SdkResolver> resolvers, int submissionId, SdkReference sdk, LoggingContext loggingContext, ElementLocation sdkReferenceLocation, string solutionPath, string projectPath, bool interactive, bool isRunningInVisualStudio, out SdkResult sdkResult) { List <SdkResult> results = new List <SdkResult>(); // Loop through resolvers which have already been sorted by priority, returning the first result that was successful SdkLogger buildEngineLogger = new SdkLogger(loggingContext); loggingContext.LogComment(MessageImportance.Low, "SdkResolving", sdk.ToString()); foreach (SdkResolver sdkResolver in resolvers) { SdkResolverContext context = new SdkResolverContext(buildEngineLogger, projectPath, solutionPath, ProjectCollection.Version, interactive, isRunningInVisualStudio) { State = GetResolverState(submissionId, sdkResolver) }; SdkResultFactory resultFactory = new SdkResultFactory(sdk); SdkResult result; try { MSBuildEventSource.Log.SdkResolverResolveSdkStart(); result = (SdkResult)sdkResolver.Resolve(sdk, context, resultFactory); MSBuildEventSource.Log.SdkResolverResolveSdkStop(sdkResolver.Name, sdk.Name, solutionPath, projectPath, result?.Path, result?.Success ?? false); } catch (Exception e) when((e is FileNotFoundException || e is FileLoadException) && sdkResolver.GetType().GetTypeInfo().Name.Equals("NuGetSdkResolver", StringComparison.Ordinal)) { // Since we explicitly add the NuGetSdkResolver, we special case this. The NuGetSdkResolver has special logic // to load NuGet assemblies at runtime which could fail if the user is not running installed MSBuild. Rather // than give them a generic error, we want to give a more specific message. This exception cannot be caught by // the resolver itself because it is usually thrown before the class is loaded // The NuGet-based SDK resolver failed to run because NuGet assemblies could not be located. Check your installation of MSBuild or set the environment variable "{0}" to the folder that contains the required NuGet assemblies. {1} throw new SdkResolverException("CouldNotRunNuGetSdkResolver", sdkResolver, sdk, e, MSBuildConstants.NuGetAssemblyPathEnvironmentVariableName, e.ToString()); } catch (Exception e) { // The SDK resolver "{0}" failed while attempting to resolve the SDK "{1}": {2} throw new SdkResolverException("SDKResolverFailed", sdkResolver, sdk, e, sdkResolver.Name, sdk.ToString(), e.ToString()); } SetResolverState(submissionId, sdkResolver, context.State); if (result == null) { continue; } if (result.Success) { LogWarnings(loggingContext, sdkReferenceLocation, result); if (!IsReferenceSameVersion(sdk, result.Version)) { // MSB4241: The SDK reference "{0}" version "{1}" was resolved to version "{2}" instead. You could be using a different version than expected if you do not update the referenced version to match. loggingContext.LogWarning(null, new BuildEventFileInfo(sdkReferenceLocation), "SdkResultVersionDifferentThanReference", sdk.Name, sdk.Version, result.Version); } // Associate the element location of the resolved SDK reference result.ElementLocation = sdkReferenceLocation; sdkResult = result; return(true); } results.Add(result); } foreach (SdkResult result in results) { LogWarnings(loggingContext, sdkReferenceLocation, result); if (result.Errors != null) { foreach (string error in result.Errors) { loggingContext.LogErrorFromText(subcategoryResourceName: null, errorCode: null, helpKeyword: null, file: new BuildEventFileInfo(sdkReferenceLocation), message: error); } } } sdkResult = new SdkResult(sdk, null, null); return(false); }