2010-05-25 Jb Evain <jbevain@novell.com>
[mcs.git] / tools / xbuild / Parameters.cs
blob8cb4f5d7498fe1cb55f9bec295f18f9dbfc32a26
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:
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.
28 #if NET_2_0
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;
41 namespace Mono.XBuild.CommandLine {
42 public class Parameters {
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 string toolsVersion;
61 string responseFile;
63 public Parameters ()
65 consoleLoggerParameters = "";
66 displayHelp = false;
67 displayVersion = true;
68 loggers = new ArrayList ();
69 loggerVerbosity = LoggerVerbosity.Normal;
70 noConsoleLogger = false;
71 noLogo = false;
72 properties = new BuildPropertyGroup ();
73 targets = new string [0];
75 responseFile = Path.Combine (
76 Path.GetDirectoryName (Assembly.GetExecutingAssembly ().Location),
77 "xbuild.rsp");
80 public void ParseArguments (string[] args)
82 bool autoResponse = true;
83 flatArguments = new ArrayList ();
84 remainingArguments = new ArrayList ();
85 responseFiles = new Hashtable ();
86 foreach (string s in args) {
87 if (s.StartsWith ("/noautoresponse") || s.StartsWith ("/noautorsp")) {
88 autoResponse = false;
89 continue;
91 if (s [0] != '@') {
92 flatArguments.Add (s);
93 continue;
95 string responseFilename = Path.GetFullPath (UnquoteIfNeeded (s.Substring (1)));
96 if (responseFiles.ContainsKey (responseFilename))
97 ReportError (1, String.Format ("We already have {0} file.", responseFilename));
98 responseFiles [responseFilename] = responseFilename;
99 LoadResponseFile (responseFilename);
101 if (autoResponse == true) {
102 // FIXME: we do not allow nested auto response file
103 LoadResponseFile (responseFile);
105 foreach (string s in flatArguments) {
106 if (s [0] != '/' || !ParseFlatArgument (s))
107 remainingArguments.Add (s);
109 if (remainingArguments.Count == 0) {
110 string[] sln_files = Directory.GetFiles (Directory.GetCurrentDirectory (), "*.sln");
111 string[] proj_files = Directory.GetFiles (Directory.GetCurrentDirectory (), "*proj");
113 if (sln_files.Length == 0 && proj_files.Length == 0)
114 ReportError (3, "Please specify the project or solution file " +
115 "to build, as none was found in the current directory.");
117 if (sln_files.Length == 1 && proj_files.Length > 0) {
118 var projects_table = new Dictionary<string, string> ();
119 foreach (string pfile in SolutionParser.GetAllProjectFileNames (sln_files [0])) {
120 string full_path = Path.GetFullPath (pfile);
121 projects_table [full_path] = full_path;
124 if (!proj_files.Any (p => !projects_table.ContainsKey (Path.GetFullPath (p))))
125 // if all the project files in the cur dir, are referenced
126 // from the single .sln in the cur dir, then pick the sln
127 proj_files = new string [0];
130 if (sln_files.Length + proj_files.Length > 1)
131 ReportError (5, "Please specify the project or solution file " +
132 "to build, as more than one solution or project file was found " +
133 "in the current directory");
135 if (sln_files.Length == 1)
136 projectFile = sln_files [0];
137 else
138 projectFile = proj_files [0];
139 } else if (remainingArguments.Count == 1) {
140 projectFile = (string) remainingArguments [0];
141 } else {
142 ReportError (4, "Too many project files specified");
146 private string UnquoteIfNeeded(string arg)
148 if (arg.StartsWith("\""))
149 return arg.Substring(1, arg.Length - 2);
150 return arg;
153 void LoadResponseFile (string filename)
155 StreamReader sr = null;
156 string line;
157 try {
158 sr = new StreamReader (filename);
159 StringBuilder sb = new StringBuilder ();
161 while ((line = sr.ReadLine ()) != null) {
162 int t = line.Length;
164 for (int i = 0; i < t; i++) {
165 char c = line [i];
167 if (c == '#')
168 // comment, ignore rest of the line
169 break;
171 if (c == '"' || c == '\'') {
172 char end = c;
174 for (i++; i < t; i++) {
175 c = line [i];
177 if (c == end)
178 break;
179 sb.Append (c);
181 } else if (c == ' ') {
182 if (sb.Length > 0) {
183 flatArguments.Add (sb.ToString ());
184 sb.Length = 0;
186 } else
187 sb.Append (c);
189 if (sb.Length > 0){
190 flatArguments.Add (sb.ToString ());
191 sb.Length = 0;
194 } catch (IOException x) {
195 ErrorUtilities.ReportWarning (2, String.Format (
196 "Error loading response file. (Exception: {0}). Ignoring.",
197 x.Message));
198 } finally {
199 if (sr != null)
200 sr.Close ();
204 private bool ParseFlatArgument (string s)
206 switch (s) {
207 case "/help":
208 case "/h":
209 case "/?":
210 ErrorUtilities.ShowUsage ();
211 break;
212 case "/nologo":
213 noLogo = true;
214 break;
215 case "/version":
216 case "/ver":
217 ErrorUtilities.ShowVersion (true);
218 break;
219 case "/noconsolelogger":
220 case "/noconlog":
221 noConsoleLogger = true;
222 break;
223 case "/validate":
224 case "/val":
225 validate = true;
226 break;
227 default:
228 if (s.StartsWith ("/target:") || s.StartsWith ("/t:")) {
229 ProcessTarget (s);
230 } else if (s.StartsWith ("/property:") || s.StartsWith ("/p:")) {
231 if (!ProcessProperty (s))
232 return false;
233 } else if (s.StartsWith ("/logger:") || s.StartsWith ("/l:")) {
234 ProcessLogger (s);
235 } else if (s.StartsWith ("/verbosity:") || s.StartsWith ("/v:")) {
236 ProcessVerbosity (s);
237 } else if (s.StartsWith ("/consoleloggerparameters:") || s.StartsWith ("/clp:")) {
238 ProcessConsoleLoggerParameters (s);
239 } else if (s.StartsWith ("/validate:") || s.StartsWith ("/val:")) {
240 ProcessValidate (s);
241 } else if (s.StartsWith ("/toolsversion:") || s.StartsWith ("/tv:")) {
242 ToolsVersion = s.Split (':') [1];
243 } else
244 return false;
245 break;
248 return true;
251 internal void ProcessTarget (string s)
253 TryProcessMultiOption (s, "Target names must be specified as /t:Target1;Target2",
254 out targets);
257 internal bool ProcessProperty (string s)
259 string[] splitProperties;
260 if (!TryProcessMultiOption (s, "Property name and value expected as /p:<prop name>=<prop value>",
261 out splitProperties))
262 return false;
264 foreach (string st in splitProperties) {
265 if (st.IndexOf ('=') < 0) {
266 ReportError (5,
267 "Invalid syntax. Property name and value expected as " +
268 "<prop name>=[<prop value>]");
269 return false;
271 string [] property = st.Split ('=');
272 properties.SetProperty (property [0], property.Length == 2 ? property [1] : "");
275 return true;
278 bool TryProcessMultiOption (string s, string error_message, out string[] values)
280 values = null;
281 int colon = s.IndexOf (':');
282 if (colon + 1 == s.Length) {
283 ReportError (5, error_message);
284 return false;
287 values = s.Substring (colon + 1).Split (';');
288 return true;
291 private void ReportError (int errorCode, string message)
293 throw new CommandLineException (message, errorCode);
296 private void ReportError (int errorCode, string message, Exception cause)
298 throw new CommandLineException (message, cause, errorCode);
301 internal void ProcessLogger (string s)
303 loggers.Add (new LoggerInfo (s));
306 internal void ProcessVerbosity (string s)
308 string[] temp = s.Split (':');
309 switch (temp [1]) {
310 case "q":
311 case "quiet":
312 loggerVerbosity = LoggerVerbosity.Quiet;
313 break;
314 case "m":
315 case "minimal":
316 loggerVerbosity = LoggerVerbosity.Minimal;
317 break;
318 case "n":
319 case "normal":
320 loggerVerbosity = LoggerVerbosity.Normal;
321 break;
322 case "d":
323 case "detailed":
324 loggerVerbosity = LoggerVerbosity.Detailed;
325 break;
326 case "diag":
327 case "diagnostic":
328 loggerVerbosity = LoggerVerbosity.Diagnostic;
329 break;
333 internal void ProcessConsoleLoggerParameters (string s)
335 consoleLoggerParameters = s;
338 internal void ProcessValidate (string s)
340 string[] temp;
341 validate = true;
342 temp = s.Split (':');
343 validationSchema = temp [1];
345 public bool DisplayHelp {
346 get { return displayHelp; }
349 public bool NoLogo {
350 get { return noLogo; }
353 public bool DisplayVersion {
354 get { return displayVersion; }
357 public string ProjectFile {
358 get { return projectFile; }
361 public string[] Targets {
362 get { return targets; }
365 public BuildPropertyGroup Properties {
366 get { return properties; }
369 public IList Loggers {
370 get { return loggers; }
373 public LoggerVerbosity LoggerVerbosity {
374 get { return loggerVerbosity; }
377 public string ConsoleLoggerParameters {
378 get { return consoleLoggerParameters; }
381 public bool NoConsoleLogger {
382 get { return noConsoleLogger; }
385 public bool Validate {
386 get { return validate; }
389 public string ValidationSchema {
390 get { return validationSchema; }
393 public string ToolsVersion {
394 get { return toolsVersion; }
395 private set { toolsVersion = value; }
401 #endif