2 // Project.cs: Project class
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;
33 using System.Collections.Specialized;
35 using System.Reflection;
38 using System.Xml.Schema;
39 using Microsoft.Build.Framework;
40 using Mono.XBuild.Framework;
42 namespace Microsoft.Build.BuildEngine {
43 public class Project {
46 Dictionary <string, List <string>> conditionedProperties;
47 string[] defaultTargets;
49 BuildItemGroup evaluatedItems;
50 BuildItemGroup evaluatedItemsIgnoringCondition;
51 Dictionary <string, BuildItemGroup> evaluatedItemsByName;
52 Dictionary <string, BuildItemGroup> evaluatedItemsByNameIgnoringCondition;
53 BuildPropertyGroup evaluatedProperties;
54 string firstTargetName;
56 BuildPropertyGroup globalProperties;
57 GroupingCollection groupingCollection;
60 BuildItemGroupCollection itemGroups;
61 ImportCollection imports;
62 string[] initialTargets;
63 Dictionary <string, BuildItemGroup> last_item_group_containing;
64 bool needToReevaluate;
66 BuildPropertyGroupCollection propertyGroups;
68 TaskDatabase taskDatabase;
69 TargetCollection targets;
70 DateTime timeOfLastDirty;
71 UsingTaskCollection usingTasks;
72 XmlDocument xmlDocument;
74 bool initialTargetsBuilt;
75 List<string> builtTargetKeys;
77 BuildSettings current_settings;
79 static string extensions_path;
80 static XmlNamespaceManager manager;
81 static string ns = "http://schemas.microsoft.com/developer/msbuild/2003";
84 : this (Engine.GlobalEngine)
88 public Project (Engine engine)
90 parentEngine = engine;
92 buildEnabled = ParentEngine.BuildEnabled;
93 xmlDocument = new XmlDocument ();
94 xmlDocument.PreserveWhitespace = false;
95 xmlDocument.AppendChild (xmlDocument.CreateElement ("Project", XmlNamespace));
96 xmlDocument.DocumentElement.SetAttribute ("xmlns", ns);
98 fullFileName = String.Empty;
99 timeOfLastDirty = DateTime.Now;
100 current_settings = BuildSettings.None;
102 builtTargetKeys = new List<string> ();
104 globalProperties = new BuildPropertyGroup (null, this, null, false);
105 foreach (BuildProperty bp in parentEngine.GlobalProperties)
106 GlobalProperties.AddProperty (bp.Clone (true));
111 [MonoTODO ("Not tested")]
112 public void AddNewImport (string importLocation,
113 string importCondition)
115 if (importLocation == null)
116 throw new ArgumentNullException ("importLocation");
118 XmlElement importElement = xmlDocument.CreateElement ("Import", XmlNamespace);
119 xmlDocument.DocumentElement.AppendChild (importElement);
120 importElement.SetAttribute ("Project", importLocation);
121 if (!String.IsNullOrEmpty (importCondition))
122 importElement.SetAttribute ("Condition", importCondition);
124 Import import = new Import (importElement, this, null);
125 imports.Add (import);
126 MarkProjectAsDirty ();
130 public BuildItem AddNewItem (string itemName,
133 return AddNewItem (itemName, itemInclude, false);
136 [MonoTODO ("Adds item not in the same place as MS")]
137 public BuildItem AddNewItem (string itemName,
139 bool treatItemIncludeAsLiteral)
143 if (itemGroups.Count == 0)
144 big = AddNewItemGroup ();
146 if (last_item_group_containing.ContainsKey (itemName)) {
147 big = last_item_group_containing [itemName];
150 BuildItemGroup [] groups = new BuildItemGroup [itemGroups.Count];
151 itemGroups.CopyTo (groups, 0);
156 BuildItem item = big.AddNewItem (itemName, itemInclude, treatItemIncludeAsLiteral);
158 MarkProjectAsDirty ();
164 [MonoTODO ("Not tested")]
165 public BuildItemGroup AddNewItemGroup ()
167 XmlElement element = xmlDocument.CreateElement ("ItemGroup", XmlNamespace);
168 xmlDocument.DocumentElement.AppendChild (element);
170 BuildItemGroup big = new BuildItemGroup (element, this, null, false);
171 itemGroups.Add (big);
172 MarkProjectAsDirty ();
178 [MonoTODO ("Ignores insertAtEndOfProject")]
179 public BuildPropertyGroup AddNewPropertyGroup (bool insertAtEndOfProject)
181 XmlElement element = xmlDocument.CreateElement ("PropertyGroup", XmlNamespace);
182 xmlDocument.DocumentElement.AppendChild (element);
184 BuildPropertyGroup bpg = new BuildPropertyGroup (element, this, null, false);
185 propertyGroups.Add (bpg);
186 MarkProjectAsDirty ();
192 [MonoTODO ("Not tested, isn't added to TaskDatabase (no reevaluation)")]
193 public void AddNewUsingTaskFromAssemblyFile (string taskName,
196 if (taskName == null)
197 throw new ArgumentNullException ("taskName");
198 if (assemblyFile == null)
199 throw new ArgumentNullException ("assemblyFile");
201 XmlElement element = xmlDocument.CreateElement ("UsingTask", XmlNamespace);
202 xmlDocument.DocumentElement.AppendChild (element);
203 element.SetAttribute ("TaskName", taskName);
204 element.SetAttribute ("AssemblyFile", assemblyFile);
206 UsingTask ut = new UsingTask (element, this, null);
208 MarkProjectAsDirty ();
211 [MonoTODO ("Not tested, isn't added to TaskDatabase (no reevaluation)")]
212 public void AddNewUsingTaskFromAssemblyName (string taskName,
215 if (taskName == null)
216 throw new ArgumentNullException ("taskName");
217 if (assemblyName == null)
218 throw new ArgumentNullException ("assemblyName");
220 XmlElement element = xmlDocument.CreateElement ("UsingTask", XmlNamespace);
221 xmlDocument.DocumentElement.AppendChild (element);
222 element.SetAttribute ("TaskName", taskName);
223 element.SetAttribute ("AssemblyName", assemblyName);
225 UsingTask ut = new UsingTask (element, this, null);
227 MarkProjectAsDirty ();
230 [MonoTODO ("Not tested")]
233 return Build (new string [0]);
236 [MonoTODO ("Not tested")]
237 public bool Build (string targetName)
239 if (targetName == null)
240 return Build ((string[]) null);
242 return Build (new string [1] { targetName });
245 [MonoTODO ("Not tested")]
246 public bool Build (string [] targetNames)
248 return Build (targetNames, null);
251 [MonoTODO ("Not tested")]
252 public bool Build (string [] targetNames,
253 IDictionary targetOutputs)
255 return Build (targetNames, targetOutputs, BuildSettings.None);
258 [MonoTODO ("Not tested")]
259 public bool Build (string [] targetNames,
260 IDictionary targetOutputs,
261 BuildSettings buildFlags)
265 ParentEngine.StartProjectBuild (this, targetNames);
266 string current_directory = Environment.CurrentDirectory;
268 current_settings = buildFlags;
269 if (!String.IsNullOrEmpty (fullFileName))
270 Directory.SetCurrentDirectory (Path.GetDirectoryName (fullFileName));
272 result = BuildInternal (targetNames, targetOutputs, buildFlags);
274 ParentEngine.EndProjectBuild (this, result);
275 current_settings = BuildSettings.None;
276 Directory.SetCurrentDirectory (current_directory);
283 bool BuildInternal (string [] targetNames,
284 IDictionary targetOutputs,
285 BuildSettings buildFlags)
288 if (buildFlags == BuildSettings.None)
291 if (targetNames == null || targetNames.Length == 0) {
292 if (defaultTargets != null && defaultTargets.Length != 0)
293 targetNames = defaultTargets;
294 else if (firstTargetName != null)
295 targetNames = new string [1] { firstTargetName};
300 if (!initialTargetsBuilt && initialTargets != null && initialTargets.Length > 0) {
301 foreach (string target in initialTargets) {
302 if (!BuildTarget (target.Trim (), targetOutputs))
305 initialTargetsBuilt = true;
308 foreach (string target in targetNames)
309 if (!BuildTarget (target.Trim (), targetOutputs))
315 bool BuildTarget (string target, IDictionary targetOutputs)
318 throw new ArgumentException ("targetNames cannot contain null strings");
320 if (!targets.Exists (target)) {
322 Console.WriteLine ("Target named '{0}' not found in the project.", target);
326 // built targets are keyed by the particular set of global
327 // properties. So, a different set could allow a target
329 string key = fullFileName + ":" + target + ":" + GlobalPropertiesToString (GlobalProperties);
331 if (ParentEngine.BuiltTargetsOutputByName.TryGetValue (key, out outputs)) {
332 if (targetOutputs != null)
333 targetOutputs.Add (target, outputs);
334 LogTargetSkipped (target);
338 if (!targets [target].Build ())
341 ParentEngine.BuiltTargetsOutputByName [key] = (ITaskItem[]) targets [target].Outputs.Clone ();
342 builtTargetKeys.Add (key);
343 if (targetOutputs != null)
344 targetOutputs.Add (target, targets [target].Outputs);
349 string GlobalPropertiesToString (BuildPropertyGroup bgp)
351 StringBuilder sb = new StringBuilder ();
352 foreach (BuildProperty bp in bgp)
353 sb.AppendFormat (" {0}:{1}", bp.Name, bp.FinalValue);
354 return sb.ToString ();
358 public string [] GetConditionedPropertyValues (string propertyName)
360 if (conditionedProperties.ContainsKey (propertyName))
361 return conditionedProperties [propertyName].ToArray ();
363 return new string [0];
366 public BuildItemGroup GetEvaluatedItemsByName (string itemName)
368 if (needToReevaluate) {
369 needToReevaluate = false;
373 if (evaluatedItemsByName.ContainsKey (itemName))
374 return evaluatedItemsByName [itemName];
376 return new BuildItemGroup (this);
379 public BuildItemGroup GetEvaluatedItemsByNameIgnoringCondition (string itemName)
381 if (needToReevaluate) {
382 needToReevaluate = false;
386 if (evaluatedItemsByNameIgnoringCondition.ContainsKey (itemName))
387 return evaluatedItemsByNameIgnoringCondition [itemName];
389 return new BuildItemGroup (this);
392 public string GetEvaluatedProperty (string propertyName)
394 if (needToReevaluate) {
395 needToReevaluate = false;
399 if (propertyName == null)
400 throw new ArgumentNullException ("propertyName");
402 BuildProperty bp = evaluatedProperties [propertyName];
404 return bp == null ? null : (string) bp;
407 [MonoTODO ("We should remember that node and not use XPath to get it")]
408 public string GetProjectExtensions (string id)
410 if (id == null || id == String.Empty)
413 XmlNode node = xmlDocument.SelectSingleNode (String.Format ("/tns:Project/tns:ProjectExtensions/tns:{0}", id), XmlNamespaceManager);
418 return node.InnerXml;
422 public void Load (string projectFileName)
424 this.fullFileName = Utilities.FromMSBuildPath (Path.GetFullPath (projectFileName));
425 DoLoad (new StreamReader (fullFileName));
428 [MonoTODO ("Not tested")]
429 public void Load (TextReader textReader)
431 fullFileName = String.Empty;
435 public void LoadXml (string projectXml)
437 fullFileName = String.Empty;
438 DoLoad (new StringReader (projectXml));
439 MarkProjectAsDirty ();
443 public void MarkProjectAsDirty ()
446 timeOfLastDirty = DateTime.Now;
449 [MonoTODO ("Not tested")]
450 public void RemoveAllItemGroups ()
452 int length = ItemGroups.Count;
453 BuildItemGroup [] groups = new BuildItemGroup [length];
454 ItemGroups.CopyTo (groups, 0);
456 for (int i = 0; i < length; i++)
457 RemoveItemGroup (groups [i]);
459 MarkProjectAsDirty ();
463 [MonoTODO ("Not tested")]
464 public void RemoveAllPropertyGroups ()
466 int length = PropertyGroups.Count;
467 BuildPropertyGroup [] groups = new BuildPropertyGroup [length];
468 PropertyGroups.CopyTo (groups, 0);
470 for (int i = 0; i < length; i++)
471 RemovePropertyGroup (groups [i]);
473 MarkProjectAsDirty ();
478 public void RemoveItem (BuildItem itemToRemove)
480 if (itemToRemove == null)
481 throw new ArgumentNullException ("itemToRemove");
483 if (!itemToRemove.FromXml && !itemToRemove.HasParentItem)
484 throw new InvalidOperationException ("The object passed in is not part of the project.");
486 BuildItemGroup big = itemToRemove.ParentItemGroup;
488 if (big.Count == 1) {
489 // ParentItemGroup for items from xml and that have parent is the same
490 groupingCollection.Remove (big);
492 if (big.ParentProject != this)
493 throw new InvalidOperationException ("The object passed in is not part of the project.");
495 if (itemToRemove.FromXml)
496 big.RemoveItem (itemToRemove);
498 big.RemoveItem (itemToRemove.ParentItem);
501 MarkProjectAsDirty ();
505 [MonoTODO ("Not tested")]
506 public void RemoveItemGroup (BuildItemGroup itemGroupToRemove)
508 if (itemGroupToRemove == null)
509 throw new ArgumentNullException ("itemGroupToRemove");
511 groupingCollection.Remove (itemGroupToRemove);
512 MarkProjectAsDirty ();
516 // NOTE: does not modify imported projects
517 public void RemoveItemGroupsWithMatchingCondition (string matchingCondition)
519 throw new NotImplementedException ();
523 public void RemoveItemsByName (string itemName)
525 if (itemName == null)
526 throw new ArgumentNullException ("itemName");
528 throw new NotImplementedException ();
531 [MonoTODO ("Not tested")]
532 public void RemovePropertyGroup (BuildPropertyGroup propertyGroupToRemove)
534 if (propertyGroupToRemove == null)
535 throw new ArgumentNullException ("propertyGroupToRemove");
537 groupingCollection.Remove (propertyGroupToRemove);
538 MarkProjectAsDirty ();
542 // NOTE: does not modify imported projects
543 public void RemovePropertyGroupsWithMatchingCondition (string matchCondition)
545 throw new NotImplementedException ();
549 public void ResetBuildStatus ()
551 // hack to allow built targets to be removed
557 public void Save (string projectFileName)
559 Save (projectFileName, Encoding.Default);
563 [MonoTODO ("Ignores encoding")]
564 public void Save (string projectFileName, Encoding encoding)
566 xmlDocument.Save (projectFileName);
570 public void Save (TextWriter outTextWriter)
572 xmlDocument.Save (outTextWriter);
576 public void SetImportedProperty (string propertyName,
577 string propertyValue,
579 Project importProject)
581 SetImportedProperty (propertyName, propertyValue, condition, importProject,
582 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup);
585 public void SetImportedProperty (string propertyName,
586 string propertyValue,
588 Project importedProject,
589 PropertyPosition position)
591 SetImportedProperty (propertyName, propertyValue, condition, importedProject,
592 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
596 public void SetImportedProperty (string propertyName,
597 string propertyValue,
599 Project importedProject,
600 PropertyPosition position,
601 bool treatPropertyValueAsLiteral)
603 throw new NotImplementedException ();
606 public void SetProjectExtensions (string id, string xmlText)
609 throw new ArgumentNullException ("id");
611 throw new ArgumentNullException ("xmlText");
613 XmlNode projectExtensions, node;
615 projectExtensions = xmlDocument.SelectSingleNode ("/tns:Project/tns:ProjectExtensions", XmlNamespaceManager);
617 if (projectExtensions == null) {
618 projectExtensions = xmlDocument.CreateElement ("ProjectExtensions", XmlNamespace);
619 xmlDocument.DocumentElement.AppendChild (projectExtensions);
621 node = xmlDocument.CreateElement (id, XmlNamespace);
622 node.InnerXml = xmlText;
623 projectExtensions.AppendChild (node);
625 node = xmlDocument.SelectSingleNode (String.Format ("/tns:Project/tns:ProjectExtensions/tns:{0}", id), XmlNamespaceManager);
628 node = xmlDocument.CreateElement (id, XmlNamespace);
629 projectExtensions.AppendChild (node);
632 node.InnerXml = xmlText;
636 MarkProjectAsDirty ();
639 public void SetProperty (string propertyName,
640 string propertyValue)
642 SetProperty (propertyName, propertyValue, "true",
643 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
646 public void SetProperty (string propertyName,
647 string propertyValue,
650 SetProperty (propertyName, propertyValue, condition,
651 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup);
654 public void SetProperty (string propertyName,
655 string propertyValue,
657 PropertyPosition position)
659 SetProperty (propertyName, propertyValue, condition,
660 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
664 public void SetProperty (string propertyName,
665 string propertyValue,
667 PropertyPosition position,
668 bool treatPropertyValueAsLiteral)
670 throw new NotImplementedException ();
673 internal void Unload ()
678 internal void CheckUnloaded ()
681 throw new InvalidOperationException ("This project object has been unloaded from the MSBuild engine and is no longer valid.");
684 internal void NeedToReevaluate ()
686 needToReevaluate = true;
689 // Does the actual loading.
690 void DoLoad (TextReader textReader)
693 ParentEngine.RemoveLoadedProject (this);
695 XmlReaderSettings settings = new XmlReaderSettings ();
697 if (SchemaFile != null) {
698 settings.Schemas.Add (null, SchemaFile);
699 settings.ValidationType = ValidationType.Schema;
700 settings.ValidationEventHandler += new ValidationEventHandler (ValidationCallBack);
703 XmlReader xmlReader = XmlReader.Create (textReader, settings);
704 xmlDocument.Load (xmlReader);
706 if (xmlDocument.DocumentElement.Name != "Project") {
707 throw new InvalidProjectFileException (String.Format (
708 "The element <{0}> is unrecognized, or not supported in this context.", xmlDocument.DocumentElement.Name));
711 if (xmlDocument.DocumentElement.GetAttribute ("xmlns") != ns) {
712 throw new InvalidProjectFileException (
713 @"The default XML namespace of the project must be the MSBuild XML namespace." +
714 " If the project is authored in the MSBuild 2003 format, please add " +
715 "xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\" to the <Project> element. " +
716 "If the project has been authored in the old 1.0 or 1.2 format, please convert it to MSBuild 2003 format. ");
719 ParentEngine.AddLoadedProject (this);
720 } catch (Exception e) {
721 throw new InvalidProjectFileException (String.Format ("{0}: {1}",
722 fullFileName, e.Message), e);
724 if (textReader != null)
736 groupingCollection = new GroupingCollection (this);
737 imports = new ImportCollection (groupingCollection);
738 usingTasks = new UsingTaskCollection (this);
739 itemGroups = new BuildItemGroupCollection (groupingCollection);
740 propertyGroups = new BuildPropertyGroupCollection (groupingCollection);
741 targets = new TargetCollection (this);
742 last_item_group_containing = new Dictionary <string, BuildItemGroup> ();
744 taskDatabase = new TaskDatabase ();
745 if (ParentEngine.DefaultTasksRegistered)
746 taskDatabase.CopyTasks (ParentEngine.DefaultTasks);
748 if (xmlDocument.DocumentElement.GetAttributeNode ("DefaultTargets") != null)
749 defaultTargets = xmlDocument.DocumentElement.GetAttribute ("DefaultTargets").Split (';');
751 defaultTargets = new string [0];
753 ProcessProjectAttributes (xmlDocument.DocumentElement.Attributes);
754 ProcessElements (xmlDocument.DocumentElement, null);
760 void ProcessProjectAttributes (XmlAttributeCollection attributes)
762 foreach (XmlAttribute attr in attributes) {
764 case "InitialTargets":
765 initialTargets = attr.Value.Split (new char [] {';'},
766 StringSplitOptions.RemoveEmptyEntries);
768 case "DefaultTargets":
769 defaultTargets = attr.Value.Split (new char [] {';'},
770 StringSplitOptions.RemoveEmptyEntries);
776 internal void ProcessElements (XmlElement rootElement, ImportedProject ip)
778 foreach (XmlNode xn in rootElement.ChildNodes) {
779 if (xn is XmlElement) {
780 XmlElement xe = (XmlElement) xn;
782 case "ProjectExtensions":
783 AddProjectExtensions (xe);
794 AddUsingTask (xe, ip);
800 AddItemGroup (xe, ip);
802 case "PropertyGroup":
803 AddPropertyGroup (xe, ip);
809 throw new InvalidProjectFileException ("Invalid element in project file.");
817 evaluatedItems = new BuildItemGroup (null, this, null, true);
818 evaluatedItemsIgnoringCondition = new BuildItemGroup (null, this, null, true);
819 evaluatedItemsByName = new Dictionary <string, BuildItemGroup> (StringComparer.InvariantCultureIgnoreCase);
820 evaluatedItemsByNameIgnoringCondition = new Dictionary <string, BuildItemGroup> (StringComparer.InvariantCultureIgnoreCase);
821 if (building && current_settings == BuildSettings.None)
822 RemoveBuiltTargets ();
824 InitializeProperties ();
826 groupingCollection.Evaluate ();
828 //FIXME: UsingTasks aren't really evaluated. (shouldn't use expressions or anything)
829 foreach (UsingTask usingTask in UsingTasks)
830 usingTask.Evaluate ();
833 // Removes entries of all earlier built targets for this project
834 void RemoveBuiltTargets ()
836 foreach (string key in builtTargetKeys)
837 ParentEngine.BuiltTargetsOutputByName.Remove (key);
840 void InitializeProperties ()
844 evaluatedProperties = new BuildPropertyGroup (null, null, null, true);
846 foreach (BuildProperty gp in GlobalProperties) {
847 bp = new BuildProperty (gp.Name, gp.Value, PropertyType.Global);
848 EvaluatedProperties.AddProperty (bp);
851 foreach (BuildProperty gp in GlobalProperties)
852 ParentEngine.GlobalProperties.AddProperty (gp);
854 // add properties that we dont have from parent engine's
856 foreach (BuildProperty gp in ParentEngine.GlobalProperties) {
857 if (EvaluatedProperties [gp.Name] == null) {
858 bp = new BuildProperty (gp.Name, gp.Value, PropertyType.Global);
859 EvaluatedProperties.AddProperty (bp);
863 foreach (DictionaryEntry de in Environment.GetEnvironmentVariables ()) {
864 bp = new BuildProperty ((string) de.Key, (string) de.Value, PropertyType.Environment);
865 EvaluatedProperties.AddProperty (bp);
868 EvaluatedProperties.AddProperty (new BuildProperty ("MSBuildBinPath", parentEngine.BinPath, PropertyType.Reserved));
869 EvaluatedProperties.AddProperty (new BuildProperty ("MSBuildToolsPath", parentEngine.BinPath, PropertyType.Reserved));
870 EvaluatedProperties.AddProperty (new BuildProperty ("MSBuildExtensionsPath", ExtensionsPath, PropertyType.Reserved));
872 // FIXME: make some internal method that will work like GetDirectoryName but output String.Empty on null/String.Empty
874 if (FullFileName == String.Empty)
875 projectDir = Environment.CurrentDirectory;
877 projectDir = Path.GetDirectoryName (FullFileName);
879 EvaluatedProperties.AddProperty (new BuildProperty ("MSBuildProjectDirectory", projectDir, PropertyType.Reserved));
882 void AddProjectExtensions (XmlElement xmlElement)
886 void AddMessage (XmlElement xmlElement)
890 void AddTarget (XmlElement xmlElement, ImportedProject importedProject)
892 Target target = new Target (xmlElement, this, importedProject);
893 targets.AddTarget (target);
895 if (firstTargetName == null)
896 firstTargetName = target.Name;
899 void AddUsingTask (XmlElement xmlElement, ImportedProject importedProject)
903 usingTask = new UsingTask (xmlElement, this, importedProject);
904 UsingTasks.Add (usingTask);
907 void AddImport (XmlElement xmlElement, ImportedProject importingProject)
911 import = new Import (xmlElement, this, importingProject);
912 Imports.Add (import);
915 void AddItemGroup (XmlElement xmlElement, ImportedProject importedProject)
917 BuildItemGroup big = new BuildItemGroup (xmlElement, this, importedProject, false);
918 ItemGroups.Add (big);
921 void AddPropertyGroup (XmlElement xmlElement, ImportedProject importedProject)
923 BuildPropertyGroup bpg = new BuildPropertyGroup (xmlElement, this, importedProject, false);
924 PropertyGroups.Add (bpg);
927 void AddChoose (XmlElement xmlElement)
929 BuildChoose bc = new BuildChoose (xmlElement, this);
930 groupingCollection.Add (bc);
933 static void ValidationCallBack (object sender, ValidationEventArgs e)
935 Console.WriteLine ("Validation Error: {0}", e.Message);
938 public bool BuildEnabled {
943 buildEnabled = value;
948 public Encoding Encoding {
949 get { return encoding; }
952 public string DefaultTargets {
954 return xmlDocument.DocumentElement.GetAttribute ("DefaultTargets");
957 xmlDocument.DocumentElement.SetAttribute ("DefaultTargets", value);
958 defaultTargets = value.Split (new char [] {';'}, StringSplitOptions.RemoveEmptyEntries);
962 public BuildItemGroup EvaluatedItems {
964 if (needToReevaluate) {
965 needToReevaluate = false;
968 return evaluatedItems;
972 public BuildItemGroup EvaluatedItemsIgnoringCondition {
974 if (needToReevaluate) {
975 needToReevaluate = false;
978 return evaluatedItemsIgnoringCondition;
982 internal IDictionary <string, BuildItemGroup> EvaluatedItemsByName {
984 // FIXME: do we need to do this here?
985 if (needToReevaluate) {
986 needToReevaluate = false;
989 return evaluatedItemsByName;
993 internal IDictionary <string, BuildItemGroup> EvaluatedItemsByNameIgnoringCondition {
995 // FIXME: do we need to do this here?
996 if (needToReevaluate) {
997 needToReevaluate = false;
1000 return evaluatedItemsByNameIgnoringCondition;
1004 // For batching implementation
1005 Dictionary<string, BuildItemGroup> perBatchItemsByName;
1006 Dictionary<string, BuildItemGroup> commonItemsByName;
1008 internal void SetBatchedItems (Dictionary<string, BuildItemGroup> perBatchItemsByName, Dictionary<string, BuildItemGroup> commonItemsByName)
1010 this.perBatchItemsByName = perBatchItemsByName;
1011 this.commonItemsByName = commonItemsByName;
1015 internal bool TryGetEvaluatedItemByNameBatched (string itemName, out BuildItemGroup group)
1017 if (perBatchItemsByName == null && commonItemsByName == null)
1018 return EvaluatedItemsByName.TryGetValue (itemName, out group);
1020 if (perBatchItemsByName != null)
1021 return perBatchItemsByName.TryGetValue (itemName, out group);
1023 if (commonItemsByName != null)
1024 return commonItemsByName.TryGetValue (itemName, out group);
1030 internal string GetMetadataBatched (string itemName, string metadataName)
1032 BuildItemGroup group = null;
1033 if (itemName == null) {
1034 //unqualified, all items in a batch(bucket) have the
1035 //same metadata values
1036 group = GetFirst<BuildItemGroup> (perBatchItemsByName.Values);
1038 group = GetFirst<BuildItemGroup> (commonItemsByName.Values);
1041 TryGetEvaluatedItemByNameBatched (itemName, out group);
1044 if (group != null) {
1045 foreach (BuildItem item in group) {
1046 if (item.HasMetadata (metadataName))
1047 return item.GetMetadata (metadataName);
1050 return String.Empty;
1053 internal IEnumerable<BuildItemGroup> GetAllItemGroups ()
1055 if (perBatchItemsByName == null && commonItemsByName == null)
1056 foreach (BuildItemGroup group in EvaluatedItemsByName.Values)
1059 if (perBatchItemsByName != null)
1060 foreach (BuildItemGroup group in perBatchItemsByName.Values)
1063 if (commonItemsByName != null)
1064 foreach (BuildItemGroup group in commonItemsByName.Values)
1068 T GetFirst<T> (ICollection<T> list)
1073 foreach (T t in list)
1079 void LogTargetSkipped (string targetName)
1081 BuildMessageEventArgs bmea;
1082 bmea = new BuildMessageEventArgs (String.Format (
1083 "Target {0} skipped, as it has already been built.", targetName),
1084 null, null, MessageImportance.Low);
1086 ParentEngine.EventSource.FireMessageRaised (this, bmea);
1089 static string ExtensionsPath {
1091 if (extensions_path == null) {
1092 // NOTE: code from mcs/tools/gacutil/driver.cs
1093 PropertyInfo gac = typeof (System.Environment).GetProperty (
1094 "GacPath", BindingFlags.Static | BindingFlags.NonPublic);
1097 MethodInfo get_gac = gac.GetGetMethod (true);
1098 string gac_path = (string) get_gac.Invoke (null, null);
1099 extensions_path = Path.GetFullPath (Path.Combine (
1100 gac_path, Path.Combine ("..", "xbuild")));
1103 return extensions_path;
1107 public BuildPropertyGroup EvaluatedProperties {
1109 if (needToReevaluate) {
1110 needToReevaluate = false;
1113 return evaluatedProperties;
1117 public string FullFileName {
1118 get { return fullFileName; }
1119 set { fullFileName = value; }
1122 public BuildPropertyGroup GlobalProperties {
1123 get { return globalProperties; }
1126 throw new ArgumentNullException ("value");
1129 throw new InvalidOperationException ("GlobalProperties can not be set to persisted property group.");
1131 globalProperties = value;
1132 NeedToReevaluate ();
1136 public bool IsDirty {
1137 get { return isDirty; }
1140 public bool IsValidated {
1141 get { return isValidated; }
1142 set { isValidated = value; }
1145 public BuildItemGroupCollection ItemGroups {
1146 get { return itemGroups; }
1149 public ImportCollection Imports {
1150 get { return imports; }
1153 public string InitialTargets {
1155 return xmlDocument.DocumentElement.GetAttribute ("InitialTargets");
1158 xmlDocument.DocumentElement.SetAttribute ("InitialTargets", value);
1159 initialTargets = value.Split (new char [] {';'}, StringSplitOptions.RemoveEmptyEntries);
1163 public Engine ParentEngine {
1164 get { return parentEngine; }
1167 public BuildPropertyGroupCollection PropertyGroups {
1168 get { return propertyGroups; }
1171 public string SchemaFile {
1172 get { return schemaFile; }
1173 set { schemaFile = value; }
1176 public TargetCollection Targets {
1177 get { return targets; }
1180 public DateTime TimeOfLastDirty {
1181 get { return timeOfLastDirty; }
1184 public UsingTaskCollection UsingTasks {
1185 get { return usingTasks; }
1190 get { return xmlDocument.InnerXml; }
1193 internal Dictionary <string, BuildItemGroup> LastItemGroupContaining {
1194 get { return last_item_group_containing; }
1197 internal static XmlNamespaceManager XmlNamespaceManager {
1199 if (manager == null) {
1200 manager = new XmlNamespaceManager (new NameTable ());
1201 manager.AddNamespace ("tns", ns);
1208 internal TaskDatabase TaskDatabase {
1209 get { return taskDatabase; }
1212 internal XmlDocument XmlDocument {
1213 get { return xmlDocument; }
1216 internal static string XmlNamespace {