2 // Target.cs: Represents a target.
5 // Marek Sieradzki (marek.sieradzki@gmail.com)
7 // (C) 2005 Marek Sieradzki
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.
31 using System.Collections;
32 using System.Collections.Generic;
34 using Microsoft.Build.Framework;
36 namespace Microsoft.Build.BuildEngine {
37 public class Target : IEnumerable {
39 BatchingImpl batchingImpl;
40 BuildState buildState;
45 XmlElement targetElement;
46 List <XmlElement> onErrorElements;
47 List <BuildTask> buildTasks;
49 internal Target (XmlElement targetElement, Project project)
52 throw new ArgumentNullException ("project");
53 if (targetElement == null)
54 throw new ArgumentNullException ("targetElement");
56 this.targetElement = targetElement;
57 this.name = targetElement.GetAttribute ("Name");
59 this.project = project;
60 this.engine = project.ParentEngine;
61 this.isImported = false;;
63 this.onErrorElements = new List <XmlElement> ();
64 this.buildState = BuildState.NotStarted;
65 this.buildTasks = new List <BuildTask> ();
66 this.batchingImpl = new BatchingImpl (project, this.targetElement);
68 foreach (XmlNode xn in targetElement.ChildNodes) {
69 if (xn is XmlElement) {
70 XmlElement xe = (XmlElement) xn;
71 if (xe.Name == "OnError") {
72 onErrorElements.Add (xe);
75 buildTasks.Add (new BuildTask (xe, this));
81 public BuildTask AddNewTask (string taskName)
83 throw new NotImplementedException ();
86 public IEnumerator GetEnumerator ()
88 foreach (BuildTask bt in buildTasks)
92 public void RemoveTask (BuildTask buildTask)
94 if (buildTask == null)
95 throw new ArgumentNullException ("buildTask");
96 buildTasks.Remove (buildTask);
99 internal bool Build ()
103 buildState = BuildState.Started;
105 if (DependsOnTargets != String.Empty) {
106 Expression dependencies = new Expression ();
107 dependencies.Parse (DependsOnTargets);
109 string[] targetsToBuildFirst = (string[]) dependencies.ConvertTo (Project, typeof (string[]));
110 foreach (string target in targetsToBuildFirst) {
111 string trimmed = target.Trim ();
112 Target t = (Target) project.Targets [trimmed];
114 throw new InvalidProjectFileException (String.Format ("Target {0} not found.", trimmed));
115 if (t.BuildState == BuildState.NotStarted) {
118 if (t.BuildState == BuildState.Started)
119 throw new InvalidProjectFileException ("Cycle in target dependencies detected.");
123 result = RealBuild ();
124 buildState = BuildState.Finished;
129 private bool RealBuild ()
131 bool executeOnErrors = false;
136 if (batchingImpl.BuildNeeded ()) {
137 foreach (BuildTask bt in buildTasks) {
138 result = batchingImpl.BatchBuildTask (bt);
140 if (!result && !bt.ContinueOnError) {
141 executeOnErrors = true;
149 LogTargetFinished (result);
151 if (executeOnErrors == true)
157 private void ExecuteOnErrors ()
159 foreach (XmlElement onError in onErrorElements) {
160 // FIXME: add condition
161 if (onError.GetAttribute ("ExecuteTargets") == String.Empty)
162 throw new InvalidProjectFileException ("ExecuteTargets attribute is required in OnError element.");
163 string[] targetsToExecute = onError.GetAttribute ("ExecuteTargets").Split (';');
164 foreach (string t in targetsToExecute)
165 this.project.Targets [t].Build ();
169 private void LogTargetSkipped ()
171 BuildMessageEventArgs bmea;
172 bmea = new BuildMessageEventArgs (String.Format ("Skipping target \"{0}\" because its outputs are up-to-date.",
173 name), null, "MSBuild", MessageImportance.Normal);
174 engine.EventSource.FireMessageRaised (this, bmea);
177 private void LogTargetStarted ()
179 TargetStartedEventArgs tsea;
180 string projectFile = project.FullFileName;
181 tsea = new TargetStartedEventArgs ("Target " + name + " started.", null, name, projectFile, null);
182 engine.EventSource.FireTargetStarted (this, tsea);
185 private void LogTargetFinished (bool succeeded)
187 TargetFinishedEventArgs tfea;
188 string projectFile = project.FullFileName;
189 tfea = new TargetFinishedEventArgs ("Target " + name + " finished.", null, name, projectFile, null, succeeded);
190 engine.EventSource.FireTargetFinished (this, tfea);
193 public string Condition {
194 get { return targetElement.GetAttribute ("Condition"); }
195 set { targetElement.SetAttribute ("Condition", value); }
198 public string DependsOnTargets {
199 get { return targetElement.GetAttribute ("DependsOnTargets"); }
200 set { targetElement.SetAttribute ("DependsOnTargets", value); }
203 public bool IsImported {
204 get { return isImported; }
205 internal set { isImported = value; }
212 internal Project Project {
213 get { return project; }
216 internal BuildState BuildState {
217 get { return buildState; }
221 internal enum BuildState {