/// <summary> /// Coordinates the processing of all detected switches. It gathers information necessary to invoke the build engine, and /// performs deeper error checking on the switches and their parameters. /// </summary> /// <returns>true, if build can be invoked</returns> private static bool ProcessCommandLineSwitches ( CommandLineSwitches switchesFromAutoResponseFile, CommandLineSwitches switchesNotFromAutoResponseFile, ref string projectFile, ref string[] targets, ref string toolsVersion, ref Dictionary<string, string> globalProperties, ref ILogger[] loggers, ref LoggerVerbosity verbosity, ref List<DistributedLoggerRecord> distributedLoggerRecords, ref bool needToValidateProject, ref string schemaFile, ref int cpuCount, ref bool enableNodeReuse, ref TextWriter preprocessWriter, ref bool debugger, ref bool detailedSummary, bool recursing ) { bool invokeBuild = false; // combine the auto-response file switches with the command line switches in a left-to-right manner, where the // auto-response file switches are on the left (default options), and the command line switches are on the // right (overriding options) so that we consume switches in the following sequence of increasing priority: // (1) switches from the msbuild.rsp file/s, including recursively included response files // (2) switches from the command line, including recursively included response file switches inserted at the point they are declared with their "@" symbol CommandLineSwitches commandLineSwitches = new CommandLineSwitches(); commandLineSwitches.Append(switchesFromAutoResponseFile); // lowest precedence commandLineSwitches.Append(switchesNotFromAutoResponseFile); // show copyright message if nologo switch is not set // NOTE: we heed the nologo switch even if there are switch errors if (!recursing && !commandLineSwitches[CommandLineSwitches.ParameterlessSwitch.NoLogo] && !commandLineSwitches.IsParameterizedSwitchSet(CommandLineSwitches.ParameterizedSwitch.Preprocess)) { DisplayCopyrightMessage(); } // if help switch is set (regardless of switch errors), show the help message and ignore the other switches if (commandLineSwitches[CommandLineSwitches.ParameterlessSwitch.Help]) { ShowHelpMessage(); } else if (commandLineSwitches.IsParameterizedSwitchSet(CommandLineSwitches.ParameterizedSwitch.NodeMode)) { StartLocalNode(commandLineSwitches); } else { // if help switch is not set, and errors were found, abort (don't process the remaining switches) commandLineSwitches.ThrowErrors(); // if version switch is set, just show the version and quit (ignore the other switches) if (commandLineSwitches[CommandLineSwitches.ParameterlessSwitch.Version]) { ShowVersion(); } else { // figure out what project we are building projectFile = ProcessProjectSwitch(commandLineSwitches[CommandLineSwitches.ParameterizedSwitch.Project], commandLineSwitches[CommandLineSwitches.ParameterizedSwitch.IgnoreProjectExtensions], Directory.GetFiles); if (!recursing && !commandLineSwitches[CommandLineSwitches.ParameterlessSwitch.NoAutoResponse]) { // gather any switches from an msbuild.rsp that is next to the project or solution file itself string projectDirectory = Path.GetDirectoryName(Path.GetFullPath(projectFile)); bool found = false; // Don't look for more response files if it's only in the same place we already looked (next to the exe) if (!String.Equals(projectDirectory, s_exePath, StringComparison.OrdinalIgnoreCase)) { // this combines any found, with higher precedence, with the switches from the original auto response file switches found = GatherAutoResponseFileSwitches(projectDirectory, switchesFromAutoResponseFile); } if (found) { // we presumably read in more switches, so start our switch processing all over again, // so that we consume switches in the following sequence of increasing priority: // (1) switches from the msbuild.rsp next to msbuild.exe, including recursively included response files // (2) switches from this msbuild.rsp next to the project or solution <<--------- these we have just now merged with (1) // (3) switches from the command line, including recursively included response file switches inserted at the point they are declared with their "@" symbol return ProcessCommandLineSwitches( switchesFromAutoResponseFile, switchesNotFromAutoResponseFile, ref projectFile, ref targets, ref toolsVersion, ref globalProperties, ref loggers, ref verbosity, ref distributedLoggerRecords, ref needToValidateProject, ref schemaFile, ref cpuCount, ref enableNodeReuse, ref preprocessWriter, ref debugger, ref detailedSummary, recursing: true ); } } // figure out which targets we are building targets = ProcessTargetSwitch(commandLineSwitches[CommandLineSwitches.ParameterizedSwitch.Target]); // figure out which ToolsVersion has been set on the command line toolsVersion = ProcessToolsVersionSwitch(commandLineSwitches[CommandLineSwitches.ParameterizedSwitch.ToolsVersion]); // figure out which properties have been set on the command line globalProperties = ProcessPropertySwitch(commandLineSwitches[CommandLineSwitches.ParameterizedSwitch.Property]); // figure out if there was a max cpu count provided cpuCount = ProcessMaxCPUCountSwitch(commandLineSwitches[CommandLineSwitches.ParameterizedSwitch.MaxCPUCount]); // figure out if we shold reuse nodes enableNodeReuse = ProcessNodeReuseSwitch(commandLineSwitches[CommandLineSwitches.ParameterizedSwitch.NodeReuse]); // determine what if any writer to preprocess to preprocessWriter = null; if (commandLineSwitches.IsParameterizedSwitchSet(CommandLineSwitches.ParameterizedSwitch.Preprocess)) { preprocessWriter = ProcessPreprocessSwitch(commandLineSwitches[CommandLineSwitches.ParameterizedSwitch.Preprocess]); } #if FEATURE_MSBUILD_DEBUGGER debugger = commandLineSwitches.IsParameterlessSwitchSet(CommandLineSwitches.ParameterlessSwitch.Debugger); #endif detailedSummary = commandLineSwitches.IsParameterlessSwitchSet(CommandLineSwitches.ParameterlessSwitch.DetailedSummary); // figure out which loggers are going to listen to build events string[][] groupedFileLoggerParameters = commandLineSwitches.GetFileLoggerParameters(); loggers = ProcessLoggingSwitches( commandLineSwitches[CommandLineSwitches.ParameterizedSwitch.Logger], commandLineSwitches[CommandLineSwitches.ParameterizedSwitch.DistributedLogger], commandLineSwitches[CommandLineSwitches.ParameterizedSwitch.Verbosity], commandLineSwitches[CommandLineSwitches.ParameterlessSwitch.NoConsoleLogger], commandLineSwitches[CommandLineSwitches.ParameterlessSwitch.DistributedFileLogger], commandLineSwitches[CommandLineSwitches.ParameterizedSwitch.FileLoggerParameters], // used by DistributedFileLogger commandLineSwitches[CommandLineSwitches.ParameterizedSwitch.ConsoleLoggerParameters], groupedFileLoggerParameters, out distributedLoggerRecords, out verbosity, ref detailedSummary, cpuCount ); // If we picked up switches from the autoreponse file, let the user know. This could be a useful // hint to a user that does not know that we are picking up the file automatically. // Since this is going to happen often in normal use, only log it in high verbosity mode. // Also, only log it to the console; logging to loggers would involve increasing the public API of // the Engine, and we don't want to do that. if (usingSwitchesFromAutoResponseFile && LoggerVerbosity.Diagnostic == verbosity) { Console.WriteLine(ResourceUtilities.FormatResourceString("PickedUpSwitchesFromAutoResponse", autoResponseFileName)); } if (verbosity == LoggerVerbosity.Diagnostic) { string equivalentCommandLine = commandLineSwitches.GetEquivalentCommandLineExceptProjectFile(); Console.WriteLine(Path.Combine(s_exePath, s_exeName) + " " + equivalentCommandLine + " " + projectFile); } // figure out if the project needs to be validated against a schema needToValidateProject = commandLineSwitches.IsParameterizedSwitchSet(CommandLineSwitches.ParameterizedSwitch.Validate); schemaFile = ProcessValidateSwitch(commandLineSwitches[CommandLineSwitches.ParameterizedSwitch.Validate]); invokeBuild = true; } } ErrorUtilities.VerifyThrow(!invokeBuild || !String.IsNullOrEmpty(projectFile), "We should have a project file if we're going to build."); return invokeBuild; }
/// <summary> /// Verifies that a switch collection has an error registered for the given command line arg. /// </summary> /// <param name="switches"></param> /// <param name="badCommandLineArg"></param> private void VerifySwitchError(CommandLineSwitches switches, string badCommandLineArg) { bool caughtError = false; try { switches.ThrowErrors(); } catch (CommandLineSwitchException e) { Assert.Equal(badCommandLineArg, e.CommandLineArg); caughtError = true; // so I can see the message in NUnit's "Standard Out" window Console.WriteLine(e.Message); } finally { Assert.True(caughtError); } }