/// <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; }
public void AppendParameterizedSwitchesTests1() { CommandLineSwitches switchesLeft = new CommandLineSwitches(); switchesLeft.SetParameterizedSwitch(CommandLineSwitches.ParameterizedSwitch.Project, "tempproject.proj", "tempproject.proj", false, true); Assert.True(switchesLeft.IsParameterizedSwitchSet(CommandLineSwitches.ParameterizedSwitch.Project)); Assert.False(switchesLeft.IsParameterizedSwitchSet(CommandLineSwitches.ParameterizedSwitch.Target)); CommandLineSwitches switchesRight = new CommandLineSwitches(); switchesRight.SetParameterizedSwitch(CommandLineSwitches.ParameterizedSwitch.Target, "/t:build", "build", true, true); Assert.False(switchesRight.IsParameterizedSwitchSet(CommandLineSwitches.ParameterizedSwitch.Project)); Assert.True(switchesRight.IsParameterizedSwitchSet(CommandLineSwitches.ParameterizedSwitch.Target)); switchesLeft.Append(switchesRight); Assert.Equal("tempproject.proj", switchesLeft.GetParameterizedSwitchCommandLineArg(CommandLineSwitches.ParameterizedSwitch.Project)); Assert.True(switchesLeft.IsParameterizedSwitchSet(CommandLineSwitches.ParameterizedSwitch.Project)); string[] parameters = switchesLeft[CommandLineSwitches.ParameterizedSwitch.Project]; Assert.NotNull(parameters); Assert.Equal(1, parameters.Length); Assert.Equal("tempproject.proj", parameters[0]); Assert.Equal("/t:build", switchesLeft.GetParameterizedSwitchCommandLineArg(CommandLineSwitches.ParameterizedSwitch.Target)); Assert.True(switchesLeft.IsParameterizedSwitchSet(CommandLineSwitches.ParameterizedSwitch.Target)); parameters = switchesLeft[CommandLineSwitches.ParameterizedSwitch.Target]; Assert.NotNull(parameters); Assert.Equal(1, parameters.Length); Assert.Equal("build", parameters[0]); }
/// <summary> /// Called when a switch that takes parameters is detected on the command line. This method flags errors and stores the /// switch parameters. /// </summary> /// <param name="commandLineSwitches"></param> /// <param name="parameterizedSwitch"></param> /// <param name="switchParameters"></param> /// <param name="duplicateSwitchErrorMessage"></param> /// <param name="multipleParametersAllowed"></param> /// <param name="missingParametersErrorMessage"></param> /// <param name="unquoteParameters"></param> /// <param name="unquotedCommandLineArg"></param> private static void GatherParameterizedCommandLineSwitch ( CommandLineSwitches commandLineSwitches, CommandLineSwitches.ParameterizedSwitch parameterizedSwitch, string switchParameters, string duplicateSwitchErrorMessage, bool multipleParametersAllowed, string missingParametersErrorMessage, bool unquoteParameters, string unquotedCommandLineArg ) { if (// switch must have parameters (switchParameters.Length > 1) || // unless the parameters are optional (missingParametersErrorMessage == null)) { // check if switch is duplicated, and if that's allowed if (!commandLineSwitches.IsParameterizedSwitchSet(parameterizedSwitch) || (duplicateSwitchErrorMessage == null)) { // skip the parameter indicator (if any) if (switchParameters.Length > 0) { switchParameters = switchParameters.Substring(1); } // save the parameters after unquoting and splitting them if necessary if (!commandLineSwitches.SetParameterizedSwitch(parameterizedSwitch, unquotedCommandLineArg, switchParameters, multipleParametersAllowed, unquoteParameters)) { // if parsing revealed there were no real parameters, flag an error, unless the parameters are optional if (missingParametersErrorMessage != null) { commandLineSwitches.SetSwitchError(missingParametersErrorMessage, unquotedCommandLineArg); } } } else { commandLineSwitches.SetSwitchError(duplicateSwitchErrorMessage, unquotedCommandLineArg); } } else { commandLineSwitches.SetSwitchError(missingParametersErrorMessage, unquotedCommandLineArg); } }
public void SetParameterizedSwitchTests2() { CommandLineSwitches switches = new CommandLineSwitches(); // we haven't set this switch yet Assert.Null(switches.GetParameterizedSwitchCommandLineArg(CommandLineSwitches.ParameterizedSwitch.Target)); Assert.False(switches.IsParameterizedSwitchSet(CommandLineSwitches.ParameterizedSwitch.Target)); string[] parameters = switches[CommandLineSwitches.ParameterizedSwitch.Target]; Assert.NotNull(parameters); Assert.Equal(0, parameters.Length); // fake/missing parameters -- this is bogus because the /target switch allows multiple parameters but we're turning // that off here just for testing purposes Assert.False(switches.SetParameterizedSwitch(CommandLineSwitches.ParameterizedSwitch.Target, "/t:\"", "\"", false, true)); // switch has been set Assert.Equal("/t:\"", switches.GetParameterizedSwitchCommandLineArg(CommandLineSwitches.ParameterizedSwitch.Target)); Assert.True(switches.IsParameterizedSwitchSet(CommandLineSwitches.ParameterizedSwitch.Target)); parameters = switches[CommandLineSwitches.ParameterizedSwitch.Target]; // but no parameters Assert.NotNull(parameters); Assert.Equal(0, parameters.Length); // more fake/missing parameters Assert.False(switches.SetParameterizedSwitch(CommandLineSwitches.ParameterizedSwitch.Target, "/t:A,\"\";B", "A,\"\";B", true, true)); Assert.Equal("/t:\" /t:A,\"\";B", switches.GetParameterizedSwitchCommandLineArg(CommandLineSwitches.ParameterizedSwitch.Target)); Assert.True(switches.IsParameterizedSwitchSet(CommandLineSwitches.ParameterizedSwitch.Target)); parameters = switches[CommandLineSwitches.ParameterizedSwitch.Target]; // now we have some parameters Assert.NotNull(parameters); Assert.Equal(2, parameters.Length); Assert.Equal("A", parameters[0]); Assert.Equal("B", parameters[1]); }
public void SetParameterizedSwitchTests3() { CommandLineSwitches switches = new CommandLineSwitches(); // we haven't set this switch yet Assert.Null(switches.GetParameterizedSwitchCommandLineArg(CommandLineSwitches.ParameterizedSwitch.Logger)); Assert.False(switches.IsParameterizedSwitchSet(CommandLineSwitches.ParameterizedSwitch.Logger)); string[] parameters = switches[CommandLineSwitches.ParameterizedSwitch.Logger]; Assert.NotNull(parameters); Assert.Equal(0, parameters.Length); // don't unquote fake/missing parameters Assert.True(switches.SetParameterizedSwitch(CommandLineSwitches.ParameterizedSwitch.Logger, "/l:\"", "\"", false, false)); Assert.Equal("/l:\"", switches.GetParameterizedSwitchCommandLineArg(CommandLineSwitches.ParameterizedSwitch.Logger)); Assert.True(switches.IsParameterizedSwitchSet(CommandLineSwitches.ParameterizedSwitch.Logger)); parameters = switches[CommandLineSwitches.ParameterizedSwitch.Logger]; Assert.NotNull(parameters); Assert.Equal(1, parameters.Length); Assert.Equal("\"", parameters[0]); // don't unquote multiple fake/missing parameters -- this is bogus because the /logger switch does not take multiple // parameters, but for testing purposes this is fine Assert.True(switches.SetParameterizedSwitch(CommandLineSwitches.ParameterizedSwitch.Logger, "/LOGGER:\"\",asm;\"p,a;r\"", "\"\",asm;\"p,a;r\"", true, false)); Assert.Equal("/l:\" /LOGGER:\"\",asm;\"p,a;r\"", switches.GetParameterizedSwitchCommandLineArg(CommandLineSwitches.ParameterizedSwitch.Logger)); Assert.True(switches.IsParameterizedSwitchSet(CommandLineSwitches.ParameterizedSwitch.Logger)); parameters = switches[CommandLineSwitches.ParameterizedSwitch.Logger]; Assert.NotNull(parameters); Assert.Equal(4, parameters.Length); Assert.Equal("\"", parameters[0]); Assert.Equal("\"\"", parameters[1]); Assert.Equal("asm", parameters[2]); Assert.Equal("\"p,a;r\"", parameters[3]); }
public void SetParameterizedSwitchTests1() { CommandLineSwitches switches = new CommandLineSwitches(); Assert.True(switches.SetParameterizedSwitch(CommandLineSwitches.ParameterizedSwitch.Verbosity, "/v:q", "q", false, true)); Assert.Equal("/v:q", switches.GetParameterizedSwitchCommandLineArg(CommandLineSwitches.ParameterizedSwitch.Verbosity)); Assert.True(switches.IsParameterizedSwitchSet(CommandLineSwitches.ParameterizedSwitch.Verbosity)); string[] parameters = switches[CommandLineSwitches.ParameterizedSwitch.Verbosity]; Assert.NotNull(parameters); Assert.Equal(1, parameters.Length); Assert.Equal("q", parameters[0]); // set it again -- this is bogus, because the /verbosity switch doesn't allow multiple parameters, but for the // purposes of testing the SetParameterizedSwitch() method, it doesn't matter Assert.True(switches.SetParameterizedSwitch(CommandLineSwitches.ParameterizedSwitch.Verbosity, "/verbosity:\"diag\";minimal", "\"diag\";minimal", true, true)); Assert.Equal("/v:q /verbosity:\"diag\";minimal", switches.GetParameterizedSwitchCommandLineArg(CommandLineSwitches.ParameterizedSwitch.Verbosity)); Assert.True(switches.IsParameterizedSwitchSet(CommandLineSwitches.ParameterizedSwitch.Verbosity)); parameters = switches[CommandLineSwitches.ParameterizedSwitch.Verbosity]; Assert.NotNull(parameters); Assert.Equal(3, parameters.Length); Assert.Equal("q", parameters[0]); Assert.Equal("diag", parameters[1]); Assert.Equal("minimal", parameters[2]); }
public void AppendParameterizedSwitchesTests3() { CommandLineSwitches switchesLeft = new CommandLineSwitches(); switchesLeft.SetParameterizedSwitch(CommandLineSwitches.ParameterizedSwitch.Project, "tempproject.proj", "tempproject.proj", false, true); Assert.True(switchesLeft.IsParameterizedSwitchSet(CommandLineSwitches.ParameterizedSwitch.Project)); CommandLineSwitches switchesRight = new CommandLineSwitches(); switchesRight.SetParameterizedSwitch(CommandLineSwitches.ParameterizedSwitch.Project, "Rhubarb.proj", "Rhubarb.proj", false, true); Assert.True(switchesRight.IsParameterizedSwitchSet(CommandLineSwitches.ParameterizedSwitch.Project)); switchesLeft.Append(switchesRight); Assert.Equal("tempproject.proj", switchesLeft.GetParameterizedSwitchCommandLineArg(CommandLineSwitches.ParameterizedSwitch.Project)); Assert.True(switchesLeft.IsParameterizedSwitchSet(CommandLineSwitches.ParameterizedSwitch.Project)); string[] parameters = switchesLeft[CommandLineSwitches.ParameterizedSwitch.Project]; Assert.NotNull(parameters); Assert.Equal(1, parameters.Length); Assert.Equal("tempproject.proj", parameters[0]); Assert.True(switchesLeft.HaveErrors()); VerifySwitchError(switchesLeft, "Rhubarb.proj"); }
public void AppendParameterizedSwitchesTests2() { CommandLineSwitches switchesLeft = new CommandLineSwitches(); switchesLeft.SetParameterizedSwitch(CommandLineSwitches.ParameterizedSwitch.Target, "/target:Clean", "Clean", true, true); Assert.True(switchesLeft.IsParameterizedSwitchSet(CommandLineSwitches.ParameterizedSwitch.Target)); CommandLineSwitches switchesRight = new CommandLineSwitches(); switchesRight.SetParameterizedSwitch(CommandLineSwitches.ParameterizedSwitch.Target, "/t:\"RESOURCES\";build", "\"RESOURCES\";build", true, true); Assert.True(switchesRight.IsParameterizedSwitchSet(CommandLineSwitches.ParameterizedSwitch.Target)); switchesLeft.Append(switchesRight); Assert.Equal("/t:\"RESOURCES\";build", switchesLeft.GetParameterizedSwitchCommandLineArg(CommandLineSwitches.ParameterizedSwitch.Target)); Assert.True(switchesLeft.IsParameterizedSwitchSet(CommandLineSwitches.ParameterizedSwitch.Target)); string[] parameters = switchesLeft[CommandLineSwitches.ParameterizedSwitch.Target]; Assert.NotNull(parameters); Assert.Equal(3, parameters.Length); Assert.Equal("Clean", parameters[0]); Assert.Equal("RESOURCES", parameters[1]); Assert.Equal("build", parameters[2]); }
/// <summary> /// Appends the given collection of command-line switches to this one. /// </summary> /// <remarks> /// Command-line switches have left-to-right precedence i.e. switches on the right override switches on the left. As a /// result, this "append" operation is also performed in a left-to-right manner -- the switches being appended to are /// considered to be on the "left", and the switches being appended are on the "right". /// </remarks> /// <param name="switchesToAppend"></param> internal void Append(CommandLineSwitches switchesToAppend) { // if this collection doesn't already have an error registered, but the collection being appended does if (!HaveErrors() && switchesToAppend.HaveErrors()) { // register the error from the given collection // NOTE: we always store the first error found (parsing left-to-right), and since this collection is considered to // be on the "left" of the collection being appended, the error flagged in this collection takes priority over the // error in the collection being appended _errorMessage = switchesToAppend._errorMessage; _badCommandLineArg = switchesToAppend._badCommandLineArg; _innerException = switchesToAppend._innerException; _isParameterError = switchesToAppend._isParameterError; } // NOTE: we might run into some duplicate switch errors below, but if we've already registered the error from the // collection being appended, all the duplicate switch errors will be ignored; this is fine because we really have no // way of telling which error would occur first in the left-to-right order without keeping track of a lot more error // information -- so we play it safe, and register the guaranteed error // append the parameterless switches with left-to-right precedence, flagging duplicate switches as necessary for (int i = 0; i < (int)ParameterlessSwitch.NumberOfParameterlessSwitches; i++) { if (switchesToAppend.IsParameterlessSwitchSet((ParameterlessSwitch)i)) { if (!IsParameterlessSwitchSet((ParameterlessSwitch)i) || (s_parameterlessSwitchesMap[i].duplicateSwitchErrorMessage == null)) { _parameterlessSwitches[i].commandLineArg = switchesToAppend._parameterlessSwitches[i].commandLineArg; } else { SetSwitchError(s_parameterlessSwitchesMap[i].duplicateSwitchErrorMessage, switchesToAppend.GetParameterlessSwitchCommandLineArg((ParameterlessSwitch)i)); } } } // append the parameterized switches with left-to-right precedence, flagging duplicate switches as necessary for (int j = 0; j < (int)ParameterizedSwitch.NumberOfParameterizedSwitches; j++) { if (switchesToAppend.IsParameterizedSwitchSet((ParameterizedSwitch)j)) { if (!IsParameterizedSwitchSet((ParameterizedSwitch)j) || (s_parameterizedSwitchesMap[j].duplicateSwitchErrorMessage == null)) { if (_parameterizedSwitches[j].commandLineArg == null) { _parameterizedSwitches[j].parameters = new ArrayList(); } _parameterizedSwitches[j].commandLineArg = switchesToAppend._parameterizedSwitches[j].commandLineArg; _parameterizedSwitches[j].parameters.AddRange(switchesToAppend._parameterizedSwitches[j].parameters); } else { SetSwitchError(s_parameterizedSwitchesMap[j].duplicateSwitchErrorMessage, switchesToAppend.GetParameterizedSwitchCommandLineArg((ParameterizedSwitch)j)); } } } }