[xbuild] Add support for Before/AfterTargets.
[mono.git] / mcs / class / Microsoft.Build.Engine / Microsoft.Build.BuildEngine / Target.cs
index 439c56fd94b14b4887d57ace200ec0d5f5e82e71..b201619615d2ebcebd6114e768b7f41dfba44950 100644 (file)
@@ -157,14 +157,15 @@ namespace Microsoft.Build.BuildEngine {
 
                        try {
                                buildState = BuildState.Started;
-                               result = BuildDependencies (GetDependencies (), out executeOnErrors);
 
-                               if (!result && executeOnErrors)
-                                       ExecuteOnErrors ();
-
-                               if (result)
-                                       // deps built fine, do main build
-                                       result = DoBuild (out executeOnErrors);
+#if NET_4_0
+                               result = BuildDependencies (out executeOnErrors) &&
+                                               BuildBeforeThisTargets (out executeOnErrors) &&
+                                               DoBuild (out executeOnErrors) && // deps & Before targets built fine, do main build
+                                               BuildAfterThisTargets (out executeOnErrors);
+#else
+                               result = BuildDependencies (out executeOnErrors) && DoBuild (out executeOnErrors);
+#endif
 
                                buildState = BuildState.Finished;
                        } catch (Exception e) {
@@ -179,36 +180,70 @@ namespace Microsoft.Build.BuildEngine {
                        return result;
                }
 
-               List <Target> GetDependencies ()
+               bool BuildDependencies (out bool executeOnErrors)
                {
-                       List <Target> list = new List <Target> ();
-                       Target t;
-                       string [] targetNames;
-                       Expression deps;
-
-                       if (DependsOnTargets != String.Empty) {
-                               deps = new Expression ();
-                               deps.Parse (DependsOnTargets, ParseOptions.AllowItemsNoMetadataAndSplit);
-                               targetNames = (string []) deps.ConvertTo (Project, typeof (string []));
-                               foreach (string dep_name in targetNames) {
-                                       t = project.Targets [dep_name.Trim ()];
-                                       if (t == null)
-                                               throw new InvalidProjectFileException (String.Format (
-                                                               "Target '{0}', a dependency of target '{1}', not found.",
-                                                               dep_name.Trim (), Name));
-                                       list.Add (t);
-                               }
-                       }
-                       return list;
+                       executeOnErrors = false;
+
+                       if (String.IsNullOrEmpty (DependsOnTargets))
+                               return true;
+
+                       var expr = new Expression ();
+                       expr.Parse (DependsOnTargets, ParseOptions.AllowItemsNoMetadataAndSplit);
+                       string [] targetNames = (string []) expr.ConvertTo (Project, typeof (string []));
+
+                       bool result = BuildOtherTargets (targetNames,
+                                                       tname => engine.LogError ("Target '{0}', a dependency of target '{1}', not found.",
+                                                                               tname, Name),
+                                                       out executeOnErrors);
+                       if (!result && executeOnErrors)
+                               ExecuteOnErrors ();
+
+                       return result;
+               }
+
+#if NET_4_0
+               bool BuildBeforeThisTargets (out bool executeOnErrors)
+               {
+                       executeOnErrors = false;
+                       bool result = BuildOtherTargets (BeforeThisTargets, null, out executeOnErrors);
+                       if (!result && executeOnErrors)
+                               ExecuteOnErrors ();
+
+                       return result;
                }
 
-               bool BuildDependencies (List <Target> deps, out bool executeOnErrors)
+               bool BuildAfterThisTargets (out bool executeOnErrors)
                {
                        executeOnErrors = false;
-                       foreach (Target t in deps) {
+                       //missing_target handler not required as these are picked from actual target's
+                       //"Before/AfterTargets attributes!
+                       bool result = BuildOtherTargets (AfterThisTargets, null, out executeOnErrors);
+                       if (!result && executeOnErrors)
+                               ExecuteOnErrors ();
+
+                       return result;
+               }
+#endif
+
+               bool BuildOtherTargets (IEnumerable<string> targetNames, Action<string> missing_target, out bool executeOnErrors)
+               {
+                       executeOnErrors = false;
+                       if (targetNames == null)
+                               // nothing to build
+                               return true;
+
+                       foreach (string target_name in targetNames) {
+                               var t = project.Targets [target_name.Trim ()];
+                               if (t == null) {
+                                       if (missing_target != null)
+                                               missing_target (target_name);
+                                       return false;
+                               }
+
                                if (t.BuildState == BuildState.NotStarted)
                                        if (!t.Build (null, out executeOnErrors))
                                                return false;
+
                                if (t.BuildState == BuildState.Started)
                                        throw new InvalidProjectFileException ("Cycle in target dependencies detected");
                        }
@@ -321,6 +356,19 @@ namespace Microsoft.Build.BuildEngine {
                        }
                }
 
+#if NET_4_0
+               internal string BeforeTargets {
+                       get { return targetElement.GetAttribute ("BeforeTargets"); }
+               }
+
+               internal string AfterTargets {
+                       get { return targetElement.GetAttribute ("AfterTargets"); }
+               }
+
+               internal List<string> BeforeThisTargets { get; set; }
+               internal List<string> AfterThisTargets { get; set; }
+#endif
+
                internal List<BuildTask> BuildTasks {
                        get { return buildTasks; }
                }