Fix tarball package build broken by 8f130a6e17c3729f32c3bf930941ab6587f6fe38
[mono.git] / mcs / tools / xbuild / Parameters.cs
index 86b5ba77e2a63befffb60148740c6af925190a34..8ecaeccd42a9447c54ad5b6cbf336dc0e8a74da3 100644 (file)
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
-#if NET_2_0
 
 using System;
 using System.IO;
 using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
 using System.Text;
+using System.Reflection;
 using Microsoft.Build.BuildEngine;
 using Microsoft.Build.Framework;
 using Microsoft.Build.Utilities;
@@ -40,7 +42,6 @@ namespace Mono.XBuild.CommandLine {
        
                string                  consoleLoggerParameters;
                bool                    displayHelp;
-               bool                    displayVersion;
                IList                   flatArguments;
                IList                   loggers;
                LoggerVerbosity         loggerVerbosity;
@@ -53,14 +54,14 @@ namespace Mono.XBuild.CommandLine {
                string[]                targets;
                bool                    validate;
                string                  validationSchema;
+               string                  toolsVersion;
                
                string                  responseFile;
        
-               public Parameters (string binPath)
+               public Parameters ()
                {
                        consoleLoggerParameters = "";
                        displayHelp = false;
-                       displayVersion = true;
                        loggers = new ArrayList ();
                        loggerVerbosity = LoggerVerbosity.Normal;
                        noConsoleLogger = false;
@@ -68,7 +69,9 @@ namespace Mono.XBuild.CommandLine {
                        properties = new BuildPropertyGroup ();
                        targets = new string [0];
                        
-                       responseFile = Path.Combine (binPath, "xbuild.rsp");
+                       responseFile = Path.Combine (
+                                       Path.GetDirectoryName (Assembly.GetExecutingAssembly ().Location),
+                                       "xbuild.rsp");
                }
                
                public void ParseArguments (string[] args)
@@ -77,6 +80,7 @@ namespace Mono.XBuild.CommandLine {
                        flatArguments = new ArrayList ();
                        remainingArguments = new ArrayList ();
                        responseFiles = new Hashtable ();
+                       FileLoggerParameters = new string[10];
                        foreach (string s in args) {
                                if (s.StartsWith ("/noautoresponse") || s.StartsWith ("/noautorsp")) {
                                        autoResponse = false;
@@ -86,9 +90,9 @@ namespace Mono.XBuild.CommandLine {
                                        flatArguments.Add (s);
                                        continue;
                                }
-                               string responseFilename = Path.GetFullPath (s.Substring (1));
+                               string responseFilename = Path.GetFullPath (UnquoteIfNeeded (s.Substring (1)));
                                if (responseFiles.ContainsKey (responseFilename))
-                                       ErrorUtilities.ReportError (1, String.Format ("We already have {0} file.", responseFilename));
+                                       ReportError (1, String.Format ("We already have {0} file.", responseFilename));
                                responseFiles [responseFilename] = responseFilename;
                                LoadResponseFile (responseFilename);
                        }
@@ -97,24 +101,53 @@ namespace Mono.XBuild.CommandLine {
                                LoadResponseFile (responseFile);
                        }
                        foreach (string s in flatArguments) {
-                               if (s [0] == '/') {
-                                       ParseFlatArgument (s);
-                               } else
+                               if (s [0] != '/' || !ParseFlatArgument (s))
                                        remainingArguments.Add (s);
                        }
                        if (remainingArguments.Count == 0) {
-                               string[] files = Directory.GetFiles (Directory.GetCurrentDirectory (), "*.??proj");
-                               if (files.Length > 0)
-                                       projectFile = files [0];
+                               string[] sln_files = Directory.GetFiles (Directory.GetCurrentDirectory (), "*.sln");
+                               string[] proj_files = Directory.GetFiles (Directory.GetCurrentDirectory (), "*proj");
+
+                               if (sln_files.Length == 0 && proj_files.Length == 0)
+                                       ReportError (3, "Please specify the project or solution file " +
+                                                       "to build, as none was found in the current directory.");
+
+                               if (sln_files.Length == 1 && proj_files.Length > 0) {
+                                       var projects_table = new Dictionary<string, string> ();
+                                       foreach (string pfile in SolutionParser.GetAllProjectFileNames (sln_files [0])) {
+                                               string full_path = Path.GetFullPath (pfile);
+                                               projects_table [full_path] = full_path;
+                                       }
+
+                                       if (!proj_files.Any (p => !projects_table.ContainsKey (Path.GetFullPath (p))))
+                                               // if all the project files in the cur dir, are referenced
+                                               // from the single .sln in the cur dir, then pick the sln
+                                               proj_files = new string [0];
+                               }
+
+                               if (sln_files.Length + proj_files.Length > 1)
+                                       ReportError (5, "Please specify the project or solution file " +
+                                                       "to build, as more than one solution or project file was found " +
+                                                       "in the current directory");
+
+                               if (sln_files.Length == 1)
+                                       projectFile = sln_files [0];
                                else
-                                       ErrorUtilities.ReportError (3, "No .proj file specified and no found in current directory.");
+                                       projectFile = proj_files [0];
                        } else if (remainingArguments.Count == 1) {
                                projectFile = (string) remainingArguments [0];
                        } else {
-                               ErrorUtilities.ReportError (4, "Too many project files specified");
+                               ReportError (4, "Too many project files specified");
                        }
                }
-               
+
+               private string UnquoteIfNeeded(string arg)
+               {
+                       if (arg.StartsWith("\""))
+                               return arg.Substring(1, arg.Length - 2);
+                       return arg;
+               }
+
                void LoadResponseFile (string filename)
                {
                        StreamReader sr = null;
@@ -156,16 +189,17 @@ namespace Mono.XBuild.CommandLine {
                                                 sb.Length = 0;
                                         }
                                 }
-                        } catch (Exception) {
-                               // FIXME: we lose exception message
-                               ErrorUtilities.ReportError (2, "Error during loading response file.");
+                        } catch (IOException x) {
+                               ErrorUtilities.ReportWarning (2, String.Format (
+                                                       "Error loading response file. (Exception: {0}). Ignoring.",
+                                                       x.Message));
                        } finally {
                                 if (sr != null)
                                         sr.Close ();
                         }
                }
                
-               private void ParseFlatArgument (string s)
+               private bool ParseFlatArgument (string s)
                {
                        switch (s) {
                        case "/help":
@@ -188,46 +222,91 @@ namespace Mono.XBuild.CommandLine {
                        case "/val":
                                validate = true;
                                break;
+                       case "/fl":
+                       case "/filelogger":
+                               if (FileLoggerParameters [0] == null)
+                                       FileLoggerParameters [0] = String.Empty;
+                               break;
                        default:
-                               if (s.StartsWith ("/target:") || s.StartsWith ("/t:")) {
+                               if (s.StartsWith ("/fl") && s.Length == 4 && Char.IsDigit (s[3])) {
+                                       int index = Int32.Parse (s[3].ToString ());
+                                       if (FileLoggerParameters [index] == null)
+                                               FileLoggerParameters [index] = String.Empty;
+                               } else if (s.StartsWith ("/fileloggerparameters") || s.StartsWith ("/flp")) {
+                                       ProcessFileLoggerParameters (s);
+                               } else if (s.StartsWith ("/target:") || s.StartsWith ("/t:")) {
                                        ProcessTarget (s);
-                               }
-                               if (s.StartsWith ("/property:") || s.StartsWith ("/p:")) {
-                                       ProcessProperty (s);
-                               }
-                               if (s.StartsWith ("/logger:") || s.StartsWith ("/l:")) {
+                               } else if (s.StartsWith ("/property:") || s.StartsWith ("/p:")) {
+                                       if (!ProcessProperty (s))
+                                               return false;
+                               } else  if (s.StartsWith ("/logger:") || s.StartsWith ("/l:")) {
                                        ProcessLogger (s);
-                               }
-                               if (s.StartsWith ("/verbosity:") || s.StartsWith ("/v:")) {
+                               } else if (s.StartsWith ("/verbosity:") || s.StartsWith ("/v:")) {
                                        ProcessVerbosity (s);
-                               }
-                               if (s.StartsWith ("/consoleloggerparameters:") || s.StartsWith ("/clp:")) {
+                               } else if (s.StartsWith ("/consoleloggerparameters:") || s.StartsWith ("/clp:")) {
                                        ProcessConsoleLoggerParameters (s);
-                               }
-                               if (s.StartsWith ("/validate:") || s.StartsWith ("/val:")) {
+                               } else if (s.StartsWith ("/validate:") || s.StartsWith ("/val:")) {
                                        ProcessValidate (s);
-                               }
+                               } else if (s.StartsWith ("/toolsversion:") || s.StartsWith ("/tv:")) {
+                                       ToolsVersion = s.Split (':') [1];
+                               } else
+                                       return false;
                                break;
                        }
+
+                       return true;
                }
                
                internal void ProcessTarget (string s)
                {
-                       string[] temp = s.Split (':');
-                       targets = temp [1].Split (';');
+                       TryProcessMultiOption (s, "Target names must be specified as /t:Target1;Target2",
+                                               out targets);
                }
                
-               internal void ProcessProperty (string s)
+               internal bool ProcessProperty (string s)
                {
-                       string[] parameter, splittedProperties, property;
-                       parameter = s.Split (':');
-                       splittedProperties = parameter [1].Split (';');
-                       foreach (string st in splittedProperties) {
-                               property = st.Split ('=');
-                               properties.SetProperty (property [0], property [1]);
+                       string[] splitProperties;
+                       if (!TryProcessMultiOption (s, "Property name and value expected as /p:<prop name>=<prop value>",
+                                               out splitProperties))
+                               return false;
+
+                       foreach (string st in splitProperties) {
+                               if (st.IndexOf ('=') < 0) {
+                                       ReportError (5,
+                                                       "Invalid syntax. Property name and value expected as " +
+                                                       "<prop name>=[<prop value>]");
+                                       return false;
+                               }
+                               string [] property = st.Split ('=');
+                               properties.SetProperty (property [0], property.Length == 2 ? property [1] : "");
                        }
+
+                       return true;
                }
-               
+
+               bool TryProcessMultiOption (string s, string error_message, out string[] values)
+               {
+                       values = null;
+                       int colon = s.IndexOf (':');
+                       if (colon + 1 == s.Length) {
+                               ReportError (5, error_message);
+                               return false;
+                       }
+
+                       values = s.Substring (colon + 1).Split (';');
+                       return true;
+               }
+
+               private void ReportError (int errorCode, string message)
+               {
+                       throw new CommandLineException (message, errorCode);
+               }
+
+               private void ReportError (int errorCode, string message, Exception cause)
+               {
+                       throw new CommandLineException (message, cause, errorCode);
+               }
+
                internal void ProcessLogger (string s)
                {
                        loggers.Add (new LoggerInfo (s));
@@ -259,10 +338,29 @@ namespace Mono.XBuild.CommandLine {
                                break;
                        }
                }
-               
+
+               void ProcessFileLoggerParameters (string s)
+               {
+                       int colon = s.IndexOf (':');
+                       if (colon + 1 == s.Length)
+                               ReportError (5, "Invalid syntax, specify parameters as /fileloggerparameters[n]:parameters");
+
+                       int index = 0;
+                       string key = s.Substring (0, colon);
+                       if (Char.IsDigit (key [key.Length - 1]))
+                       //if (key.Length == 22 && Char.IsDigit (key [21]))
+                               index = Int32.Parse (key [key.Length - 1].ToString ());
+
+                       FileLoggerParameters [index] = s.Substring (colon + 1);
+               }
+
                internal void ProcessConsoleLoggerParameters (string s)
                {
-                       consoleLoggerParameters = s; 
+                       int colon = s.IndexOf (':');
+                       if (colon + 1 == s.Length)
+                               ReportError (5, "Invalid syntax, specify parameters as /clp:parameters");
+
+                       consoleLoggerParameters = s.Substring (colon + 1);
                }
                
                internal void ProcessValidate (string s)
@@ -280,10 +378,6 @@ namespace Mono.XBuild.CommandLine {
                        get { return noLogo; }
                }
                
-               public bool DisplayVersion {
-                       get { return displayVersion; }
-               }
-               
                public string ProjectFile {
                        get { return projectFile; }
                }
@@ -311,6 +405,8 @@ namespace Mono.XBuild.CommandLine {
                public bool NoConsoleLogger {
                        get { return noConsoleLogger; }
                }
+
+               public string[] FileLoggerParameters { get; set; }
                
                public bool Validate {
                        get { return validate; }
@@ -319,8 +415,12 @@ namespace Mono.XBuild.CommandLine {
                public string ValidationSchema {
                        get { return validationSchema; }
                }
+
+               public string ToolsVersion {
+                       get { return toolsVersion; }
+                       private set { toolsVersion = value; }
+               }
                
        }
 }
 
-#endif