Wed Feb 24 15:47:16 CET 2010 Paolo Molaro <lupus@ximian.com>
[mono.git] / mcs / tools / xbuild / Parameters.cs
1 //
2 // Parameters.cs: Class that contains information about command line parameters
3 //
4 // Author:
5 //   Marek Sieradzki (marek.sieradzki@gmail.com)
6 //
7 // (C) 2005 Marek Sieradzki
8 //
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:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
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.
27
28 #if NET_2_0
29
30 using System;
31 using System.IO;
32 using System.Collections;
33 using System.Collections.Generic;
34 using System.Linq;
35 using System.Text;
36 using System.Reflection;
37 using Microsoft.Build.BuildEngine;
38 using Microsoft.Build.Framework;
39 using Microsoft.Build.Utilities;
40
41 namespace Mono.XBuild.CommandLine {
42         public class Parameters {
43         
44                 string                  consoleLoggerParameters;
45                 bool                    displayHelp;
46                 bool                    displayVersion;
47                 IList                   flatArguments;
48                 IList                   loggers;
49                 LoggerVerbosity         loggerVerbosity;
50                 bool                    noConsoleLogger;
51                 bool                    noLogo;
52                 string                  projectFile;
53                 BuildPropertyGroup      properties;
54                 IList                   remainingArguments;
55                 Hashtable               responseFiles;
56                 string[]                targets;
57                 bool                    validate;
58                 string                  validationSchema;
59                 
60                 string                  responseFile;
61         
62                 public Parameters (string binPath)
63                 {
64                         consoleLoggerParameters = "";
65                         displayHelp = false;
66                         displayVersion = true;
67                         loggers = new ArrayList ();
68                         loggerVerbosity = LoggerVerbosity.Normal;
69                         noConsoleLogger = false;
70                         noLogo = false;
71                         properties = new BuildPropertyGroup ();
72                         targets = new string [0];
73                         
74                         responseFile = Path.Combine (
75                                         Path.GetDirectoryName (Assembly.GetExecutingAssembly ().Location),
76                                         "xbuild.rsp");
77                 }
78                 
79                 public void ParseArguments (string[] args)
80                 {
81                         bool autoResponse = true;
82                         flatArguments = new ArrayList ();
83                         remainingArguments = new ArrayList ();
84                         responseFiles = new Hashtable ();
85                         foreach (string s in args) {
86                                 if (s.StartsWith ("/noautoresponse") || s.StartsWith ("/noautorsp")) {
87                                         autoResponse = false;
88                                         continue;
89                                 }
90                                 if (s [0] != '@') {
91                                         flatArguments.Add (s);
92                                         continue;
93                                 }
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);
99                         }
100                         if (autoResponse == true) {
101                                 // FIXME: we do not allow nested auto response file
102                                 LoadResponseFile (responseFile);
103                         }
104                         foreach (string s in flatArguments) {
105                                 if (s [0] != '/' || !ParseFlatArgument (s))
106                                         remainingArguments.Add (s);
107                         }
108                         if (remainingArguments.Count == 0) {
109                                 string[] sln_files = Directory.GetFiles (Directory.GetCurrentDirectory (), "*.sln");
110                                 string[] proj_files = Directory.GetFiles (Directory.GetCurrentDirectory (), "*proj");
111
112                                 if (sln_files.Length == 0 && proj_files.Length == 0)
113                                         ReportError (3, "Please specify the project or solution file " +
114                                                         "to build, as none was found in the current directory.");
115
116                                 if (sln_files.Length == 1 && proj_files.Length > 0) {
117                                         var projects_table = new Dictionary<string, string> ();
118                                         foreach (string pfile in SolutionParser.GetAllProjectFileNames (sln_files [0])) {
119                                                 string full_path = Path.GetFullPath (pfile);
120                                                 projects_table [full_path] = full_path;
121                                         }
122
123                                         if (!proj_files.Any (p => !projects_table.ContainsKey (Path.GetFullPath (p))))
124                                                 // if all the project files in the cur dir, are referenced
125                                                 // from the single .sln in the cur dir, then pick the sln
126                                                 proj_files = new string [0];
127                                 }
128
129                                 if (sln_files.Length + proj_files.Length > 1)
130                                         ReportError (5, "Please specify the project or solution file " +
131                                                         "to build, as more than one solution or project file was found " +
132                                                         "in the current directory");
133
134                                 if (sln_files.Length == 1)
135                                         projectFile = sln_files [0];
136                                 else
137                                         projectFile = proj_files [0];
138                         } else if (remainingArguments.Count == 1) {
139                                 projectFile = (string) remainingArguments [0];
140                         } else {
141                                 ReportError (4, "Too many project files specified");
142                         }
143                 }
144
145                 private string UnquoteIfNeeded(string arg)
146                 {
147                         if (arg.StartsWith("\""))
148                                 return arg.Substring(1, arg.Length - 2);
149                         return arg;
150                 }
151
152                 void LoadResponseFile (string filename)
153                 {
154                         StreamReader sr = null;
155                         string line;
156                         try {
157                                 sr = new StreamReader (filename);
158                                 StringBuilder sb = new StringBuilder ();
159
160                                 while ((line = sr.ReadLine ()) != null) {
161                                         int t = line.Length;
162
163                                         for (int i = 0; i < t; i++) {
164                                                 char c = line [i];
165
166                                                 if (c == '#')
167                                                         // comment, ignore rest of the line
168                                                         break;
169
170                                                 if (c == '"' || c == '\'') {
171                                                         char end = c;
172
173                                                         for (i++; i < t; i++) {
174                                                                 c = line [i];
175
176                                                                 if (c == end)
177                                                                         break;
178                                                                 sb.Append (c);
179                                                         }
180                                                 } else if (c == ' ') {
181                                                         if (sb.Length > 0) {
182                                                                 flatArguments.Add (sb.ToString ());
183                                                                 sb.Length = 0;
184                                                         }
185                                                 } else
186                                                         sb.Append (c);
187                                         }
188                                         if (sb.Length > 0){
189                                                 flatArguments.Add (sb.ToString ());
190                                                 sb.Length = 0;
191                                         }
192                                 }
193                         } catch (Exception x) {
194                                 ReportError (2, "Error during loading response file.", x);
195                         } finally {
196                                 if (sr != null)
197                                         sr.Close ();
198                         }
199                 }
200                 
201                 private bool ParseFlatArgument (string s)
202                 {
203                         switch (s) {
204                         case "/help":
205                         case "/h":
206                         case "/?":
207                                 ErrorUtilities.ShowUsage ();
208                                 break;
209                         case "/nologo":
210                                 noLogo = true;
211                                 break;
212                         case "/version":
213                         case "/ver":
214                                 ErrorUtilities.ShowVersion (true);
215                                 break;
216                         case "/noconsolelogger":
217                         case "/noconlog":
218                                 noConsoleLogger = true;
219                                 break;
220                         case "/validate":
221                         case "/val":
222                                 validate = true;
223                                 break;
224                         default:
225                                 if (s.StartsWith ("/target:") || s.StartsWith ("/t:")) {
226                                         ProcessTarget (s);
227                                 } else if (s.StartsWith ("/property:") || s.StartsWith ("/p:")) {
228                                         if (!ProcessProperty (s))
229                                                 return false;
230                                 } else  if (s.StartsWith ("/logger:") || s.StartsWith ("/l:")) {
231                                         ProcessLogger (s);
232                                 } else if (s.StartsWith ("/verbosity:") || s.StartsWith ("/v:")) {
233                                         ProcessVerbosity (s);
234                                 } else if (s.StartsWith ("/consoleloggerparameters:") || s.StartsWith ("/clp:")) {
235                                         ProcessConsoleLoggerParameters (s);
236                                 } else if (s.StartsWith ("/validate:") || s.StartsWith ("/val:")) {
237                                         ProcessValidate (s);
238                                 } else
239                                         return false;
240                                 break;
241                         }
242
243                         return true;
244                 }
245                 
246                 internal void ProcessTarget (string s)
247                 {
248                         TryProcessMultiOption (s, "Target names must be specified as /t:Target1;Target2",
249                                                 out targets);
250                 }
251                 
252                 internal bool ProcessProperty (string s)
253                 {
254                         string[] splitProperties;
255                         if (!TryProcessMultiOption (s, "Property name and value expected as /p:<prop name>=<prop value>",
256                                                 out splitProperties))
257                                 return false;
258
259                         foreach (string st in splitProperties) {
260                                 if (st.IndexOf ('=') < 0) {
261                                         ReportError (5,
262                                                         "Invalid syntax. Property name and value expected as " +
263                                                         "<prop name>=[<prop value>]");
264                                         return false;
265                                 }
266                                 string [] property = st.Split ('=');
267                                 properties.SetProperty (property [0], property.Length == 2 ? property [1] : "");
268                         }
269
270                         return true;
271                 }
272
273                 bool TryProcessMultiOption (string s, string error_message, out string[] values)
274                 {
275                         values = null;
276                         int colon = s.IndexOf (':');
277                         if (colon + 1 == s.Length) {
278                                 ReportError (5, error_message);
279                                 return false;
280                         }
281
282                         values = s.Substring (colon + 1).Split (';');
283                         return true;
284                 }
285
286                 private void ReportError (int errorCode, string message)
287                 {
288                         throw new CommandLineException (message, errorCode);
289                 }
290
291                 private void ReportError (int errorCode, string message, Exception cause)
292                 {
293                         throw new CommandLineException (message, cause, errorCode);
294                 }
295
296                 internal void ProcessLogger (string s)
297                 {
298                         loggers.Add (new LoggerInfo (s));
299                 }
300                 
301                 internal void ProcessVerbosity (string s)
302                 {
303                         string[] temp = s.Split (':');
304                         switch (temp [1]) {
305                         case "q":
306                         case "quiet":
307                                 loggerVerbosity = LoggerVerbosity.Quiet;
308                                 break;
309                         case "m":
310                         case "minimal":
311                                 loggerVerbosity = LoggerVerbosity.Minimal;
312                                 break;
313                         case "n":
314                         case "normal":
315                                 loggerVerbosity = LoggerVerbosity.Normal;
316                                 break;
317                         case "d":
318                         case "detailed":
319                                 loggerVerbosity = LoggerVerbosity.Detailed;
320                                 break;
321                         case "diag":
322                         case "diagnostic":
323                                 loggerVerbosity = LoggerVerbosity.Diagnostic;
324                                 break;
325                         }
326                 }
327                 
328                 internal void ProcessConsoleLoggerParameters (string s)
329                 {
330                         consoleLoggerParameters = s; 
331                 }
332                 
333                 internal void ProcessValidate (string s)
334                 {
335                         string[] temp;
336                         validate = true;
337                         temp = s.Split (':');
338                         validationSchema = temp [1];
339                 }
340                 public bool DisplayHelp {
341                         get { return displayHelp; }
342                 }
343                 
344                 public bool NoLogo {
345                         get { return noLogo; }
346                 }
347                 
348                 public bool DisplayVersion {
349                         get { return displayVersion; }
350                 }
351                 
352                 public string ProjectFile {
353                         get { return projectFile; }
354                 }
355                 
356                 public string[] Targets {
357                         get { return targets; }
358                 }
359                 
360                 public BuildPropertyGroup Properties {
361                         get { return properties; }
362                 }
363                 
364                 public IList Loggers {
365                         get { return loggers; }
366                 }
367                 
368                 public LoggerVerbosity LoggerVerbosity {
369                         get { return loggerVerbosity; }
370                 }
371                 
372                 public string ConsoleLoggerParameters {
373                         get { return consoleLoggerParameters; }
374                 }
375                 
376                 public bool NoConsoleLogger {
377                         get { return noConsoleLogger; }
378                 }
379                 
380                 public bool Validate {
381                         get { return validate; }
382                 }
383                 
384                 public string ValidationSchema {
385                         get { return validationSchema; }
386                 }
387                 
388         }
389 }
390
391 #endif