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.
31 using System
.Collections
;
32 using System
.Collections
.Generic
;
35 using System
.Reflection
;
36 using Microsoft
.Build
.BuildEngine
;
37 using Microsoft
.Build
.Framework
;
38 using Microsoft
.Build
.Utilities
;
40 namespace Mono
.XBuild
.CommandLine
{
41 public class Parameters
{
43 string consoleLoggerParameters
;
47 LoggerVerbosity loggerVerbosity
;
51 BuildPropertyGroup properties
;
52 IList remainingArguments
;
53 Hashtable responseFiles
;
56 string validationSchema
;
63 consoleLoggerParameters
= "";
65 loggers
= new ArrayList ();
66 loggerVerbosity
= LoggerVerbosity
.Normal
;
67 noConsoleLogger
= false;
69 properties
= new BuildPropertyGroup ();
70 targets
= new string [0];
72 responseFile
= Path
.Combine (
73 Path
.GetDirectoryName (Assembly
.GetExecutingAssembly ().Location
),
77 public void ParseArguments (string[] args
)
79 bool autoResponse
= true;
80 flatArguments
= new ArrayList ();
81 remainingArguments
= new ArrayList ();
82 responseFiles
= new Hashtable ();
83 FileLoggerParameters
= new string[10];
84 foreach (string s
in args
) {
85 if (s
.StartsWith ("/noautoresponse") || s
.StartsWith ("/noautorsp")) {
90 flatArguments
.Add (s
);
93 string responseFilename
= Path
.GetFullPath (UnquoteIfNeeded (s
.Substring (1)));
94 if (responseFiles
.ContainsKey (responseFilename
))
95 ReportError (1, String
.Format ("We already have {0} file.", responseFilename
));
96 responseFiles
[responseFilename
] = responseFilename
;
97 LoadResponseFile (responseFilename
);
99 if (autoResponse
== true) {
100 // FIXME: we do not allow nested auto response file
101 LoadResponseFile (responseFile
);
103 foreach (string s
in flatArguments
) {
104 if (s
[0] != '/' || !ParseFlatArgument (s
))
105 remainingArguments
.Add (s
);
107 if (remainingArguments
.Count
== 0) {
108 string[] sln_files
= Directory
.GetFiles (Directory
.GetCurrentDirectory (), "*.sln");
109 string[] proj_files
= Directory
.GetFiles (Directory
.GetCurrentDirectory (), "*proj");
111 if (sln_files
.Length
== 0 && proj_files
.Length
== 0)
112 ReportError (3, "Please specify the project or solution file " +
113 "to build, as none was found in the current directory.");
115 if (sln_files
.Length
== 1 && proj_files
.Length
> 0) {
116 var projects_table
= new Dictionary
<string, string> ();
117 foreach (string pfile
in SolutionParser
.GetAllProjectFileNames (sln_files
[0])) {
118 string full_path
= Path
.GetFullPath (pfile
);
119 projects_table
[full_path
] = full_path
;
122 if (!proj_files
.Any (p
=> !projects_table
.ContainsKey (Path
.GetFullPath (p
))))
123 // if all the project files in the cur dir, are referenced
124 // from the single .sln in the cur dir, then pick the sln
125 proj_files
= new string [0];
128 if (sln_files
.Length
+ proj_files
.Length
> 1)
129 ReportError (5, "Please specify the project or solution file " +
130 "to build, as more than one solution or project file was found " +
131 "in the current directory");
133 if (sln_files
.Length
== 1)
134 projectFile
= sln_files
[0];
136 projectFile
= proj_files
[0];
137 } else if (remainingArguments
.Count
== 1) {
138 projectFile
= (string) remainingArguments
[0];
140 ReportError (4, "Too many project files specified");
144 private string UnquoteIfNeeded(string arg
)
146 if (arg
.StartsWith("\""))
147 return arg
.Substring(1, arg
.Length
- 2);
151 void LoadResponseFile (string filename
)
153 StreamReader sr
= null;
156 sr
= new StreamReader (filename
);
157 StringBuilder sb
= new StringBuilder ();
159 while ((line
= sr
.ReadLine ()) != null) {
162 for (int i
= 0; i
< t
; i
++) {
166 // comment, ignore rest of the line
169 if (c
== '"' || c
== '\'') {
172 for (i
++; i
< t
; i
++) {
179 } else if (c
== ' ') {
181 flatArguments
.Add (sb
.ToString ());
188 flatArguments
.Add (sb
.ToString ());
192 } catch (IOException x
) {
193 ErrorUtilities
.ReportWarning (2, String
.Format (
194 "Error loading response file. (Exception: {0}). Ignoring.",
202 private bool ParseFlatArgument (string s
)
208 ErrorUtilities
.ShowUsage ();
215 ErrorUtilities
.ShowVersion (true);
217 case "/noconsolelogger":
219 noConsoleLogger
= true;
227 if (FileLoggerParameters
[0] == null)
228 FileLoggerParameters
[0] = String
.Empty
;
231 if (s
.StartsWith ("/fl") && s
.Length
== 4 && Char
.IsDigit (s
[3])) {
232 int index
= Int32
.Parse (s
[3].ToString ());
233 if (FileLoggerParameters
[index
] == null)
234 FileLoggerParameters
[index
] = String
.Empty
;
235 } else if (s
.StartsWith ("/fileloggerparameters") || s
.StartsWith ("/flp")) {
236 ProcessFileLoggerParameters (s
);
237 } else if (s
.StartsWith ("/target:") || s
.StartsWith ("/t:")) {
239 } else if (s
.StartsWith ("/property:") || s
.StartsWith ("/p:")) {
240 if (!ProcessProperty (s
))
242 } else if (s
.StartsWith ("/logger:") || s
.StartsWith ("/l:")) {
244 } else if (s
.StartsWith ("/verbosity:") || s
.StartsWith ("/v:")) {
245 ProcessVerbosity (s
);
246 } else if (s
.StartsWith ("/consoleloggerparameters:") || s
.StartsWith ("/clp:")) {
247 ProcessConsoleLoggerParameters (s
);
248 } else if (s
.StartsWith ("/validate:") || s
.StartsWith ("/val:")) {
250 } else if (s
.StartsWith ("/toolsversion:") || s
.StartsWith ("/tv:")) {
251 ToolsVersion
= s
.Split (':') [1];
260 internal void ProcessTarget (string s
)
262 TryProcessMultiOption (s
, "Target names must be specified as /t:Target1;Target2",
266 internal bool ProcessProperty (string s
)
268 string[] splitProperties
;
269 if (!TryProcessMultiOption (s
, "Property name and value expected as /p:<prop name>=<prop value>",
270 out splitProperties
))
273 foreach (string st
in splitProperties
) {
274 if (st
.IndexOf ('=') < 0) {
276 "Invalid syntax. Property name and value expected as " +
277 "<prop name>=[<prop value>]");
280 string [] property
= st
.Split ('=');
281 properties
.SetProperty (property
[0], property
.Length
== 2 ? property
[1] : "");
287 bool TryProcessMultiOption (string s
, string error_message
, out string[] values
)
290 int colon
= s
.IndexOf (':');
291 if (colon
+ 1 == s
.Length
) {
292 ReportError (5, error_message
);
296 values
= s
.Substring (colon
+ 1).Split (';');
300 private void ReportError (int errorCode
, string message
)
302 throw new CommandLineException (message
, errorCode
);
305 private void ReportError (int errorCode
, string message
, Exception cause
)
307 throw new CommandLineException (message
, cause
, errorCode
);
310 internal void ProcessLogger (string s
)
312 loggers
.Add (new LoggerInfo (s
));
315 internal void ProcessVerbosity (string s
)
317 string[] temp
= s
.Split (':');
321 loggerVerbosity
= LoggerVerbosity
.Quiet
;
325 loggerVerbosity
= LoggerVerbosity
.Minimal
;
329 loggerVerbosity
= LoggerVerbosity
.Normal
;
333 loggerVerbosity
= LoggerVerbosity
.Detailed
;
337 loggerVerbosity
= LoggerVerbosity
.Diagnostic
;
342 void ProcessFileLoggerParameters (string s
)
344 int colon
= s
.IndexOf (':');
345 if (colon
+ 1 == s
.Length
)
346 ReportError (5, "Invalid syntax, specify parameters as /fileloggerparameters[n]:parameters");
349 string key
= s
.Substring (0, colon
);
350 if (Char
.IsDigit (key
[key
.Length
- 1]))
351 //if (key.Length == 22 && Char.IsDigit (key [21]))
352 index
= Int32
.Parse (key
[key
.Length
- 1].ToString ());
354 FileLoggerParameters
[index
] = s
.Substring (colon
+ 1);
357 internal void ProcessConsoleLoggerParameters (string s
)
359 int colon
= s
.IndexOf (':');
360 if (colon
+ 1 == s
.Length
)
361 ReportError (5, "Invalid syntax, specify parameters as /clp:parameters");
363 consoleLoggerParameters
= s
.Substring (colon
+ 1);
366 internal void ProcessValidate (string s
)
370 temp
= s
.Split (':');
371 validationSchema
= temp
[1];
373 public bool DisplayHelp
{
374 get { return displayHelp; }
378 get { return noLogo; }
381 public string ProjectFile
{
382 get { return projectFile; }
385 public string[] Targets
{
386 get { return targets; }
389 public BuildPropertyGroup Properties
{
390 get { return properties; }
393 public IList Loggers
{
394 get { return loggers; }
397 public LoggerVerbosity LoggerVerbosity
{
398 get { return loggerVerbosity; }
401 public string ConsoleLoggerParameters
{
402 get { return consoleLoggerParameters; }
405 public bool NoConsoleLogger
{
406 get { return noConsoleLogger; }
409 public string[] FileLoggerParameters { get; set; }
411 public bool Validate
{
412 get { return validate; }
415 public string ValidationSchema
{
416 get { return validationSchema; }
419 public string ToolsVersion
{
420 get { return toolsVersion; }
421 private set { toolsVersion = value; }