[xbuild] Add support for wildcards in Import.
authorAnkit Jain <radical@corewars.org>
Thu, 3 Mar 2011 15:59:40 +0000 (21:29 +0530)
committerAnkit Jain <radical@corewars.org>
Thu, 3 Mar 2011 19:20:30 +0000 (00:50 +0530)
With 4.0 profile, <Import ..> can have wildcards. This works correctly
with our multiple MSBuildExtensionsPath also.

If the import references $(MSBuildExtensionsPath) property, then the
each extension path is used to resolve the import, and the search
stop as soon as an import is found.

If such an import uses wildcard, then the search stops at the
extension path in which *atleast one* file got imported.
And the import fails if any invalid project file is encountered.

This commit also heavily refactors the Import code to simplify
in the face of the new features, and improves error detection
and reporting.

ImportTest.cs: Add test for wildcards.

mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/Import.cs
mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/Project.cs
mcs/class/Microsoft.Build.Engine/Test/Microsoft.Build.BuildEngine/ImportTest.cs

index 951f4f46fd4337a72e955a824116781cec190a8f..f9c0e52bbc1439d29e50e28237bcb40d84a52c76 100644 (file)
@@ -3,8 +3,10 @@
 //
 // Author:
 //   Marek Sieradzki (marek.sieradzki@gmail.com)
+//   Ankit Jain (jankit@novell.com)
 // 
 // (C) 2006 Marek Sieradzki
+// Copyright 2011 Novell, Inc (http://www.novell.com)
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
 #if NET_2_0
 
 using System;
+using System.Collections.Generic;
 using System.IO;
