/// <summary> /// Read the provided binary log file and raise corresponding events for each BuildEventArgs /// </summary> /// <param name="sourceFilePath">The full file path of the binary log file</param> /// <param name="cancellationToken">A <see cref="CancellationToken"/> indicating the replay should stop as soon as possible.</param> public void Replay(string sourceFilePath, CancellationToken cancellationToken) { using (var stream = new FileStream(sourceFilePath, FileMode.Open, FileAccess.Read, FileShare.Read)) { var gzipStream = new GZipStream(stream, CompressionMode.Decompress, leaveOpen: true); var binaryReader = new BinaryReader(gzipStream); int fileFormatVersion = binaryReader.ReadInt32(); // the log file is written using a newer version of file format // that we don't know how to read if (fileFormatVersion > BinaryLogger.FileFormatVersion) { var text = ResourceUtilities.FormatResourceString("UnsupportedLogFileFormat", fileFormatVersion, BinaryLogger.FileFormatVersion); throw new NotSupportedException(text); } var reader = new BuildEventArgsReader(binaryReader, fileFormatVersion); while (true) { if (cancellationToken.IsCancellationRequested) { return; } BuildEventArgs instance = null; instance = reader.Read(); if (instance == null) { break; } Dispatch(instance); } } }
/// <summary> /// Instantiates a new MSBuild process acting as a child node. /// </summary> public bool CreateNode(int nodeId, INodePacketFactory factory, NodeConfiguration configuration) { ErrorUtilities.VerifyThrowArgumentNull(factory, "factory"); if (_nodeContexts.Count == ComponentHost.BuildParameters.MaxNodeCount) { ErrorUtilities.ThrowInternalError("All allowable nodes already created ({0}).", _nodeContexts.Count); return(false); } // Start the new process. We pass in a node mode with a node number of 1, to indicate that we // want to start up just a standard MSBuild out-of-proc node. // Note: We need to always pass /nodeReuse to ensure the value for /nodeReuse from msbuild.rsp // (next to msbuild.exe) is ignored. string commandLineArgs = ComponentHost.BuildParameters.EnableNodeReuse ? "/nologo /nodemode:1 /nodeReuse:true" : "/nologo /nodemode:1 /nodeReuse:false"; // Make it here. CommunicationsUtilities.Trace("Starting to acquire a new or existing node to establish node ID {0}...", nodeId); NodeContext context = GetNode(null, commandLineArgs, nodeId, factory, NodeProviderOutOfProc.GetHostHandshake(ComponentHost.BuildParameters.EnableNodeReuse), NodeProviderOutOfProc.GetClientHandshake(), NodeContextTerminated); if (null != context) { _nodeContexts[nodeId] = context; // Start the asynchronous read. context.BeginAsyncPacketRead(); // Configure the node. context.SendData(configuration); return(true); } throw new BuildAbortedException(ResourceUtilities.FormatResourceString("CouldNotConnectToMSBuildExe", ComponentHost.BuildParameters.NodeExeLocation)); }
public void VerifyInvalidProjectSchema ( ) { string[] msbuildTempXsdFilenames = new string[] {}; try { // Create schema files in the temp folder msbuildTempXsdFilenames = PrepareSchemaFiles(); string projectContents = @" <Project xmlns=`msbuildnamespace`> <MyInvalidTag/> <Target Name=`Build` /> </Project> "; Engine buildEngine = new Engine(@"c:\"); ProjectSchemaValidationHandler validator = new ProjectSchemaValidationHandler(null, buildEngine.LoggingServices, @"c:\"); try { validator.VerifyProjectSchema(ObjectModelHelpers.CleanupFileContents(projectContents), msbuildTempXsdFilenames[0]); } catch (InvalidProjectFileException e) { Assertion.AssertEquals(e.BaseMessage, ResourceUtilities.FormatResourceString("ProjectSchemaErrorHalt")); throw; } } finally { CleanupSchemaFiles(msbuildTempXsdFilenames); } }
public void Initialize(IEventSource eventSource) { ErrorUtilities.VerifyThrowArgumentNull(eventSource, nameof(eventSource)); ParseFileLoggerParameters(); string fileName = logFile; try { // Create a new file logger and pass it some parameters to make the build log very detailed nodeFileLogger = new FileLogger(); string extension = Path.GetExtension(logFile); // If there is no extension add a default of .log to it if (String.IsNullOrEmpty(extension)) { logFile += ".log"; extension = ".log"; } // Log 0-based node id's, where 0 is the parent. This is a little unnatural for the reader, // but avoids confusion by being consistent with the Engine and any error messages it may produce. fileName = logFile.Replace(extension, nodeId + extension); nodeFileLogger.Verbosity = LoggerVerbosity.Detailed; nodeFileLogger.Parameters = "ShowEventId;ShowCommandLine;logfile=" + fileName + ";" + parameters; } catch (ArgumentException e) // Catching Exception, but rethrowing unless it's a well-known exception. { nodeFileLogger?.Shutdown(); string errorCode; string helpKeyword; string message = ResourceUtilities.FormatResourceString(out errorCode, out helpKeyword, "InvalidFileLoggerFile", fileName, e.Message); throw new LoggerException(message, e, errorCode, helpKeyword); } // Say we are operating on 2 processors so we can get the multiproc output nodeFileLogger.Initialize(eventSource, 2); }
/// <summary> /// Gets the working directory to use for the process. Should return null if ToolTask should use the /// current directory. /// May throw an IOException if the directory to be used is somehow invalid. /// </summary> /// <returns>working directory</returns> protected override string GetWorkingDirectory() { // If the working directory is UNC, we're going to use "pushd" in the batch file to set it. // If it's invalid, pushd won't fail: it will just go ahead and use the system folder. // So verify it's valid here. if (!Directory.Exists(_workingDirectory)) { throw new DirectoryNotFoundException(ResourceUtilities.FormatResourceString("Exec.InvalidWorkingDirectory", _workingDirectory)); } if (workingDirectoryIsUNC) { // if the working directory for the exec command is UNC, set the process working directory to the system path // so that it doesn't display this silly error message: // '\\<server>\<share>' // CMD.EXE was started with the above path as the current directory. // UNC paths are not supported. Defaulting to Windows directory. return(ToolLocationHelper.PathToSystem); } else { return(_workingDirectory); } }
/// <summary> /// Apply the verbosity value /// </summary> private bool ApplyVerbosityParameter(string parameterValue) { switch (parameterValue.ToUpperInvariant()) { case "Q": case "QUIET": Verbosity = LoggerVerbosity.Quiet; return(true); case "M": case "MINIMAL": Verbosity = LoggerVerbosity.Minimal; return(true); case "N": case "NORMAL": Verbosity = LoggerVerbosity.Normal; return(true); case "D": case "DETAILED": Verbosity = LoggerVerbosity.Detailed; return(true); case "DIAG": case "DIAGNOSTIC": Verbosity = LoggerVerbosity.Diagnostic; return(true); default: string errorCode; string helpKeyword; string message = ResourceUtilities.FormatResourceString(out errorCode, out helpKeyword, "InvalidVerbosity", parameterValue); throw new LoggerException(message, null, errorCode, helpKeyword); } }
private bool ParseAsContentOrFile(string contentOrFile, string desiredRule) { // On Windows: // - xml string will be an invalid file path, so, Path.GetFullPath will // return null // - xml string cannot be a rooted path ("C:\\<abc />") // // On Unix: // - xml string is a valid path, this is not a definite check as Path.GetFullPath // will return !null in most cases // - xml string cannot be a rooted path ("/foo/<abc />") bool isRootedPath = false; string maybeFullPath = null; try { isRootedPath = Path.IsPathRooted(contentOrFile); if (!isRootedPath) { maybeFullPath = Path.GetFullPath(contentOrFile); } } catch (Exception e) { if (ExceptionHandling.IsCriticalException(e)) { throw; } // We will get an exception if the contents are not a path (for instance, they are actual XML.) } if (isRootedPath) { // valid *absolute* file path if (!File.Exists(contentOrFile)) { throw new ArgumentException(ResourceUtilities.FormatResourceString("Xaml.RuleFileNotFound", contentOrFile)); } return(ParseXamlDocument(new StreamReader(contentOrFile), desiredRule)); } // On Windows, xml content string is not a valid path, so, maybeFullPath == null // On Unix, xml content string would be a valid path, so, maybeFullPath != null if (maybeFullPath == null) { // Unable to convert to a path, parse as XML return(ParseXamlDocument(new StringReader(contentOrFile), desiredRule)); } if (File.Exists(maybeFullPath)) { // file found, parse as a file return(ParseXamlDocument(new StreamReader(maybeFullPath), desiredRule)); } // @maybeFullPath is either: // - a non-existent fullpath // - or xml content with the current dir prepended (like "/foo/bar/<abc .. />"), // but not on Windows // // On Windows, this means that @contentOrFile is really a non-existant file name if (NativeMethodsShared.IsWindows) { throw new ArgumentException(ResourceUtilities.FormatResourceString("Xaml.RuleFileNotFound", maybeFullPath)); } else // On !Windows, try parsing as XML { return(ParseXamlDocument(new StringReader(contentOrFile), desiredRule)); } }
/// <summary> /// Creates a new MSBuild process /// </summary> private int LaunchNode(string msbuildLocation, string commandLineArgs) { // Should always have been set already. ErrorUtilities.VerifyThrowInternalLength(msbuildLocation, "msbuildLocation"); if (!File.Exists(msbuildLocation)) { throw new BuildAbortedException(ResourceUtilities.FormatResourceString("CouldNotFindMSBuildExe", msbuildLocation)); } // Repeat the executable name as the first token of the command line because the command line // parser logic expects it and will otherwise skip the first argument commandLineArgs = msbuildLocation + " " + commandLineArgs; BackendNativeMethods.STARTUP_INFO startInfo = new BackendNativeMethods.STARTUP_INFO(); startInfo.cb = Marshal.SizeOf <BackendNativeMethods.STARTUP_INFO>(); // Null out the process handles so that the parent process does not wait for the child process // to exit before it can exit. uint creationFlags = 0; if (Traits.Instance.EscapeHatches.EnsureStdOutForChildNodesIsPrimaryStdout) { creationFlags = BackendNativeMethods.NORMALPRIORITYCLASS; } if (String.IsNullOrEmpty(Environment.GetEnvironmentVariable("MSBUILDNODEWINDOW"))) { if (!Traits.Instance.EscapeHatches.EnsureStdOutForChildNodesIsPrimaryStdout) { // Redirect the streams of worker nodes so that this MSBuild.exe's // parent doesn't wait on idle worker nodes to close streams // after the build is complete. startInfo.hStdError = BackendNativeMethods.InvalidHandle; startInfo.hStdInput = BackendNativeMethods.InvalidHandle; startInfo.hStdOutput = BackendNativeMethods.InvalidHandle; startInfo.dwFlags = BackendNativeMethods.STARTFUSESTDHANDLES; creationFlags = creationFlags | BackendNativeMethods.CREATENOWINDOW; } } else { creationFlags = creationFlags | BackendNativeMethods.CREATE_NEW_CONSOLE; } BackendNativeMethods.SECURITY_ATTRIBUTES processSecurityAttributes = new BackendNativeMethods.SECURITY_ATTRIBUTES(); BackendNativeMethods.SECURITY_ATTRIBUTES threadSecurityAttributes = new BackendNativeMethods.SECURITY_ATTRIBUTES(); processSecurityAttributes.nLength = Marshal.SizeOf <BackendNativeMethods.SECURITY_ATTRIBUTES>(); threadSecurityAttributes.nLength = Marshal.SizeOf <BackendNativeMethods.SECURITY_ATTRIBUTES>(); CommunicationsUtilities.Trace("Launching node from {0}", msbuildLocation); string exeName = msbuildLocation; #if RUNTIME_TYPE_NETCORE // Run the child process with the same host as the currently-running process. exeName = GetCurrentHost(); commandLineArgs = "\"" + msbuildLocation + "\" " + commandLineArgs; #endif if (!NativeMethodsShared.IsWindows) { ProcessStartInfo processStartInfo = new ProcessStartInfo(); processStartInfo.FileName = exeName; processStartInfo.Arguments = commandLineArgs; if (!Traits.Instance.EscapeHatches.EnsureStdOutForChildNodesIsPrimaryStdout) { // Redirect the streams of worker nodes so that this MSBuild.exe's // parent doesn't wait on idle worker nodes to close streams // after the build is complete. processStartInfo.RedirectStandardInput = true; processStartInfo.RedirectStandardOutput = true; processStartInfo.RedirectStandardError = true; processStartInfo.CreateNoWindow = (creationFlags | BackendNativeMethods.CREATENOWINDOW) == BackendNativeMethods.CREATENOWINDOW; } processStartInfo.UseShellExecute = false; Process process; try { process = Process.Start(processStartInfo); } catch (Exception ex) { CommunicationsUtilities.Trace ( "Failed to launch node from {0}. CommandLine: {1}" + Environment.NewLine + "{2}", msbuildLocation, commandLineArgs, ex.ToString() ); throw new NodeFailedToLaunchException(ex); } CommunicationsUtilities.Trace("Successfully launched msbuild.exe node with PID {0}", process.Id); return(process.Id); } else { #if RUNTIME_TYPE_NETCORE if (NativeMethodsShared.IsWindows) { // Repeat the executable name in the args to suit CreateProcess commandLineArgs = "\"" + exeName + "\" " + commandLineArgs; } #endif BackendNativeMethods.PROCESS_INFORMATION processInfo = new BackendNativeMethods.PROCESS_INFORMATION(); bool result = BackendNativeMethods.CreateProcess ( exeName, commandLineArgs, ref processSecurityAttributes, ref threadSecurityAttributes, #if FEATURE_NAMED_PIPES_FULL_DUPLEX false, #else true, // Inherit handles for the anonymous pipes for IPC #endif creationFlags, BackendNativeMethods.NullPtr, null, ref startInfo, out processInfo ); if (!result) { // Creating an instance of this exception calls GetLastWin32Error and also converts it to a user-friendly string. System.ComponentModel.Win32Exception e = new System.ComponentModel.Win32Exception(); CommunicationsUtilities.Trace ( "Failed to launch node from {0}. System32 Error code {1}. Description {2}. CommandLine: {2}", msbuildLocation, e.NativeErrorCode.ToString(CultureInfo.InvariantCulture), e.Message, commandLineArgs ); throw new NodeFailedToLaunchException(e.NativeErrorCode.ToString(CultureInfo.InvariantCulture), e.Message); } int childProcessId = processInfo.dwProcessId; if (processInfo.hProcess != IntPtr.Zero && processInfo.hProcess != NativeMethods.InvalidHandle) { NativeMethodsShared.CloseHandle(processInfo.hProcess); } if (processInfo.hThread != IntPtr.Zero && processInfo.hThread != NativeMethods.InvalidHandle) { NativeMethodsShared.CloseHandle(processInfo.hThread); } CommunicationsUtilities.Trace("Successfully launched msbuild.exe node with PID {0}", childProcessId); return(childProcessId); } }
/// <summary> /// This function will start a node and send requests to it /// </summary> private void LaunchNodeAndPostBuildRequest() { int nodeIndex = 0; // Find out what node to launch lock (nodesToLaunch) { nodeIndex = nodesToLaunch.Dequeue(); } // If the provider is shutting down - don't launch the node if (shuttingDown) { nodeData[nodeIndex].NodeState = NodeState.NotLaunched; return; } try { // Either launch node or connect to an already running node InitializeNode(nodeIndex); if (!nodeData[nodeIndex].CommunicationFailed) { // Change the state of the node to launched lock (nodeStateLock) { nodeData[nodeIndex].NodeState = NodeState.Launched; } // Send all the requests to the node. Note that the requests may end up in // mixed order with the request currently being posted. LinkedListNode <BuildRequest> current = nodeData[nodeIndex].TargetList.First; BuildRequest[] buildRequests = new BuildRequest[nodeData[nodeIndex].TargetList.Count]; int i = 0; while (current != null) { buildRequests[i] = current.Value; i++; current = current.Next; } LocalCallDescriptorForPostBuildRequests callDescriptor = new LocalCallDescriptorForPostBuildRequests(buildRequests); nodeData[nodeIndex].NodeCommandQueue.Enqueue(callDescriptor); nodeData[nodeIndex].TargetList = null; } else { // Allow the engine to decide how to proceed since the node failed to launch string message = ResourceUtilities.FormatResourceString("NodeProviderFailure"); ReportNodeCommunicationFailure(nodeIndex, new Exception(message), false); } } catch (Exception e) { // Allow the engine to deal with the exception ReportNodeCommunicationFailure(nodeIndex, e, false); } }
/// <summary> /// Apply a logger parameter. /// parameterValue may be null, if there is no parameter value. /// </summary> internal virtual bool ApplyParameter(string parameterName, string parameterValue) { ErrorUtilities.VerifyThrowArgumentNull(parameterName, "parameterName"); switch (parameterName.ToUpperInvariant()) { case "PERFORMANCESUMMARY": showPerfSummary = true; return(true); case "NOSUMMARY": showSummary = false; return(true); case "SUMMARY": showSummary = true; return(true); case "NOITEMANDPROPERTYLIST": showItemAndPropertyList = false; return(true); case "WARNINGSONLY": showOnlyWarnings = true; return(true); case "ERRORSONLY": showOnlyErrors = true; return(true); case "V": case "VERBOSITY": { switch (parameterValue.ToUpperInvariant()) { case "Q": case "QUIET": verbosity = LoggerVerbosity.Quiet; return(true); case "M": case "MINIMAL": verbosity = LoggerVerbosity.Minimal; return(true); case "N": case "NORMAL": verbosity = LoggerVerbosity.Normal; return(true); case "D": case "DETAILED": verbosity = LoggerVerbosity.Detailed; return(true); case "DIAG": case "DIAGNOSTIC": verbosity = LoggerVerbosity.Diagnostic; return(true); default: string errorCode; string helpKeyword; string message = ResourceUtilities.FormatResourceString(out errorCode, out helpKeyword, "InvalidVerbosity", parameterValue); throw new LoggerException(message, null, errorCode, helpKeyword); } } } return(false); }
private void NodeLocalEngineLoop() { buildInProgress = true; // Create a logging service for this build request localEngine = new Engine(parentGlobalProperties, toolsetSearchLocations, 1 /* cpus */, true /* child node */, this.nodeId, parentStartupDirectory, null); localEngine.Router.ChildMode = true; localEngine.Router.ParentNode = this; this.outProcLoggingService = new EngineLoggingServicesOutProc(this, localEngine.FlushRequestEvent); if (nodeLoggers.Length != 0) { foreach (LoggerDescription loggerDescription in nodeLoggers) { IForwardingLogger newLogger = null; bool exitedDueToError = true; try { newLogger = loggerDescription.CreateForwardingLogger(); // Check if the class was not found in the assembly if (newLogger == null) { InternalLoggerException.Throw(null, null, "FatalErrorWhileInitializingLogger", true, loggerDescription.Name); } newLogger.Verbosity = loggerDescription.Verbosity; newLogger.Parameters = loggerDescription.LoggerSwitchParameters; newLogger.NodeId = nodeId; EventRedirector newRedirector = new EventRedirector(loggerDescription.LoggerId, outProcLoggingService); newLogger.BuildEventRedirector = newRedirector; exitedDueToError = false; } // Polite logger failure catch (LoggerException e) { ReportUnhandledError(e); } // Logger class was not found catch (InternalLoggerException e) { ReportUnhandledError(e); } catch (Exception e) { // Wrap the exception in a InternalLoggerException and send it to the parent node string errorCode; string helpKeyword; string message = ResourceUtilities.FormatResourceString(out errorCode, out helpKeyword, "FatalErrorWhileInitializingLogger", loggerDescription.Name); ReportUnhandledError(new InternalLoggerException(message, e, null, errorCode, helpKeyword, true)); } // If there was a failure registering loggers, null out the engine pointer if (exitedDueToError) { localEngine = null; return; } localEngine.RegisterLogger(newLogger); } localEngine.ExternalLoggingServices = outProcLoggingService; } // Hook up logging service to forward all events to the central engine if necessary if (centralizedLogging) { if (nodeLoggers.Length != 0) { localEngine.LoggingServices.ForwardingService = outProcLoggingService; localEngine.ExternalLoggingServices = outProcLoggingService; } else { localEngine.LoggingServices = outProcLoggingService; } } localEngine.LoggingServices.OnlyLogCriticalEvents = this.logOnlyCriticalEvents; if (!useBreadthFirstTraversal) { localEngine.PostEngineCommand(new ChangeTraversalTypeCommand(useBreadthFirstTraversal, true)); } // Post all the requests that passed in while the engine was being constructed // into the engine queue lock (buildRequests) { while (buildRequests.Count != 0) { BuildRequest buildRequest = buildRequests.Dequeue(); localEngine.PostBuildRequest(buildRequest); } } try { // If there are forwarding loggers registered - generate a custom build started if (nodeLoggers.Length > 0) { localEngine.LoggingServices.LogBuildStarted(EngineLoggingServicesInProc.CENTRAL_ENGINE_EVENTSOURCE); localEngine.LoggingServices.ProcessPostedLoggingEvents(); } // Trigger the actual build if shutdown was not called while the engine was being initialized if (!nodeShutdown) { localEngine.EngineBuildLoop(null); } } catch (Exception e) { // Unhandled exception during execution. The node has to be shutdown. ReportUnhandledError(e); } finally { if (localEngine != null) { // Flush all the messages associated before shutting down localEngine.LoggingServices.ProcessPostedLoggingEvents(); NodeManager nodeManager = localEngine.NodeManager; // If the local engine is already shutting down, the TEM will be nulled out if (nodeManager.TaskExecutionModule != null && nodeManager.TaskExecutionModule.TaskExecutionTime != 0) { TimeSpan taskTimeSpan = new TimeSpan(localEngine.NodeManager.TaskExecutionModule.TaskExecutionTime); totalTaskTime = (int)taskTimeSpan.TotalMilliseconds; } localEngine.Shutdown(); } // Flush all the events to the parent engine outProcLoggingService.ProcessPostedLoggingEvents(); // Indicate that the node logger thread should exit exitNodeEvent.Set(); } }
/// <summary> /// Finds or creates a child process which can act as a node. /// </summary> /// <returns>The pipe stream representing the node.</returns> protected NodeContext GetNode(string msbuildLocation, string commandLineArgs, int nodeId, INodePacketFactory factory, long hostHandshake, long clientHandshake, NodeContextTerminateDelegate terminateNode) { if (String.IsNullOrEmpty(msbuildLocation)) { msbuildLocation = _componentHost.BuildParameters.NodeExeLocation; } if (String.IsNullOrEmpty(msbuildLocation)) { string msbuildExeName = Environment.GetEnvironmentVariable("MSBUILD_EXE_NAME"); if (!String.IsNullOrEmpty(msbuildExeName)) { // we assume that MSBUILD_EXE_NAME is, in fact, just the name. msbuildLocation = Path.Combine(msbuildExeName, ".exe"); } } if (String.IsNullOrEmpty(msbuildLocation)) { msbuildLocation = "MSBuild.exe"; } string msbuildName = Path.GetFileNameWithoutExtension(msbuildLocation); List <Process> nodeProcesses = new List <Process>(Process.GetProcessesByName(msbuildName)); // Trivial sort to try to prefer most recently used nodes nodeProcesses.Sort ( delegate(Process left, Process right) { return(left.Id - right.Id); } ); CommunicationsUtilities.Trace("Attempting to connect to each existing msbuild.exe process in turn to establish node {0}...", nodeId); foreach (Process nodeProcess in nodeProcesses) { if (nodeProcess.Id == Process.GetCurrentProcess().Id) { continue; } // Get the full context of this inspection so that we can always skip this process when we have the same taskhost context string nodeLookupKey = GetProcessesToIgnoreKey(hostHandshake, clientHandshake, nodeProcess.Id); if (_processesToIgnore.Contains(nodeLookupKey)) { continue; } // We don't need to check this again _processesToIgnore.Add(nodeLookupKey); // Attempt to connect to each process in turn. NamedPipeClientStream nodeStream = TryConnectToProcess(nodeProcess.Id, 0 /* poll, don't wait for connections */, hostHandshake, clientHandshake); if (nodeStream != null) { // Connection successful, use this node. CommunicationsUtilities.Trace("Successfully connected to existed node {0} which is PID {1}", nodeId, nodeProcess.Id); return(new NodeContext(nodeId, nodeProcess.Id, nodeStream, factory, terminateNode)); } } // None of the processes we tried to connect to allowed a connection, so create a new one. // We try this in a loop because it is possible that there is another MSBuild multiproc // host process running somewhere which is also trying to create nodes right now. It might // find our newly created node and connect to it before we get a chance. CommunicationsUtilities.Trace("Could not connect to existing process, now creating a process..."); int retries = NodeCreationRetries; while (retries-- > 0) { // We will also check to see if .NET 3.5 is installed in the case where we need to launch a CLR2 OOP TaskHost. // Failure to detect this has been known to stall builds when Windows pops up a related dialog. // It's also a waste of time when we attempt several times to launch multiple MSBuildTaskHost.exe (CLR2 TaskHost) // nodes because we should never be able to connect in this case. string taskHostNameForClr2TaskHost = Path.GetFileNameWithoutExtension(NodeProviderOutOfProcTaskHost.TaskHostNameForClr2TaskHost); if (msbuildName.Equals(taskHostNameForClr2TaskHost, StringComparison.OrdinalIgnoreCase)) { if (FrameworkLocationHelper.GetPathToDotNetFrameworkV35(DotNetFrameworkArchitecture.Current) == null) { CommunicationsUtilities.Trace ( "Failed to launch node from {0}. The required .NET Framework v3.5 is not installed or enabled. CommandLine: {1}", msbuildLocation, commandLineArgs ); string nodeFailedToLaunchError = ResourceUtilities.FormatResourceString("TaskHostNodeFailedToLaunchErrorCodeNet35NotInstalled"); throw new NodeFailedToLaunchException(null, nodeFailedToLaunchError); } } // Create the node process int msbuildProcessId = LaunchNode(msbuildLocation, commandLineArgs); _processesToIgnore.Add(GetProcessesToIgnoreKey(hostHandshake, clientHandshake, msbuildProcessId)); // Note, when running under IMAGEFILEEXECUTIONOPTIONS registry key to debug, the process ID // gotten back from CreateProcess is that of the debugger, which causes this to try to connect // to the debugger process. Instead, use MSBUILDDEBUGONSTART=1 // Now try to connect to it. NamedPipeClientStream nodeStream = TryConnectToProcess(msbuildProcessId, TimeoutForNewNodeCreation, hostHandshake, clientHandshake); if (nodeStream != null) { // Connection successful, use this node. CommunicationsUtilities.Trace("Successfully connected to created node {0} which is PID {1}", nodeId, msbuildProcessId); return(new NodeContext(nodeId, msbuildProcessId, nodeStream, factory, terminateNode)); } } // We were unable to launch a node. CommunicationsUtilities.Trace("FAILED TO CONNECT TO A CHILD NODE"); return(null); }
/// <summary> /// Instructs the MSBuild engine to build one or more project files whose locations are specified by the /// <see cref="Projects"/> property. /// </summary> /// <returns>true if all projects build successfully; false if any project fails</returns> public async Task <bool> ExecuteInternal() { // If no projects were passed in, just return success. if ((Projects == null) || (Projects.Length == 0)) { return(true); } // We have been asked to unescape all escaped characters before processing if (this.TargetAndPropertyListSeparators != null && this.TargetAndPropertyListSeparators.Length > 0) { ExpandAllTargetsAndProperties(); } // Parse the global properties into a hashtable. Hashtable propertiesTable; if (!PropertyParser.GetTableWithEscaping(Log, ResourceUtilities.FormatResourceString("General.GlobalProperties"), "Properties", this.Properties, out propertiesTable)) { return(false); } // Parse out the properties to undefine, if any. string[] undefinePropertiesArray = null; if (!String.IsNullOrEmpty(_undefineProperties)) { Log.LogMessageFromResources(MessageImportance.Low, "General.UndefineProperties"); undefinePropertiesArray = _undefineProperties.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); foreach (string property in undefinePropertiesArray) { Log.LogMessageFromText(String.Format(CultureInfo.InvariantCulture, " {0}", property), MessageImportance.Low); } } bool isRunningMultipleNodes = BuildEngine2.IsRunningMultipleNodes; // If we are in single proc mode and stopOnFirstFailure is true, we cannot build in parallel because // building in parallel sends all of the projects to the engine at once preventing us from not sending // any more projects after the first failure. Therefore, to preserve compatibility with whidbey if we are in this situation disable buildInParallel. if (!isRunningMultipleNodes && _stopOnFirstFailure && _buildInParallel) { _buildInParallel = false; Log.LogMessageFromResources(MessageImportance.Low, "MSBuild.NotBuildingInParallel"); } // When the condition below is met, provide an information message indicating stopOnFirstFailure // will have no effect. The reason there will be no effect is, when buildInParallel is true // All project files will be submitted to the engine all at once, this mean there is no stopping for failures between projects. // When RunEachTargetSeparately is false, all targets will be submitted to the engine at once, this means there is no way to stop between target failures. // therefore the first failure seen will be the only failure seen. if (isRunningMultipleNodes && _buildInParallel && _stopOnFirstFailure && !_runEachTargetSeparately) { Log.LogMessageFromResources(MessageImportance.Low, "MSBuild.NoStopOnFirstFailure"); } // This is a list of string[]. That is, each element in the list is a string[]. Each // string[] represents a set of target names to build. Depending on the value // of the RunEachTargetSeparately parameter, we each just call the engine to run all // the targets together, or we call the engine separately for each target. ArrayList targetLists = CreateTargetLists(this.Targets, this.RunEachTargetSeparately); bool success = true; ITaskItem[] singleProject = null; bool[] skipProjects = null; if (_buildInParallel) { skipProjects = new bool[Projects.Length]; for (int i = 0; i < skipProjects.Length; i++) { skipProjects[i] = true; } } else { singleProject = new ITaskItem[1]; } // Read in each project file. If there are any errors opening the file or parsing the XML, // raise an event and return False. If any one of the projects fails to build, return False, // otherwise return True. If parallel build is requested we first check for file existence so // that we don't pass a non-existent file to IBuildEngine causing an exception for (int i = 0; i < Projects.Length; i++) { ITaskItem project = Projects[i]; string projectPath = FileUtilities.AttemptToShortenPath(project.ItemSpec); if (_stopOnFirstFailure && !success) { // Inform the user that we skipped the remaining projects because StopOnFirstFailure=true. Log.LogMessageFromResources(MessageImportance.Low, "MSBuild.SkippingRemainingProjects"); // We have encountered a failure. Caller has requested that we not // continue with remaining projects. break; } if (File.Exists(projectPath) || (_skipNonexistentProjects == SkipNonexistentProjectsBehavior.Build)) { if (FileUtilities.IsVCProjFilename(projectPath)) { Log.LogErrorWithCodeFromResources("MSBuild.ProjectUpgradeNeededToVcxProj", project.ItemSpec); success = false; continue; } // If we are building in parallel we want to only make one call to // ExecuteTargets once we verified that all projects exist if (!_buildInParallel) { singleProject[0] = project; bool executeResult = await ExecuteTargets( singleProject, propertiesTable, undefinePropertiesArray, targetLists, StopOnFirstFailure, RebaseOutputs, BuildEngine3, Log, _targetOutputs, _useResultsCache, _unloadProjectsOnCompletion, ToolsVersion ); if (!executeResult) { success = false; } } else { skipProjects[i] = false; } } else { if (_skipNonexistentProjects == SkipNonexistentProjectsBehavior.Skip) { Log.LogMessageFromResources(MessageImportance.High, "MSBuild.ProjectFileNotFoundMessage", project.ItemSpec); } else { ErrorUtilities.VerifyThrow(_skipNonexistentProjects == SkipNonexistentProjectsBehavior.Error, "skipNonexistentProjects has unexpected value {0}", _skipNonexistentProjects); Log.LogErrorWithCodeFromResources("MSBuild.ProjectFileNotFound", project.ItemSpec); success = false; } } } // We need to build all the projects that were not skipped if (_buildInParallel) { success = await BuildProjectsInParallel(propertiesTable, undefinePropertiesArray, targetLists, success, skipProjects); } return(success); }
/// <summary> /// Reads a plan for the specified submission Id. /// </summary> public void ReadPlan(int submissionId, ILoggingService loggingService, BuildEventContext buildEventContext) { if (!BuildParameters.EnableBuildPlan) { return; } SchedulableRequest rootRequest = GetRootRequest(submissionId); if (rootRequest == null) { return; } string planName = GetPlanName(rootRequest); if (String.IsNullOrEmpty(planName)) { return; } if (!File.Exists(planName)) { return; } try { using (StreamReader file = new StreamReader(File.Open(planName, FileMode.Open))) { ReadTimes(file); ReadHierarchy(file); } if (_configIdToData.Count > 0) { AnalyzeData(); } } catch (IOException) { loggingService.LogCommentFromText(buildEventContext, MessageImportance.Low, ResourceUtilities.FormatResourceString("CantReadBuildPlan", planName)); } catch (InvalidDataException) { loggingService.LogCommentFromText(buildEventContext, MessageImportance.Low, ResourceUtilities.FormatResourceString("BuildPlanCorrupt", planName)); } catch (FormatException) { loggingService.LogCommentFromText(buildEventContext, MessageImportance.Low, ResourceUtilities.FormatResourceString("BuildPlanCorrupt", planName)); } }
private void VerifyImplementationArchitecture(string winmdName, string targetProcessorArchitecture, string implementationFileArch, string warnOrErrorOnTargetArchitectureMismatch) { // Create the engine. MockEngine engine = new MockEngine(); TaskItem item = new TaskItem(winmdName); ITaskItem[] assemblyFiles = new TaskItem[] { item }; ResolveAssemblyReference t = new ResolveAssemblyReference(); t.BuildEngine = engine; t.Assemblies = assemblyFiles; t.SearchPaths = new String[] { @"C:\WinMDArchVerification" }; t.TargetProcessorArchitecture = targetProcessorArchitecture; t.WarnOrErrorOnTargetArchitectureMismatch = warnOrErrorOnTargetArchitectureMismatch; bool succeeded = Execute(t); Assert.Equal(1, t.ResolvedFiles.Length); Assert.True(t.ResolvedFiles[0].ItemSpec.Equals(@"C:\WinMDArchVerification\" + winmdName + ".winmd", StringComparison.OrdinalIgnoreCase)); Assert.True(t.ResolvedFiles[0].GetMetadata(ItemMetadataNames.imageRuntime).Equals(@"WindowsRuntime 1.0", StringComparison.OrdinalIgnoreCase)); Assert.True(bool.Parse(t.ResolvedFiles[0].GetMetadata(ItemMetadataNames.winMDFile))); string fullMessage = null; if (implementationFileArch.Equals("Unknown")) { fullMessage = ResourceUtilities.FormatResourceString("ResolveAssemblyReference.UnknownProcessorArchitecture", @"C:\WinMDArchVerification\" + winmdName + ".dll", @"C:\WinMDArchVerification\" + winmdName + ".winmd", NativeMethods.IMAGE_FILE_MACHINE_R4000.ToString("X", CultureInfo.InvariantCulture)); } else { fullMessage = ResourceUtilities.FormatResourceString("ResolveAssemblyReference.MismatchBetweenTargetedAndReferencedArchOfImplementation", targetProcessorArchitecture, implementationFileArch, @"C:\WinMDArchVerification\" + winmdName + ".dll", @"C:\WinMDArchVerification\" + winmdName + ".winmd"); } if (warnOrErrorOnTargetArchitectureMismatch.Equals("None", StringComparison.OrdinalIgnoreCase)) { engine.AssertLogDoesntContain(fullMessage); } else { engine.AssertLogContains(fullMessage); } if (warnOrErrorOnTargetArchitectureMismatch.Equals("Warning", StringComparison.OrdinalIgnoreCase)) { // Should fail since PE Header is not valid and this is always an error. Assert.True(succeeded); Assert.True(t.ResolvedFiles[0].GetMetadata(ItemMetadataNames.winmdImplmentationFile).Equals(winmdName + ".dll")); Assert.Equal(0, engine.Errors); Assert.Equal(1, engine.Warnings); } else if (warnOrErrorOnTargetArchitectureMismatch.Equals("Error", StringComparison.OrdinalIgnoreCase)) { // Should fail since PE Header is not valid and this is always an error. Assert.False(succeeded); Assert.Equal(0, t.ResolvedFiles[0].GetMetadata(ItemMetadataNames.winmdImplmentationFile).Length); Assert.Equal(1, engine.Errors); Assert.Equal(0, engine.Warnings); } else if (warnOrErrorOnTargetArchitectureMismatch.Equals("None", StringComparison.OrdinalIgnoreCase)) { Assert.True(succeeded); Assert.True(t.ResolvedFiles[0].GetMetadata(ItemMetadataNames.winmdImplmentationFile).Equals(winmdName + ".dll")); Assert.Equal(0, engine.Errors); Assert.Equal(0, engine.Warnings); } }
private string GenerateCode(out string extension) { extension = null; bool haveGeneratedContent = false; CodeDomProvider provider; try { provider = CodeDomProvider.CreateProvider(Language); } catch (System.Configuration.ConfigurationException ex) { Log.LogErrorWithCodeFromResources("WriteCodeFragment.CouldNotCreateProvider", Language, ex.Message); return(null); } catch (SecurityException ex) { Log.LogErrorWithCodeFromResources("WriteCodeFragment.CouldNotCreateProvider", Language, ex.Message); return(null); } extension = provider.FileExtension; CodeCompileUnit unit = new CodeCompileUnit(); CodeNamespace globalNamespace = new CodeNamespace(); unit.Namespaces.Add(globalNamespace); // Declare authorship. Unfortunately CodeDOM puts this comment after the attributes. string comment = ResourceUtilities.FormatResourceString("WriteCodeFragment.Comment"); globalNamespace.Comments.Add(new CodeCommentStatement(comment)); if (AssemblyAttributes == null) { return(String.Empty); } // For convenience, bring in the namespaces, where many assembly attributes lie globalNamespace.Imports.Add(new CodeNamespaceImport("System")); globalNamespace.Imports.Add(new CodeNamespaceImport("System.Reflection")); foreach (ITaskItem attributeItem in AssemblyAttributes) { CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(new CodeTypeReference(attributeItem.ItemSpec)); // Some attributes only allow positional constructor arguments, or the user may just prefer them. // To set those, use metadata names like "_Parameter1", "_Parameter2" etc. // If a parameter index is skipped, it's an error. IDictionary customMetadata = attributeItem.CloneCustomMetadata(); List <CodeAttributeArgument> orderedParameters = new List <CodeAttributeArgument>(new CodeAttributeArgument[customMetadata.Count + 1] /* max possible slots needed */); List <CodeAttributeArgument> namedParameters = new List <CodeAttributeArgument>(); foreach (DictionaryEntry entry in customMetadata) { string name = (string)entry.Key; string value = (string)entry.Value; if (name.StartsWith("_Parameter", StringComparison.OrdinalIgnoreCase)) { int index; if (!Int32.TryParse(name.Substring("_Parameter".Length), out index)) { Log.LogErrorWithCodeFromResources("General.InvalidValue", name, "WriteCodeFragment"); return(null); } if (index > orderedParameters.Count || index < 1) { Log.LogErrorWithCodeFromResources("WriteCodeFragment.SkippedNumberedParameter", index); return(null); } // "_Parameter01" and "_Parameter1" would overwrite each other orderedParameters[index - 1] = new CodeAttributeArgument(String.Empty, new CodePrimitiveExpression(value)); } else { namedParameters.Add(new CodeAttributeArgument(name, new CodePrimitiveExpression(value))); } } bool encounteredNull = false; for (int i = 0; i < orderedParameters.Count; i++) { if (orderedParameters[i] == null) { // All subsequent args should be null, else a slot was missed encounteredNull = true; continue; } if (encounteredNull) { Log.LogErrorWithCodeFromResources("WriteCodeFragment.SkippedNumberedParameter", i + 1 /* back to 1 based */); return(null); } attribute.Arguments.Add(orderedParameters[i]); } foreach (CodeAttributeArgument namedParameter in namedParameters) { attribute.Arguments.Add(namedParameter); } unit.AssemblyCustomAttributes.Add(attribute); haveGeneratedContent = true; } StringBuilder generatedCode = new StringBuilder(); using (StringWriter writer = new StringWriter(generatedCode, CultureInfo.CurrentCulture)) { provider.GenerateCodeFromCompileUnit(unit, writer, new CodeGeneratorOptions()); } string code = generatedCode.ToString(); // If we just generated infrastructure, don't bother returning anything // as there's no point writing the file return(haveGeneratedContent ? code : String.Empty); }
/// <summary> /// Initializes the logger by subscribing to events of IEventSource /// </summary> public void Initialize(IEventSource eventSource) { _initialTargetOutputLogging = Environment.GetEnvironmentVariable("MSBUILDTARGETOUTPUTLOGGING"); _initialLogImports = Environment.GetEnvironmentVariable("MSBUILDLOGIMPORTS"); Environment.SetEnvironmentVariable("MSBUILDTARGETOUTPUTLOGGING", "true"); Environment.SetEnvironmentVariable("MSBUILDLOGIMPORTS", "1"); ProcessParameters(); try { string logDirectory = null; try { logDirectory = Path.GetDirectoryName(FilePath); } catch (Exception) { // Directory creation is best-effort; if finding its path fails don't create the directory // and possibly let the FileStream constructor below report the failure } if (logDirectory != null) { Directory.CreateDirectory(logDirectory); } stream = new FileStream(FilePath, FileMode.Create); if (CollectProjectImports != ProjectImportsCollectionMode.None) { projectImportsCollector = new ProjectImportsCollector(FilePath, CollectProjectImports == ProjectImportsCollectionMode.ZipFile); } if (eventSource is IEventSource3 eventSource3) { eventSource3.IncludeEvaluationMetaprojects(); } } catch (Exception e) { string errorCode; string helpKeyword; string message = ResourceUtilities.FormatResourceString(out errorCode, out helpKeyword, "InvalidFileLoggerFile", FilePath, e.Message); throw new LoggerException(message, e, errorCode, helpKeyword); } stream = new GZipStream(stream, CompressionLevel.Optimal); // wrapping the GZipStream in a buffered stream significantly improves performance // and the max throughput is reached with a 32K buffer. See details here: // https://github.com/dotnet/runtime/issues/39233#issuecomment-745598847 stream = new BufferedStream(stream, bufferSize: 32768); binaryWriter = new BinaryWriter(stream); eventArgsWriter = new BuildEventArgsWriter(binaryWriter); binaryWriter.Write(FileFormatVersion); LogInitialInfo(); eventSource.AnyEventRaised += EventSource_AnyEventRaised; }
/// <summary> /// Reads the settings for a specified tools version /// </summary> /// <param name="toolsVersion"></param> /// <param name="globalProperties"></param> /// <param name="initialProperties"></param> /// <param name="accumulateProperties"></param> /// <returns></returns> private Toolset ReadToolset(PropertyDefinition toolsVersion, BuildPropertyGroup globalProperties, BuildPropertyGroup initialProperties, bool accumulateProperties) { // Initial properties is the set of properties we're going to use to expand property expressions like $(foo) // in the values we read out of the registry or config file. We'll add to it as we pick up properties (including binpath) // from the registry or config file, so that properties there can be referenced in values below them. // After processing all the properties, we don't need initialProperties anymore. string toolsPath = null; string binPath = null; BuildPropertyGroup properties = new BuildPropertyGroup(); IEnumerable <PropertyDefinition> rawProperties = GetPropertyDefinitions(toolsVersion.Name); Expander expander = new Expander(initialProperties); foreach (PropertyDefinition property in rawProperties) { if (String.Equals(property.Name, ReservedPropertyNames.toolsPath, StringComparison.OrdinalIgnoreCase)) { toolsPath = ExpandProperty(property, expander); toolsPath = ExpandRelativePathsRelativeToExeLocation(toolsPath); if (accumulateProperties) { SetProperty ( new PropertyDefinition(ReservedPropertyNames.toolsPath, toolsPath, property.Source), initialProperties, globalProperties ); } } else if (String.Equals(property.Name, ReservedPropertyNames.binPath, StringComparison.OrdinalIgnoreCase)) { binPath = ExpandProperty(property, expander); binPath = ExpandRelativePathsRelativeToExeLocation(binPath); if (accumulateProperties) { SetProperty ( new PropertyDefinition(ReservedPropertyNames.binPath, binPath, property.Source), initialProperties, globalProperties ); } } else if (ReservedPropertyNames.IsReservedProperty(property.Name)) { // We don't allow toolsets to define reserved properties string baseMessage = ResourceUtilities.FormatResourceString("CannotModifyReservedProperty", property.Name); InvalidToolsetDefinitionException.Throw("InvalidPropertyNameInToolset", property.Name, property.Source, baseMessage); } else { // It's an arbitrary property string propertyValue = ExpandProperty(property, expander); PropertyDefinition expandedProperty = new PropertyDefinition(property.Name, propertyValue, property.Source); SetProperty(expandedProperty, properties, globalProperties); if (accumulateProperties) { SetProperty(expandedProperty, initialProperties, globalProperties); } } if (accumulateProperties) { expander = new Expander(initialProperties); } } // All tools versions must specify a value for MSBuildToolsPath (or MSBuildBinPath) if (String.IsNullOrEmpty(toolsPath) && String.IsNullOrEmpty(binPath)) { InvalidToolsetDefinitionException.Throw("MSBuildToolsPathIsNotSpecified", toolsVersion.Name, toolsVersion.Source); } // If both MSBuildBinPath and MSBuildToolsPath are present, they must be the same if (toolsPath != null && binPath != null && !toolsPath.Equals(binPath, StringComparison.OrdinalIgnoreCase)) { return(null); } Toolset toolset = null; try { toolset = new Toolset(toolsVersion.Name, toolsPath ?? binPath, properties); } catch (ArgumentException e) { InvalidToolsetDefinitionException.Throw("ErrorCreatingToolset", toolsVersion.Name, e.Message); } return(toolset); }
/// <summary> /// Get the SDK. /// </summary> /// <returns>true</returns> public override bool Execute() { // TargetPlatformVersion and TargetPlatformIdentifier are requried to correctly look for SDKs. if (String.IsNullOrEmpty(TargetPlatformVersion) || String.IsNullOrEmpty(TargetPlatformIdentifier)) { Log.LogErrorWithCodeFromResources("GetInstalledSDKs.TargetPlatformInformationMissing"); return(false); } // Dictionary of ESDKs. Each entry is a (location, platform version) tuple IDictionary <string, Tuple <string, string> > installedSDKs = null; try { Log.LogMessageFromResources("GetInstalledSDKs.SearchingForSDKs", _targetPlatformIdentifier, _targetPlatformVersion); Version platformVersion = Version.Parse(TargetPlatformVersion); installedSDKs = ToolLocationHelper.GetPlatformExtensionSDKLocationsAndVersions(SDKDirectoryRoots, SDKExtensionDirectoryRoots, SDKRegistryRoot, TargetPlatformIdentifier, platformVersion); } catch (Exception e) { if (ExceptionHandling.IsCriticalException(e)) { throw; } Log.LogErrorWithCodeFromResources("GetInstalledSDKs.CouldNotGetSDKList", e.Message); } List <ITaskItem> outputItems = new List <ITaskItem>(); if (installedSDKs != null && installedSDKs.Count > 0) { Log.LogMessageFromResources(MessageImportance.Low, "GetInstalledSDKs.FoundSDKs", installedSDKs.Count); Log.LogMessageFromResources(MessageImportance.Low, "GetInstalledSDKs.ListInstalledSDKs"); foreach (KeyValuePair <string, Tuple <string, string> > sdk in installedSDKs) { string sdkInfo = ResourceUtilities.FormatResourceString("GetInstalledSDKs.SDKNameAndLocation", sdk.Key, sdk.Value.Item1); Log.LogMessageFromResources(MessageImportance.Low, "ResolveAssemblyReference.FourSpaceIndent", sdkInfo); TaskItem item = new TaskItem(sdk.Value.Item1); item.SetMetadata("SDKName", sdk.Key); item.SetMetadata("PlatformVersion", sdk.Value.Item2); // Need to stash these so we can unroll the platform via GetMatchingPlatformSDK when we get the reference files for the sdks item.SetMetadata(DirectoryRootsMetadataName, String.Join(";", SDKDirectoryRoots ?? new string[0])); item.SetMetadata(ExtensionDirectoryRootsMetadataName, String.Join(";", SDKExtensionDirectoryRoots ?? new string[0])); item.SetMetadata(RegistryRootMetadataName, SDKRegistryRoot); outputItems.Add(item); } } else { Log.LogWarningWithCodeFromResources("GetInstalledSDKs.NoSDksFound"); } InstalledSDKs = outputItems.ToArray(); // We need to register an object so that at the end of the build we will clear the static toolLocationhelper caches. // this is important because if someone adds an SDK between builds we would not know about it and not be able to use it. // This code is mainly used to deal with the case where msbuild nodes hang around between builds. IBuildEngine4 buildEngine4 = BuildEngine as IBuildEngine4; if (buildEngine4 != null) { object staticCacheDisposer = buildEngine4.GetRegisteredTaskObject(StaticSDKCacheKey, RegisteredTaskObjectLifetime.Build); if (staticCacheDisposer == null) { BuildCacheDisposeWrapper staticDisposer = new BuildCacheDisposeWrapper(new BuildCacheDisposeWrapper.CallDuringDispose(ToolLocationHelper.ClearSDKStaticCache)); buildEngine4.RegisterTaskObject(StaticSDKCacheKey, staticDisposer, RegisteredTaskObjectLifetime.Build, allowEarlyCollection: false); } } return(!Log.HasLoggedErrors); }
/// <summary> /// Load content of Platform.xml /// </summary> private void LoadManifestFile() { /* * Platform.xml format: * * <ApplicationPlatform name="UAP" friendlyName="Universal Application Platform" version="1.0.0.0"> * <DependentPlatform name="UAP" version="1.0.0.0" /> * <ContainedApiContracts> * <ApiContract name="UAP" version="1.0.0.0" /> * </ContainedApiContracts> * </ApplicationPlatform> */ try { string platformManifestPath = Path.Combine(_pathToManifest, "Platform.xml"); if (File.Exists(platformManifestPath)) { XmlDocument doc = new XmlDocument(); XmlReaderSettings readerSettings = new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore }; using (XmlReader xmlReader = XmlReader.Create(platformManifestPath, readerSettings)) { doc.Load(xmlReader); } XmlElement rootElement = null; foreach (XmlNode childNode in doc.ChildNodes) { if (childNode.NodeType == XmlNodeType.Element && string.Equals(childNode.Name, Elements.ApplicationPlatform, StringComparison.Ordinal)) { rootElement = (XmlElement)childNode; break; } } DependentPlatforms = new List <DependentPlatform>(); ApiContracts = new List <ApiContract>(); if (rootElement != null) { Name = rootElement.GetAttribute(Attributes.Name); FriendlyName = rootElement.GetAttribute(Attributes.FriendlyName); PlatformVersion = rootElement.GetAttribute(Attributes.Version); foreach (XmlNode childNode in rootElement.ChildNodes) { if (!(childNode is XmlElement childElement)) { continue; } if (ApiContract.IsContainedApiContractsElement(childElement.Name)) { ApiContract.ReadContractsElement(childElement, ApiContracts); } else if (ApiContract.IsVersionedContentElement(childElement.Name)) { bool.TryParse(childElement.InnerText, out bool versionedContent); VersionedContent = versionedContent; } else if (string.Equals(childElement.Name, Elements.DependentPlatform, StringComparison.Ordinal)) { DependentPlatforms.Add(new DependentPlatform(childElement.GetAttribute(Attributes.Name), childElement.GetAttribute(Attributes.Version))); } } } } else { ReadErrorMessage = ResourceUtilities.FormatResourceString("PlatformManifest.MissingPlatformXml", platformManifestPath); } } catch (Exception e) { if (ExceptionHandling.IsCriticalException(e)) { throw; } ReadErrorMessage = e.Message; } }
/// <summary> /// Generates the code into a string. /// If it fails, logs an error and returns null. /// If no meaningful code is generated, returns empty string. /// Returns the default language extension as an out parameter. /// </summary> private string GenerateCodeCoreClr(out string extension) { extension = null; bool haveGeneratedContent = false; StringBuilder code = new StringBuilder(); switch (Language.ToLowerInvariant()) { case "c#": if (AssemblyAttributes == null) { return(string.Empty); } extension = "cs"; code.AppendLine("//------------------------------------------------------------------------------"); code.AppendLine("// <auto-generated>"); code.AppendLine("// " + ResourceUtilities.FormatResourceString("WriteCodeFragment.Comment")); code.AppendLine("// </auto-generated>"); code.AppendLine("//------------------------------------------------------------------------------"); code.AppendLine(); code.AppendLine("using System;"); code.AppendLine("using System.Reflection;"); code.AppendLine(); foreach (ITaskItem attributeItem in AssemblyAttributes) { string args = GetAttributeArguments(attributeItem, "=", QuoteSnippetStringCSharp); if (args == null) { return(null); } code.AppendLine(string.Format($"[assembly: {attributeItem.ItemSpec}({args})]")); haveGeneratedContent = true; } break; case "visual basic": case "visualbasic": case "vb": if (AssemblyAttributes == null) { return(string.Empty); } extension = "vb"; code.AppendLine("'------------------------------------------------------------------------------"); code.AppendLine("' <auto-generated>"); code.AppendLine("' " + ResourceUtilities.FormatResourceString("WriteCodeFragment.Comment")); code.AppendLine("' </auto-generated>"); code.AppendLine("'------------------------------------------------------------------------------"); code.AppendLine(); code.AppendLine("Option Strict Off"); code.AppendLine("Option Explicit On"); code.AppendLine(); code.AppendLine("Imports System"); code.AppendLine("Imports System.Reflection"); foreach (ITaskItem attributeItem in AssemblyAttributes) { string args = GetAttributeArguments(attributeItem, ":=", QuoteSnippetStringVisualBasic); if (args == null) { return(null); } code.AppendLine(string.Format($"<Assembly: {attributeItem.ItemSpec}({args})>")); haveGeneratedContent = true; } break; default: Log.LogErrorWithCodeFromResources("WriteCodeFragment.CouldNotCreateProvider", Language, string.Empty); return(null); } // If we just generated infrastructure, don't bother returning anything // as there's no point writing the file return(haveGeneratedContent ? code.ToString() : string.Empty); }
/// <summary> /// /// </summary> /// <returns>True if the operation was successful</returns> internal static async Task <bool> ExecuteTargets ( ITaskItem[] projects, Hashtable propertiesTable, string[] undefineProperties, ArrayList targetLists, bool stopOnFirstFailure, bool rebaseOutputs, IBuildEngine3 buildEngine, TaskLoggingHelper log, ArrayList targetOutputs, bool useResultsCache, bool unloadProjectsOnCompletion, string toolsVersion ) { bool success = true; // We don't log a message about the project and targets we're going to // build, because it'll all be in the immediately subsequent ProjectStarted event. string[] projectDirectory = new string[projects.Length]; string[] projectNames = new string[projects.Length]; string[] toolsVersions = new string[projects.Length]; IList <IDictionary <string, ITaskItem[]> > targetOutputsPerProject = null; IDictionary[] projectProperties = new IDictionary[projects.Length]; List <string>[] undefinePropertiesPerProject = new List <string> [projects.Length]; for (int i = 0; i < projectNames.Length; i++) { projectNames[i] = null; projectProperties[i] = propertiesTable; if (projects[i] != null) { // Retrieve projectDirectory only the first time. It never changes anyway. string projectPath = FileUtilities.AttemptToShortenPath(projects[i].ItemSpec); projectDirectory[i] = Path.GetDirectoryName(projectPath); projectNames[i] = projects[i].ItemSpec; toolsVersions[i] = toolsVersion; // If the user specified a different set of global properties for this project, then // parse the string containing the properties if (!String.IsNullOrEmpty(projects[i].GetMetadata("Properties"))) { Hashtable preProjectPropertiesTable; if (!PropertyParser.GetTableWithEscaping (log, ResourceUtilities.FormatResourceString("General.OverridingProperties", projectNames[i]), "Properties", projects[i].GetMetadata("Properties").Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries), out preProjectPropertiesTable) ) { return(false); } projectProperties[i] = preProjectPropertiesTable; } if (undefineProperties != null) { undefinePropertiesPerProject[i] = new List <string>(undefineProperties); } // If the user wanted to undefine specific global properties for this project, parse // that string and remove them now. string projectUndefineProperties = projects[i].GetMetadata("UndefineProperties"); if (!String.IsNullOrEmpty(projectUndefineProperties)) { string[] propertiesToUndefine = projectUndefineProperties.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); if (undefinePropertiesPerProject[i] == null) { undefinePropertiesPerProject[i] = new List <string>(propertiesToUndefine.Length); } if (log != null && propertiesToUndefine.Length > 0) { log.LogMessageFromResources(MessageImportance.Low, "General.ProjectUndefineProperties", projectNames[i]); foreach (string property in propertiesToUndefine) { undefinePropertiesPerProject[i].Add(property); log.LogMessageFromText(String.Format(CultureInfo.InvariantCulture, " {0}", property), MessageImportance.Low); } } } // If the user specified a different set of global properties for this project, then // parse the string containing the properties if (!String.IsNullOrEmpty(projects[i].GetMetadata("AdditionalProperties"))) { Hashtable additionalProjectPropertiesTable; if (!PropertyParser.GetTableWithEscaping (log, ResourceUtilities.FormatResourceString("General.AdditionalProperties", projectNames[i]), "AdditionalProperties", projects[i].GetMetadata("AdditionalProperties").Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries), out additionalProjectPropertiesTable) ) { return(false); } Hashtable combinedTable = new Hashtable(StringComparer.OrdinalIgnoreCase); // First copy in the properties from the global table that not in the additional properties table if (projectProperties[i] != null) { foreach (DictionaryEntry entry in projectProperties[i]) { if (!additionalProjectPropertiesTable.Contains(entry.Key)) { combinedTable.Add(entry.Key, entry.Value); } } } // Add all the additional properties foreach (DictionaryEntry entry in additionalProjectPropertiesTable) { combinedTable.Add(entry.Key, entry.Value); } projectProperties[i] = combinedTable; } // If the user specified a different toolsVersion for this project - then override the setting if (!String.IsNullOrEmpty(projects[i].GetMetadata("ToolsVersion"))) { toolsVersions[i] = projects[i].GetMetadata("ToolsVersion"); } } } foreach (string[] targetList in targetLists) { if (stopOnFirstFailure && !success) { // Inform the user that we skipped the remaining targets StopOnFirstFailure=true. log.LogMessageFromResources(MessageImportance.Low, "MSBuild.SkippingRemainingTargets"); // We have encountered a failure. Caller has requested that we not // continue with remaining targets. break; } // Send the project off to the build engine. By passing in null to the // first param, we are indicating that the project to build is the same // as the *calling* project file. bool currentTargetResult = true; TaskHost taskHost = (TaskHost)buildEngine; BuildEngineResult result = await taskHost.InternalBuildProjects(projectNames, targetList, projectProperties, undefinePropertiesPerProject, toolsVersions, true /* ask that target outputs are returned in the buildengineresult */); currentTargetResult = result.Result; targetOutputsPerProject = result.TargetOutputsPerProject; success = success && currentTargetResult; // If the engine was able to satisfy the build request if (currentTargetResult) { for (int i = 0; i < projects.Length; i++) { IEnumerable nonNullTargetList = (targetList != null) ? targetList : targetOutputsPerProject[i].Keys; foreach (string targetName in nonNullTargetList) { if (targetOutputsPerProject[i].ContainsKey(targetName)) { ITaskItem[] outputItemsFromTarget = (ITaskItem[])targetOutputsPerProject[i][targetName]; foreach (ITaskItem outputItemFromTarget in outputItemsFromTarget) { // No need to rebase if the calling project is the same as the callee project // (project == null). Also no point in trying to copy item metadata either, // because no items were passed into the Projects parameter! if (projects[i] != null) { // Rebase the output item paths if necessary. No need to rebase if the calling // project is the same as the callee project (project == null). if (rebaseOutputs) { try { outputItemFromTarget.ItemSpec = Path.Combine(projectDirectory[i], outputItemFromTarget.ItemSpec); } catch (ArgumentException e) { log.LogWarningWithCodeFromResources(null, projects[i].ItemSpec, 0, 0, 0, 0, "MSBuild.CannotRebaseOutputItemPath", outputItemFromTarget.ItemSpec, e.Message); } } // Copy the custom item metadata from the "Projects" items to these // output items. projects[i].CopyMetadataTo(outputItemFromTarget); // Set a metadata on the output items called "MSBuildProjectFile" which tells you which project file produced this item. if (String.IsNullOrEmpty(outputItemFromTarget.GetMetadata(ItemMetadataNames.msbuildSourceProjectFile))) { outputItemFromTarget.SetMetadata(ItemMetadataNames.msbuildSourceProjectFile, projects[i].GetMetadata(FileUtilities.ItemSpecModifiers.FullPath)); } } // Set a metadata on the output items called "MSBuildTargetName" which tells you which target produced this item. if (String.IsNullOrEmpty(outputItemFromTarget.GetMetadata(ItemMetadataNames.msbuildSourceTargetName))) { outputItemFromTarget.SetMetadata(ItemMetadataNames.msbuildSourceTargetName, targetName); } } targetOutputs.AddRange(outputItemsFromTarget); } } } } } return(success); }
/// <summary> /// Increases the error count by 1, and logs the error message /// </summary> private void LogError(string messageResourceName, params object[] messageArgs) { ErrorLog.AddLast(ResourceUtilities.FormatResourceString(messageResourceName, messageArgs)); ErrorCount++; }
/// <summary> /// Creates a new MSBuild process /// </summary> private int LaunchNode(string msbuildLocation, string commandLineArgs) { // Should always have been set already. ErrorUtilities.VerifyThrowInternalLength(msbuildLocation, "msbuildLocation"); if (!File.Exists(msbuildLocation)) { throw new BuildAbortedException(ResourceUtilities.FormatResourceString("CouldNotFindMSBuildExe", msbuildLocation)); } // Repeat the executable name as the first token of the command line because the command line // parser logic expects it and will otherwise skip the first argument commandLineArgs = msbuildLocation + " " + commandLineArgs; BackendNativeMethods.STARTUP_INFO startInfo = new BackendNativeMethods.STARTUP_INFO(); startInfo.cb = Marshal.SizeOf <BackendNativeMethods.STARTUP_INFO>(); // Null out the process handles so that the parent process does not wait for the child process // to exit before it can exit. uint creationFlags = BackendNativeMethods.NORMALPRIORITYCLASS; startInfo.dwFlags = BackendNativeMethods.STARTFUSESTDHANDLES; if (String.IsNullOrEmpty(Environment.GetEnvironmentVariable("MSBUILDNODEWINDOW"))) { startInfo.hStdError = BackendNativeMethods.InvalidHandle; startInfo.hStdInput = BackendNativeMethods.InvalidHandle; startInfo.hStdOutput = BackendNativeMethods.InvalidHandle; creationFlags = creationFlags | BackendNativeMethods.CREATENOWINDOW; } else { creationFlags = creationFlags | BackendNativeMethods.CREATE_NEW_CONSOLE; } BackendNativeMethods.SECURITY_ATTRIBUTES processSecurityAttributes = new BackendNativeMethods.SECURITY_ATTRIBUTES(); BackendNativeMethods.SECURITY_ATTRIBUTES threadSecurityAttributes = new BackendNativeMethods.SECURITY_ATTRIBUTES(); processSecurityAttributes.nLength = Marshal.SizeOf <BackendNativeMethods.SECURITY_ATTRIBUTES>(); threadSecurityAttributes.nLength = Marshal.SizeOf <BackendNativeMethods.SECURITY_ATTRIBUTES>(); CommunicationsUtilities.Trace("Launching node from {0}", msbuildLocation); #if RUNTIME_TYPE_NETCORE // Run the child process with the same host as the currently-running process. string pathToHost; using (Process currentProcess = Process.GetCurrentProcess()) pathToHost = currentProcess.MainModule.FileName; commandLineArgs = "\"" + msbuildLocation + "\" " + commandLineArgs; ProcessStartInfo processStartInfo = new ProcessStartInfo(); processStartInfo.FileName = pathToHost; processStartInfo.Arguments = commandLineArgs; processStartInfo.CreateNoWindow = (creationFlags | BackendNativeMethods.CREATENOWINDOW) == BackendNativeMethods.CREATENOWINDOW; processStartInfo.UseShellExecute = false; Process process; try { process = Process.Start(processStartInfo); } catch (Exception ex) { CommunicationsUtilities.Trace ( "Failed to launch node from {0}. CommandLine: {1}" + Environment.NewLine + "{2}", msbuildLocation, commandLineArgs, ex.ToString() ); throw new NodeFailedToLaunchException(ex); } CommunicationsUtilities.Trace("Successfully launched msbuild.exe node with PID {0}", process.Id); return(process.Id); #else BackendNativeMethods.PROCESS_INFORMATION processInfo = new BackendNativeMethods.PROCESS_INFORMATION(); string exeName = msbuildLocation; bool result = BackendNativeMethods.CreateProcess ( exeName, commandLineArgs, ref processSecurityAttributes, ref threadSecurityAttributes, false, creationFlags, BackendNativeMethods.NullPtr, null, ref startInfo, out processInfo ); if (!result) { // Creating an instance of this exception calls GetLastWin32Error and also converts it to a user-friendly string. System.ComponentModel.Win32Exception e = new System.ComponentModel.Win32Exception(); CommunicationsUtilities.Trace ( "Failed to launch node from {0}. System32 Error code {1}. Description {2}. CommandLine: {2}", msbuildLocation, e.NativeErrorCode.ToString(CultureInfo.InvariantCulture), e.Message, commandLineArgs ); throw new NodeFailedToLaunchException(e.NativeErrorCode.ToString(CultureInfo.InvariantCulture), e.Message); } CommunicationsUtilities.Trace("Successfully launched msbuild.exe node with PID {0}", processInfo.dwProcessId); return(processInfo.dwProcessId); #endif }
/// <summary> /// Writes a plan for the specified submission id. /// </summary> public void WritePlan(int submissionId, ILoggingService loggingService, BuildEventContext buildEventContext) { if (!BuildParameters.EnableBuildPlan) { return; } SchedulableRequest rootRequest = GetRootRequest(submissionId); if (rootRequest == null) { return; } string planName = GetPlanName(rootRequest); if (String.IsNullOrEmpty(planName)) { return; } try { using (StreamWriter file = new StreamWriter(File.Open(planName, FileMode.Create))) { // Write the accumulated configuration times. Dictionary <int, double> accumulatedTimeByConfiguration = new Dictionary <int, double>(); RecursiveAccumulateConfigurationTimes(rootRequest, accumulatedTimeByConfiguration); List <int> configurationsInOrder = new List <int>(accumulatedTimeByConfiguration.Keys); configurationsInOrder.Sort(); foreach (int configId in configurationsInOrder) { file.WriteLine(String.Format(CultureInfo.InvariantCulture, "{0} {1} {2}", configId, accumulatedTimeByConfiguration[configId], _configCache[configId].ProjectFullPath)); } file.WriteLine(); // Write out the dependency information. RecursiveWriteDependencies(file, rootRequest); } } catch (IOException) { loggingService.LogCommentFromText(buildEventContext, MessageImportance.Low, ResourceUtilities.FormatResourceString("CantWriteBuildPlan", planName)); } }
/// <summary> /// Apply a parameter /// </summary> private void ApplyFileLoggerParameter(string parameterName, string parameterValue) { if (String.Compare("LOGFILE", parameterName, StringComparison.OrdinalIgnoreCase) == 0) { if (string.IsNullOrEmpty(parameterValue)) { string message = ResourceUtilities.FormatResourceString("InvalidFileLoggerFile", string.Empty, ResourceUtilities.FormatResourceString("logfilePathNullOrEmpty")); throw new LoggerException(message); } // Set log file to the right half of the parameter string and then remove it as it is going to be replaced in Initialize _logFile = parameterValue; int indexOfParameter = _parameters.IndexOf(parameterName + s_fileLoggerParameterValueSplitCharacter[0] + parameterValue, 0, StringComparison.OrdinalIgnoreCase); int length = ((string)(parameterName + s_fileLoggerParameterValueSplitCharacter[0] + parameterValue)).Length; // Check to see if the next char is a ; if so remove that as well if ((indexOfParameter + length) < _parameters.Length && _parameters[indexOfParameter + length] == ';') { length++; } _parameters = _parameters.Remove(indexOfParameter, length); } }
/// <summary> /// Writes a line from a resource string to the log, using the specified indentation. /// </summary> internal void WriteLinePrettyFromResource(int indentLevel, string resourceString, params object[] args) { string formattedString = ResourceUtilities.FormatResourceString(resourceString, args); WriteLinePretty(indentLevel, formattedString); }
public static SdkResultBase GetSdkResult(SdkReference sdk, object nuGetVersion, SdkResolverContextBase context, SdkResultFactoryBase factory) { // Cast the NuGet version since the caller does not want to consume NuGet classes directly NuGetVersion parsedSdkVersion = (NuGetVersion)nuGetVersion; // Stores errors and warnings for the result ICollection <string> errors = new List <string>(); ICollection <string> warnings = new List <string>(); // Load NuGet settings and a path resolver ISettings settings = Settings.LoadDefaultSettings(context.ProjectFilePath); FallbackPackagePathResolver fallbackPackagePathResolver = new FallbackPackagePathResolver(NuGetPathContext.Create(settings)); string installedPath, installedVersion; // Attempt to find a package if its already installed if (!TryGetMSBuildSdkPackageInfo(fallbackPackagePathResolver, sdk.Name, parsedSdkVersion, out installedPath, out installedVersion)) { try { // Asynchronously run the restore without a commit which find the package on configured feeds, download, and unzip it without generating any other files IReadOnlyList <RestoreResultPair> results = RestoreRunnerEx.RunWithoutCommit( context.ProjectFilePath, sdk.Name, parsedSdkVersion.ToFullString(), settings, new NuGetSdkLogger(context.Logger, warnings, errors)) .ConfigureAwait(continueOnCapturedContext: false) .GetAwaiter() .GetResult(); fallbackPackagePathResolver = new FallbackPackagePathResolver(NuGetPathContext.Create(settings)); // Look for a successful result, any errors are logged by NuGet foreach (RestoreResult result in results.Select(i => i.Result).Where(i => i.Success)) { // Find the information about the package that was installed. In some cases, the version can be different than what was specified (like you specify 1.0 but get 1.0.0) LibraryIdentity installedPackage = result.GetAllInstalled().FirstOrDefault(i => i.Name.Equals(sdk.Name)); if (installedPackage != null) { if (!TryGetMSBuildSdkPackageInfo(fallbackPackagePathResolver, installedPackage.Name, installedPackage.Version, out installedPath, out installedVersion)) { // This should never happen because we were told the package was successfully installed. // If we can't find it, we probably did something wrong with the NuGet API errors.Add(ResourceUtilities.FormatResourceString("CouldNotFindInstalledPackage", sdk)); } } else { // This should never happen because we were told the restore succeeded. // If we can't find the package from GetAllInstalled(), we probably did something wrong with the NuGet API errors.Add(ResourceUtilities.FormatResourceString("PackageWasNotInstalled", sdk, sdk.Name)); } } } catch (Exception e) { errors.Add(e.Message); } } if (errors.Count == 0) { return(factory.IndicateSuccess(path: installedPath, version: installedVersion, warnings: warnings)); } return(factory.IndicateFailure(errors, warnings)); }