2 // Parameters.cs: Class that contains information about command line parameters
5 // Marek Sieradzki (marek.sieradzki@gmail.com)
7 // (C) 2005 Marek Sieradzki
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System.Collections;
33 using System.Collections.Generic;
36 using System.Reflection;
37 using Microsoft.Build.BuildEngine;
38 using Microsoft.Build.Framework;
39 using Microsoft.Build.Utilities;
41 namespace Mono.XBuild.CommandLine {
42 public class Parameters {
44 string consoleLoggerParameters;
48 LoggerVerbosity loggerVerbosity;
52 BuildPropertyGroup properties;
53 IList remainingArguments;
54 Hashtable responseFiles;
57 string validationSchema;
64 consoleLoggerParameters = "";
66 loggers = new ArrayList ();
67 loggerVerbosity = LoggerVerbosity.Normal;
68 noConsoleLogger = false;
70 properties = new BuildPropertyGroup ();
71 targets = new string [0];
73 responseFile = Path.Combine (
74 Path.GetDirectoryName (Assembly.GetExecutingAssembly ().Location),
78 public void ParseArguments (string[] args)
80 bool autoResponse = true;
81 flatArguments = new ArrayList ();
82 remainingArguments = new ArrayList ();
83 responseFiles = new Hashtable ();
84 FileLoggerParameters = new string[10];
85 foreach (string s in args) {
86 if (s.StartsWith ("/noautoresponse") || s.StartsWith ("/noautorsp")) {
91 flatArguments.Add (s);
94 string responseFilename = Path.GetFullPath (UnquoteIfNeeded (s.Substring (1)));
95 if (responseFiles.ContainsKey (responseFilename))
96 ReportError (1, String.Format ("We already have {0} file.", responseFilename));
97 responseFiles [responseFilename] = responseFilename;
98 LoadResponseFile (responseFilename);
100 if (autoResponse == true) {
101 // FIXME: we do not allow nested auto response file
102 LoadResponseFile (responseFile);
104 foreach (string s in flatArguments) {
106 remainingArguments.Add (s);
107 else if (!ParseFlatArgument (s))
108 ReportError (1, "Unknown switch: " + s);
110 if (remainingArguments.Count == 0) {
111 string[] sln_files = Directory.GetFiles (Directory.GetCurrentDirectory (), "*.sln");
112 string[] proj_files = Directory.GetFiles (Directory.GetCurrentDirectory (), "*proj");
114 if (sln_files.Length == 0 && proj_files.Length == 0)
115 ReportError (3, "Please specify the project or solution file " +
116 "to build, as none was found in the current directory.");
118 if (sln_files.Length == 1 && proj_files.Length > 0) {
119 var projects_table = new Dictionary<string, string> ();
120 foreach (string pfile in SolutionParser.GetAllProjectFileNames (sln_files [0])) {
121 string full_path = Path.GetFullPath (pfile);
122 projects_table [full_path] = full_path;
125 if (!proj_files.Any (p => !projects_table.ContainsKey (Path.GetFullPath (p))))
126 // if all the project files in the cur dir, are referenced
127 // from the single .sln in the cur dir, then pick the sln
128 proj_files = new string [0];
131 if (sln_files.Length + proj_files.Length > 1)
132 ReportError (5, "Please specify the project or solution file " +
133 "to build, as more than one solution or project file was found " +
134 "in the current directory");
136 if (sln_files.Length == 1)
137 projectFile = sln_files [0];
139 projectFile = proj_files [0];
140 } else if (remainingArguments.Count == 1) {
141 projectFile = (string) remainingArguments [0];
143 ReportError (4, "Too many project files specified");
147 private string UnquoteIfNeeded(string arg)
149 if (arg.StartsWith("\""))
150 return arg.Substring(1, arg.Length - 2);
154 void LoadResponseFile (string filename)
156 StreamReader sr = null;
159 sr = new StreamReader (filename);
160 StringBuilder sb = new StringBuilder ();
162 while ((line = sr.ReadLine ()) != null) {
165 for (int i = 0; i < t; i++) {
169 // comment, ignore rest of the line
172 if (c == '"' || c == '\'') {
175 for (i++; i < t; i++) {
182 } else if (c == ' ') {
184 flatArguments.Add (sb.ToString ());
191 flatArguments.Add (sb.ToString ());
195 } catch (IOException x) {
196 ErrorUtilities.ReportWarning (2, String.Format (
197 "Error loading response file. (Exception: {0}). Ignoring.",
205 private bool ParseFlatArgument (string s)
211 ErrorUtilities.ShowUsage ();
218 ErrorUtilities.ShowVersion (true);
220 case "/noconsolelogger":
222 noConsoleLogger = true;
230 if (FileLoggerParameters [0] == null)
231 FileLoggerParameters [0] = String.Empty;
234 if (s.StartsWith ("/fl") && s.Length == 4 && Char.IsDigit (s[3])) {
235 int index = Int32.Parse (s[3].ToString ());
236 if (FileLoggerParameters [index] == null)
237 FileLoggerParameters [index] = String.Empty;
238 } else if (s.StartsWith ("/fileloggerparameters") || s.StartsWith ("/flp")) {
239 ProcessFileLoggerParameters (s);
240 } else if (s.StartsWith ("/target:") || s.StartsWith ("/t:")) {
242 } else if (s.StartsWith ("/property:") || s.StartsWith ("/p:")) {
243 if (!ProcessProperty (s))
245 } else if (s.StartsWith ("/logger:") || s.StartsWith ("/l:")) {
247 } else if (s.StartsWith ("/verbosity:") || s.StartsWith ("/v:")) {
248 ProcessVerbosity (s);
249 } else if (s.StartsWith ("/consoleloggerparameters:") || s.StartsWith ("/clp:")) {
250 ProcessConsoleLoggerParameters (s);
251 } else if (s.StartsWith ("/validate:") || s.StartsWith ("/val:")) {
253 } else if (s.StartsWith ("/toolsversion:") || s.StartsWith ("/tv:")) {
254 ToolsVersion = s.Split (':') [1];
263 internal void ProcessTarget (string s)
265 TryProcessMultiOption (s, "Target names must be specified as /t:Target1;Target2",
269 internal bool ProcessProperty (string s)
271 string[] splitProperties;
272 if (!TryProcessMultiOption (s, "Property name and value expected as /p:<prop name>=<prop value>",
273 out splitProperties))
276 foreach (string st in splitProperties) {
277 if (st.IndexOf ('=') < 0) {
279 "Invalid syntax. Property name and value expected as " +
280 "<prop name>=[<prop value>]");
283 string [] property = st.Split ('=');
284 properties.SetProperty (property [0], property.Length == 2 ? property [1] : "");
290 bool TryProcessMultiOption (string s, string error_message, out string[] values)
293 int colon = s.IndexOf (':');
294 if (colon + 1 == s.Length) {
295 ReportError (5, error_message);
299 values = s.Substring (colon + 1).Split (';');
303 private void ReportError (int errorCode, string message)
305 throw new CommandLineException (message, errorCode);
308 private void ReportError (int errorCode, string message, Exception cause)
310 throw new CommandLineException (message, cause, errorCode);
313 internal void ProcessLogger (string s)
315 loggers.Add (new LoggerInfo (s));
318 internal void ProcessVerbosity (string s)
320 string[] temp = s.Split (':');
324 loggerVerbosity = LoggerVerbosity.Quiet;
328 loggerVerbosity = LoggerVerbosity.Minimal;
332 loggerVerbosity = LoggerVerbosity.Normal;
336 loggerVerbosity = LoggerVerbosity.Detailed;
340 loggerVerbosity = LoggerVerbosity.Diagnostic;
345 void ProcessFileLoggerParameters (string s)
347 int colon = s.IndexOf (':');
348 if (colon + 1 == s.Length)
349 ReportError (5, "Invalid syntax, specify parameters as /fileloggerparameters[n]:parameters");
352 string key = s.Substring (0, colon);
353 if (Char.IsDigit (key [key.Length - 1]))
354 //if (key.Length == 22 && Char.IsDigit (key [21]))
355 index = Int32.Parse (key [key.Length - 1].ToString ());
357 FileLoggerParameters [index] = s.Substring (colon + 1);
360 internal void ProcessConsoleLoggerParameters (string s)
362 int colon = s.IndexOf (':');
363 if (colon + 1 == s.Length)
364 ReportError (5, "Invalid syntax, specify parameters as /clp:parameters");
366 consoleLoggerParameters = s.Substring (colon + 1);
369 internal void ProcessValidate (string s)
373 temp = s.Split (':');
374 validationSchema = temp [1];
376 public bool DisplayHelp {
377 get { return displayHelp; }
381 get { return noLogo; }
384 public string ProjectFile {
385 get { return projectFile; }
388 public string[] Targets {
389 get { return targets; }
392 public BuildPropertyGroup Properties {
393 get { return properties; }
396 public IList Loggers {
397 get { return loggers; }
400 public LoggerVerbosity LoggerVerbosity {
401 get { return loggerVerbosity; }
404 public string ConsoleLoggerParameters {
405 get { return consoleLoggerParameters; }
408 public bool NoConsoleLogger {
409 get { return noConsoleLogger; }
412 public string[] FileLoggerParameters { get; set; }
414 public bool Validate {
415 get { return validate; }
418 public string ValidationSchema {
419 get { return validationSchema; }
422 public string ToolsVersion {
423 get { return toolsVersion; }
424 private set { toolsVersion = value; }