+using System.Linq;
 using System.Xml;
 
 using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
 using Mono.XBuild.Utilities;
 
 namespace Microsoft.Build.BuildEngine {
@@ -47,6 +52,11 @@ namespace Microsoft.Build.BuildEngine {
                static string PathSeparatorAsString = Path.PathSeparator.ToString ();
        
                internal Import (XmlElement importElement, Project project, ImportedProject originalProject)
+                       : this (importElement, null, project, originalProject)
+               {}
+
+               // if @alternateProjectPath is available then that it used as the EvaluatedProjectPath!
+               internal Import (XmlElement importElement, string alternateProjectPath, Project project, ImportedProject originalProject)
                {
                        if (importElement == null)
                                throw new ArgumentNullException ("importElement");
@@ -61,7 +71,8 @@ namespace Microsoft.Build.BuildEngine {
                                throw new InvalidProjectFileException ("The required attribute \"Project\" is missing from element <Import>.");
 
                        if (ConditionParser.ParseAndEvaluate (Condition, project)) {
-                               evaluatedProjectPath = EvaluateProjectPath (ProjectPath);
+                               evaluatedProjectPath = String.IsNullOrEmpty (alternateProjectPath) ? EvaluateProjectPath (ProjectPath) : alternateProjectPath;
+
                                evaluatedProjectPath = GetFullPath ();
                                if (EvaluatedProjectPath == String.Empty)
                                        throw new InvalidProjectFileException ("The required attribute \"Project\" is missing from element <Import>.");
@@ -73,9 +84,9 @@ namespace Microsoft.Build.BuildEngine {
                {
                        string filename = evaluatedProjectPath;
                        // NOTE: it's a hack to transform Microsoft.CSharp.Targets to Microsoft.CSharp.targets
-                       if (Path.HasExtension (filename))
-                               filename = Path.ChangeExtension (filename, Path.GetExtension (filename));
-                       
+                       if (!File.Exists (filename) && Path.GetFileName (filename) == "Microsoft.CSharp.Targets")
+                               filename = Path.ChangeExtension (filename, ".targets");
+
                        if (!File.Exists (filename)) {
                                if (ignoreMissingImports) {
                                        project.LogWarning (project.FullFileName, "Could not find project file {0}, to import. Ignoring.", filename);
@@ -93,91 +104,152 @@ namespace Microsoft.Build.BuildEngine {
 
                string EvaluateProjectPath (string file)
                {
-                       string ret;
-                       if (EvaluateAsMSBuildExtensionsPath (file, "MSBuildExtensionsPath", out ret) ||
-                               EvaluateAsMSBuildExtensionsPath (file, "MSBuildExtensionsPath32", out ret) ||
-                               EvaluateAsMSBuildExtensionsPath (file, "MSBuildExtensionsPath64", out ret))
-                               return ret;
+                       return Expression.ParseAs<string> (file, ParseOptions.Split, project);
+               }
+
+               string GetFullPath ()
+               {
+                       string file = EvaluatedProjectPath;
+                       if (!Path.IsPathRooted (file) && !String.IsNullOrEmpty (ContainedInProjectFileName))
+                               file = Path.Combine (Path.GetDirectoryName (ContainedInProjectFileName), file);
+
+                       return MSBuildUtils.FromMSBuildPath (file);
+               }
+
+               // For every extension path, in order, finds suitable
+               // import filename(s) matching the Import, and calls
+               // @func with them
+               //
+               // func: bool func(importPath, from_source_msg)
+               //
+               // If for an extension path, atleast one file gets imported,
+               // then it stops at that.
+               // So, in case imports like "$(MSBuildExtensionsPath)\foo\*",
+               // for every extension path, it will try to import the "foo\*",
+               // and if atleast one file gets successfully imported, then it
+               // stops at that
+               internal static void ForEachExtensionPathTillFound (XmlElement xmlElement, Project project, ImportedProject importingProject,
+                               Func<string, string, bool> func)
+               {
+                       string project_attribute = xmlElement.GetAttribute ("Project");
+                       string condition_attribute = xmlElement.GetAttribute ("Condition");
+
+                       bool has_extn_ref = project_attribute.IndexOf ("$(MSBuildExtensionsPath)") >= 0 ||
+                                               project_attribute.IndexOf ("$(MSBuildExtensionsPath32)") >= 0 ||
+                                               project_attribute.IndexOf ("$(MSBuildExtensionsPath64)") >= 0;
+
+                       string importingFile = importingProject != null ? importingProject.FullFileName : project.FullFileName;
+                       DirectoryInfo base_dir_info = null;
+                       if (!String.IsNullOrEmpty (importingFile))
+                               base_dir_info = new DirectoryInfo (Path.GetDirectoryName (importingFile));
+                       else
+                               base_dir_info = new DirectoryInfo (Directory.GetCurrentDirectory ());
+
+                       IEnumerable<string> extn_paths = has_extn_ref ? GetExtensionPaths (project) : new string [] {null};
+                       try {
+                               foreach (string path in extn_paths) {
+                                       string extn_msg = null;
+                                       if (has_extn_ref) {
+                                               project.SetExtensionsPathProperties (path);
+                                               extn_msg = "from extension path " + path;
+                                       }
+
+                                       // do this after setting new Extension properties, as condition might
+                                       // reference it
+                                       if (!ConditionParser.ParseAndEvaluate (condition_attribute, project)) {
+                                               project.ParentEngine.LogMessage (MessageImportance.Low,
+                                                               "{0}: Not importing '{1}' project as the condition '{2}' is false",
+                                                               importingFile, project_attribute, condition_attribute);
+                                               continue;
+                                       }
 
-                       return EvaluatePath (file);
+                                       // We stop if atleast one file got imported.
+                                       // Remaining extension paths are *not* tried
+                                       bool atleast_one = false;
+                                       foreach (string importPath in GetImportPathsFromString (project_attribute, project, base_dir_info)) {
+                                               try {
+                                                       if (func (importPath, extn_msg))
+                                                               atleast_one = true;
+                                               } catch (Exception e) {
+                                                       throw new InvalidProjectFileException (String.Format (
+                                                                               "{0}: Project file could not be imported, it was being imported by " +
+                                                                               "{1}: {2}", importPath, importingFile, e.Message), e);
+                                               }
+                                       }
+
+                                       if (atleast_one)
+                                               return;
+                               }
+                       } finally {
+                               if (has_extn_ref)
+                                       project.SetExtensionsPathProperties (Project.DefaultExtensionsPath);
+                       }
                }
 
-               bool EvaluateAsMSBuildExtensionsPath (string file, string property_name, out string epath)
+               // Parses the Project attribute from an Import,
+               // and returns the import filenames that match.
+               // This handles wildcards also
+               static IEnumerable<string> GetImportPathsFromString (string import_string, Project project, DirectoryInfo base_dir_info)
                {
-                       epath = null;
-                       string property_ref = String.Format ("$({0})", property_name);
-                       if (file.IndexOf (property_ref) < 0)
-                               return false;
+                       string parsed_import = Expression.ParseAs<string> (import_string, ParseOptions.AllowItemsNoMetadataAndSplit, project);
+                       if (parsed_import != null)
+                               parsed_import = parsed_import.Trim ();
+
+                       if (String.IsNullOrEmpty (parsed_import))
+                               throw new InvalidProjectFileException ("The required attribute \"Project\" in Import is empty");
+
+#if NET_4_0
+                       if (DirectoryScanner.HasWildcard (parsed_import)) {
+                               var directoryScanner = new DirectoryScanner () {
+                                       Includes = new ITaskItem [] { new TaskItem (parsed_import) },
+                                       BaseDirectory = base_dir_info
+                               };
+                               directoryScanner.Scan ();
+
+                               foreach (ITaskItem matchedItem in directoryScanner.MatchedItems)
+                                       yield return matchedItem.ItemSpec;
+                       } else
+#endif
+                               yield return parsed_import;
+               }
 
+               // Gives a list of extensions paths to try for $(MSBuildExtensionsPath),
+               // *in-order*
+               static IEnumerable<string> GetExtensionPaths (Project project)
+               {
                        // This is a *HACK* to support multiple paths for
                        // MSBuildExtensionsPath property. Normally it would
                        // get resolved to a single value, but here we special
-                       // case it and try ~/.config/xbuild/tasks and any
-                       // paths specified in the env var $MSBuildExtensionsPath .
+                       // case it and try various paths, see the code below
                        //
                        // The property itself will resolve to the default
-                       // location though, so you get in any other part of the
+                       // location though, so you get that in any other part of the
                        // project.
 
-                       string envvar = Environment.GetEnvironmentVariable (property_name);
+                       string envvar = Environment.GetEnvironmentVariable ("MSBuildExtensionsPath");
                        envvar = String.Join (PathSeparatorAsString, new string [] {
                                                (envvar ?? String.Empty),
                                                // For mac osx, look in the 'External' dir on macosx,
                                                // see bug #663180
                                                MSBuildUtils.RunningOnMac ? MacOSXExternalXBuildDir : String.Empty,
-                                               DotConfigExtensionsPath});
+                                               DotConfigExtensionsPath,
+                                               Project.DefaultExtensionsPath});
 
-                       string [] paths = envvar.Split (new char [] {Path.PathSeparator}, StringSplitOptions.RemoveEmptyEntries);
-                       foreach (string path in paths) {
-                               if (!Directory.Exists (path)) {
-                                       project.ParentEngine.LogMessage (MessageImportance.Low, "Extension path '{0}' not found, ignoring.", path);
+                       var pathsTable = new Dictionary<string, string> ();
+                       foreach (string extn_path in envvar.Split (new char [] {Path.PathSeparator}, StringSplitOptions.RemoveEmptyEntries)) {
+                               if (pathsTable.ContainsKey (extn_path))
                                        continue;
-                               }
-
-                               string pfile = Path.GetFullPath (file.Replace ("\\", "/").Replace (
-                                                       property_ref, path + Path.DirectorySeparatorChar));
 
-                               var evaluated_path = EvaluatePath (pfile);
-                               if (File.Exists (evaluated_path)) {
-                                       project.ParentEngine.LogMessage (MessageImportance.Low,
-                                               "{0}: Importing project {1} from extension path {2}", project.FullFileName, evaluated_path, path);
-                                       epath = pfile;
-                                       return true;
+                               if (!Directory.Exists (extn_path)) {
+                                       project.ParentEngine.LogMessage (MessageImportance.Low, "Extension path '{0}' not found, ignoring.", extn_path);
+                                       continue;
                                }
-                               project.ParentEngine.LogMessage (MessageImportance.Low,
-                                               "{0}: Couldn't find project {1} for extension path {2}", project.FullFileName, evaluated_path, path);
-                       }
-
-                       return false;
-               }
-
-               string EvaluatePath (string path)
-               {
-                       var exp = new Expression ();
-                       exp.Parse (path, ParseOptions.Split);
-                       return (string) exp.ConvertTo (project, typeof (string));
-               }
 
-               string GetFullPath ()
-               {
-                       string file = EvaluatedProjectPath;
-
-                       if (!Path.IsPathRooted (EvaluatedProjectPath)) {
-                               string dir = null;
-                               if (originalProject == null) {
-                                       if (project.FullFileName != String.Empty) // Path.GetDirectoryName throws exception on String.Empty
-                                               dir = Path.GetDirectoryName (project.FullFileName);
-                               } else {
-                                       if (originalProject.FullFileName != String.Empty)
-                                               dir = Path.GetDirectoryName (originalProject.FullFileName);
-                               }
-                               if (dir != null)
-                                       file = Path.Combine (dir, EvaluatedProjectPath);
+                               pathsTable [extn_path] = extn_path;
+                               yield return extn_path;
                        }
-                       
-                       return MSBuildUtils.FromMSBuildPath (file);
                }
-               
+
                public string Condition {
                        get {
                                string s = importElement.GetAttribute ("Condition");
@@ -196,6 +268,10 @@ namespace Microsoft.Build.BuildEngine {
                public string ProjectPath {
                        get { return importElement.GetAttribute ("Project"); }
                }
+
+               internal string ContainedInProjectFileName {
+                       get { return originalProject != null ? originalProject.FullFileName : project.FullFileName; }
+               }
        }
 }
 
index 533f7b4f3a550131495daf81580eab3b93442844..9750d831e7a267ca7892b1b80d1f317f274cf2d1 100644 (file)
@@ -3,8 +3,10 @@
 //
 // Author:
 //   Marek Sieradzki (marek.sieradzki@gmail.com)
+//   Ankit Jain (jankit@novell.com)
 //
 // (C) 2005 Marek Sieradzki
+// Copyright 2011 Novell, Inc (http://www.novell.com)
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -142,8 +144,7 @@ namespace Microsoft.Build.BuildEngine {
                        if (!String.IsNullOrEmpty (importCondition))
                                importElement.SetAttribute ("Condition", importCondition);
 
-                       Import import = new Import (importElement, this, null);
-                       imports.Add (import);
+                       AddImport (importElement, null, false);
                        MarkProjectAsDirty ();
                        NeedToReevaluate ();
                }
@@ -275,7 +276,7 @@ namespace Microsoft.Build.BuildEngine {
                {
                        return Build (targetNames, targetOutputs, BuildSettings.None);
                }
-               
+
                [MonoTODO ("Not tested")]
                public bool Build (string [] targetNames,
                                   IDictionary targetOutputs,
@@ -517,6 +518,7 @@ namespace Microsoft.Build.BuildEngine {
                        string filename = fullFileName;
                        if (String.Compare (Path.GetExtension (fullFileName), ".sln", true) == 0) {
                                Project tmp_project = ParentEngine.CreateNewProject ();
+                               tmp_project.FullFileName = filename;
                                SolutionParser sln_parser = new SolutionParser ();
                                sln_parser.ParseSolution (fullFileName, tmp_project, delegate (int errorNumber, string message) {
                                                LogWarning (filename, message);
@@ -922,7 +924,7 @@ namespace Microsoft.Build.BuildEngine {
                                                AddUsingTask (xe, ip);
                                                break;
                                        case "Import":
-                                               AddImport (xe, ip);
+                                               AddImport (xe, ip, true);
                                                break;
                                        case "ItemGroup":
                                                AddItemGroup (xe, ip);
@@ -1013,9 +1015,7 @@ namespace Microsoft.Build.BuildEngine {
                        evaluatedProperties.AddProperty (new BuildProperty ("MSBuildToolsPath", toolsPath, PropertyType.Reserved));
                        evaluatedProperties.AddProperty (new BuildProperty ("MSBuildToolsRoot", Path.GetDirectoryName (toolsPath), PropertyType.Reserved));
                        evaluatedProperties.AddProperty (new BuildProperty ("MSBuildToolsVersion", effective_tools_version, PropertyType.Reserved));
-                       evaluatedProperties.AddProperty (new BuildProperty ("MSBuildExtensionsPath", ExtensionsPath, PropertyType.Reserved));
-                       evaluatedProperties.AddProperty (new BuildProperty ("MSBuildExtensionsPath32", ExtensionsPath, PropertyType.Reserved));
-                       evaluatedProperties.AddProperty (new BuildProperty ("MSBuildExtensionsPath64", ExtensionsPath, PropertyType.Reserved));
+                       SetExtensionsPathProperties (DefaultExtensionsPath);
                        evaluatedProperties.AddProperty (new BuildProperty ("MSBuildProjectDefaultTargets", DefaultTargets, PropertyType.Reserved));
                        evaluatedProperties.AddProperty (new BuildProperty ("OS", OS, PropertyType.Environment));
 
@@ -1034,6 +1034,15 @@ namespace Microsoft.Build.BuildEngine {
                                SetMSBuildThisFileProperties (this_file_property_stack.Peek ());
                }
 
+               internal void SetExtensionsPathProperties (string extn_path)
+               {
+                       if (!String.IsNullOrEmpty (extn_path)) {
+                               evaluatedProperties.AddProperty (new BuildProperty ("MSBuildExtensionsPath", extn_path, PropertyType.Reserved));
+                               evaluatedProperties.AddProperty (new BuildProperty ("MSBuildExtensionsPath32", extn_path, PropertyType.Reserved));
+                               evaluatedProperties.AddProperty (new BuildProperty ("MSBuildExtensionsPath64", extn_path, PropertyType.Reserved));
+                       }
+               }
+
                // precedence:
                // ToolsVersion property
                // ToolsVersion attribute on the project
@@ -1080,23 +1089,46 @@ namespace Microsoft.Build.BuildEngine {
                        usingTask = new UsingTask (xmlElement, this, importedProject);
                        UsingTasks.Add (usingTask);
                }
-               
-               void AddImport (XmlElement xmlElement, ImportedProject importingProject)
+
+               void AddImport (XmlElement xmlElement, ImportedProject importingProject, bool evaluate_properties)
                {
                        // eval all the properties etc till the import
-                       groupingCollection.Evaluate (EvaluationType.Property);
+                       if (evaluate_properties)
+                               groupingCollection.Evaluate (EvaluationType.Property);
 
-                       Import import = new Import (xmlElement, this, importingProject);
-                       if (!ConditionParser.ParseAndEvaluate (import.Condition, this))
-                               return;
+                       string project_attribute = xmlElement.GetAttribute ("Project");
+                       if (String.IsNullOrEmpty (project_attribute))
+                               throw new InvalidProjectFileException ("The required attribute \"Project\" is missing from element <Import>.");
 
-                       if (Imports.Contains (import)) {
-                               LogWarning (importingProject != null ? importingProject.FullFileName : fullFileName,
-                                               "A circular reference was found involving the import of {0}. Only" +
-                                               " the first import of this file will be used, ignoring others.",
-                                               import.ProjectPath);
+                       Import.ForEachExtensionPathTillFound (xmlElement, this, importingProject,
+                               (importPath, from_source_msg) => AddSingleImport (xmlElement, importPath, importingProject, from_source_msg));
+               }
 
-                               return;
+               bool AddSingleImport (XmlElement xmlElement, string projectPath, ImportedProject importingProject, string from_source_msg)
+               {
+                       Import import = new Import (xmlElement, projectPath, this, importingProject);
+                       if (!ConditionParser.ParseAndEvaluate (import.Condition, this)) {
+                               ParentEngine.LogMessage (MessageImportance.Low,
+                                               "Not importing project '{0}' as the condition '{1}' is false",
+                                               import.ProjectPath, import.Condition);
+                               return false;
+                       }
+
+                       Import existingImport;
+                       if (Imports.TryGetImport (import, out existingImport)) {
+                               if (importingProject == null)
+                                       LogWarning (fullFileName,
+                                                       "Cannot import project '{0}' again. It was already imported by " +
+                                                       "'{1}'. Ignoring.",
+                                                       projectPath, existingImport.ContainedInProjectFileName);
+                               else
+                                       LogWarning (importingProject != null ? importingProject.FullFileName : fullFileName,
+                                               "A circular reference was found involving the import of '{0}'. " +
+                                               "It was earlier imported by '{1}'. Only " +
+                                               "the first import of this file will be used, ignoring others.",
+                                               import.EvaluatedProjectPath, existingImport.ContainedInProjectFileName);
+
+                               return false;
                        }
 
                        if (String.Compare (fullFileName, import.EvaluatedProjectPath) == 0) {
@@ -1104,13 +1136,19 @@ namespace Microsoft.Build.BuildEngine {
                                                "The main project file was imported here, which creates a circular " +
                                                "reference. Ignoring this import.");
 
-                               return;
+                               return false;
                        }
 
                        Imports.Add (import);
+                       string importingFile = importingProject != null ? importingProject.FullFileName : FullFileName;
+                       ParentEngine.LogMessage (MessageImportance.Low,
+                                       "{0}: Importing project {1} {2}",
+                                       importingFile, import.EvaluatedProjectPath, from_source_msg);
+
                        import.Evaluate (project_load_settings == ProjectLoadSettings.IgnoreMissingImports);
+                       return true;
                }
-               
+
                void AddItemGroup (XmlElement xmlElement, ImportedProject importedProject)
                {
                        BuildItemGroup big = new BuildItemGroup (xmlElement, this, importedProject, false);
@@ -1370,7 +1408,7 @@ namespace Microsoft.Build.BuildEngine {
                        ParentEngine.EventSource.FireErrorRaised (this, beea);
                }
 
-               static string ExtensionsPath {
+               internal static string DefaultExtensionsPath {
                        get {
                                if (extensions_path == null) {
                                        // NOTE: code from mcs/tools/gacutil/driver.cs
index c353b0400923ffdae98e5c5fc48bee2600d9d484..076db84e6c5f8c915d94ad9b5ebe7c976e86bd26 100644 (file)
@@ -209,5 +209,62 @@ namespace MonoTests.Microsoft.Build.BuildEngine {
                        project.LoadXml (documentString);
                }
 
+#if NET_4_0
+               [Test]
+               public void TestImportWildcard ()
+               {
+                       string main_project_xml = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"" ToolsVersion=""4.0"">
+                               <ItemGroup>
+                                       <FooItem Include=""From main.proj""/>
+                               </ItemGroup>
+
+                               <Import Project=""tmp\*""/>
+
+                               <Target Name=""Build"">
+                                       <Message Text=""FooItem: @(FooItem)""/>
+                               </Target>
+                       </Project>";
+
+                       string other_project_xml = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"" ToolsVersion=""4.0"">
+                               <ItemGroup>
+                                       <FooItem Include=""From $(MSBuildThisFile)""/>
+                               </ItemGroup>
+                       </Project>";
+
+                       Engine engine = new Engine (Consts.BinPath);
+                       MonoTests.Microsoft.Build.Tasks.TestMessageLogger logger =
+                               new MonoTests.Microsoft.Build.Tasks.TestMessageLogger ();
+                       engine.RegisterLogger (logger);
+
+                       string base_dir = Path.GetFullPath (Path.Combine ("Test", "resources")) + Path.DirectorySeparatorChar;
+                       string tmp_dir = Path.GetFullPath (Path.Combine (base_dir, "tmp")) + Path.DirectorySeparatorChar;
+
+                       string main_project = Path.Combine (base_dir, "main.proj");
+                       string first_project = Path.Combine (tmp_dir, "first.proj");
+                       string second_project = Path.Combine (tmp_dir, "second.proj");
+
+                       Directory.CreateDirectory (tmp_dir);
+                       File.WriteAllText (main_project, main_project_xml);
+                       File.WriteAllText (first_project, other_project_xml);
+                       File.WriteAllText (second_project, other_project_xml);
+
+                       Project project = engine.CreateNewProject ();
+                       project.Load (main_project);
+                       try {
+                               Assert.IsTrue (project.Build ("Build"), "Build failed");
+
+                               logger.CheckLoggedMessageHead ("FooItem: From main.proj;From first.proj;From second.proj", "A1");
+                               Assert.AreEqual (0, logger.NormalMessageCount, "Unexpected extra messages found");
+                       } catch {
+                               logger.DumpMessages ();
+                               throw;
+                       } finally {
+                               File.Delete (main_project);
+                               File.Delete (first_project);
+                               File.Delete (second_project);
+                       }
+               }
+#endif
+
        }
 }