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;
41 using Mono.XBuild.CommandLine;
43 namespace Microsoft.Build.BuildEngine {
44 public class Project {
47 Dictionary <string, List <string>> conditionedProperties;
48 string[] defaultTargets;
50 BuildItemGroup evaluatedItems;
51 BuildItemGroup evaluatedItemsIgnoringCondition;
52 Dictionary <string, BuildItemGroup> evaluatedItemsByName;
53 Dictionary <string, BuildItemGroup> evaluatedItemsByNameIgnoringCondition;
54 BuildPropertyGroup evaluatedProperties;
55 string firstTargetName;
57 BuildPropertyGroup globalProperties;
58 GroupingCollection groupingCollection;
61 BuildItemGroupCollection itemGroups;
62 ImportCollection imports;
63 string[] initialTargets;
64 Dictionary <string, BuildItemGroup> last_item_group_containing;
65 bool needToReevaluate;
67 BuildPropertyGroupCollection propertyGroups;
69 TaskDatabase taskDatabase;
70 TargetCollection targets;
71 DateTime timeOfLastDirty;
72 UsingTaskCollection usingTasks;
73 XmlDocument xmlDocument;
75 bool initialTargetsBuilt;
76 List<string> builtTargetKeys;
78 BuildSettings current_settings;
80 static string extensions_path;
81 static XmlNamespaceManager manager;
82 static string ns = "http://schemas.microsoft.com/developer/msbuild/2003";
85 : this (Engine.GlobalEngine)
89 public Project (Engine engine)
91 parentEngine = engine;
93 buildEnabled = ParentEngine.BuildEnabled;
94 xmlDocument = new XmlDocument ();
95 xmlDocument.PreserveWhitespace = false;
96 xmlDocument.AppendChild (xmlDocument.CreateElement ("Project", XmlNamespace));
97 xmlDocument.DocumentElement.SetAttribute ("xmlns", ns);
99 fullFileName = String.Empty;
100 timeOfLastDirty = DateTime.Now;
101 current_settings = BuildSettings.None;
103 builtTargetKeys = new List<string> ();
105 globalProperties = new BuildPropertyGroup (null, this, null, false);
106 foreach (BuildProperty bp in parentEngine.GlobalProperties)
107 GlobalProperties.AddProperty (bp.Clone (true));
112 [MonoTODO ("Not tested")]
113 public void AddNewImport (string importLocation,
114 string importCondition)
116 if (importLocation == null)
117 throw new ArgumentNullException ("importLocation");
119 XmlElement importElement = xmlDocument.CreateElement ("Import", XmlNamespace);
120 xmlDocument.DocumentElement.AppendChild (importElement);
121 importElement.SetAttribute ("Project", importLocation);
122 if (!String.IsNullOrEmpty (importCondition))
123 importElement.SetAttribute ("Condition", importCondition);
125 Import import = new Import (importElement, this, null);
126 imports.Add (import);
127 MarkProjectAsDirty ();
131 public BuildItem AddNewItem (string itemName,
134 return AddNewItem (itemName, itemInclude, false);
137 [MonoTODO ("Adds item not in the same place as MS")]
138 public BuildItem AddNewItem (string itemName,
140 bool treatItemIncludeAsLiteral)
144 if (itemGroups.Count == 0)
145 big = AddNewItemGroup ();
147 if (last_item_group_containing.ContainsKey (itemName)) {
148 big = last_item_group_containing [itemName];
151 BuildItemGroup [] groups = new BuildItemGroup [itemGroups.Count];
152 itemGroups.CopyTo (groups, 0);
157 BuildItem item = big.AddNewItem (itemName, itemInclude, treatItemIncludeAsLiteral);
159 MarkProjectAsDirty ();
165 [MonoTODO ("Not tested")]
166 public BuildItemGroup AddNewItemGroup ()
168 XmlElement element = xmlDocument.CreateElement ("ItemGroup", XmlNamespace);
169 xmlDocument.DocumentElement.AppendChild (element);
171 BuildItemGroup big = new BuildItemGroup (element, this, null, false);
172 itemGroups.Add (big);
173 MarkProjectAsDirty ();
179 [MonoTODO ("Ignores insertAtEndOfProject")]
180 public BuildPropertyGroup AddNewPropertyGroup (bool insertAtEndOfProject)
182 XmlElement element = xmlDocument.CreateElement ("PropertyGroup", XmlNamespace);
183 xmlDocument.DocumentElement.AppendChild (element);
185 BuildPropertyGroup bpg = new BuildPropertyGroup (element, this, null, false);
186 propertyGroups.Add (bpg);
187 MarkProjectAsDirty ();
193 [MonoTODO ("Not tested, isn't added to TaskDatabase (no reevaluation)")]
194 public void AddNewUsingTaskFromAssemblyFile (string taskName,
197 if (taskName == null)
198 throw new ArgumentNullException ("taskName");
199 if (assemblyFile == null)
200 throw new ArgumentNullException ("assemblyFile");
202 XmlElement element = xmlDocument.CreateElement ("UsingTask", XmlNamespace);
203 xmlDocument.DocumentElement.AppendChild (element);
204 element.SetAttribute ("TaskName", taskName);
205 element.SetAttribute ("AssemblyFile", assemblyFile);
207 UsingTask ut = new UsingTask (element, this, null);
209 MarkProjectAsDirty ();
212 [MonoTODO ("Not tested, isn't added to TaskDatabase (no reevaluation)")]
213 public void AddNewUsingTaskFromAssemblyName (string taskName,
216 if (taskName == null)
217 throw new ArgumentNullException ("taskName");
218 if (assemblyName == null)
219 throw new ArgumentNullException ("assemblyName");
221 XmlElement element = xmlDocument.CreateElement ("UsingTask", XmlNamespace);
222 xmlDocument.DocumentElement.AppendChild (element);
223 element.SetAttribute ("TaskName", taskName);
224 element.SetAttribute ("AssemblyName", assemblyName);
226 UsingTask ut = new UsingTask (element, this, null);
228 MarkProjectAsDirty ();
231 [MonoTODO ("Not tested")]
234 return Build (new string [0]);
237 [MonoTODO ("Not tested")]
238 public bool Build (string targetName)
240 if (targetName == null)
241 return Build ((string[]) null);
243 return Build (new string [1] { targetName });
246 [MonoTODO ("Not tested")]
247 public bool Build (string [] targetNames)
249 return Build (targetNames, null);
252 [MonoTODO ("Not tested")]
253 public bool Build (string [] targetNames,
254 IDictionary targetOutputs)
256 return Build (targetNames, targetOutputs, BuildSettings.None);
259 [MonoTODO ("Not tested")]
260 public bool Build (string [] targetNames,
261 IDictionary targetOutputs,
262 BuildSettings buildFlags)
266 ParentEngine.StartProjectBuild (this, targetNames);
267 string current_directory = Environment.CurrentDirectory;
269 current_settings = buildFlags;
270 if (!String.IsNullOrEmpty (fullFileName))
271 Directory.SetCurrentDirectory (Path.GetDirectoryName (fullFileName));
273 result = BuildInternal (targetNames, targetOutputs, buildFlags);
275 ParentEngine.EndProjectBuild (this, result);
276 current_settings = BuildSettings.None;
277 Directory.SetCurrentDirectory (current_directory);
284 bool BuildInternal (string [] targetNames,
285 IDictionary targetOutputs,
286 BuildSettings buildFlags)
289 if (buildFlags == BuildSettings.None)
292 if (targetNames == null || targetNames.Length == 0) {
293 if (defaultTargets != null && defaultTargets.Length != 0)
294 targetNames = defaultTargets;
295 else if (firstTargetName != null)
296 targetNames = new string [1] { firstTargetName};
301 if (!initialTargetsBuilt && initialTargets != null && initialTargets.Length > 0) {
302 foreach (string target in initialTargets) {
303 if (!BuildTarget (target.Trim (), targetOutputs))
306 initialTargetsBuilt = true;
309 foreach (string target in targetNames)
310 if (!BuildTarget (target.Trim (), targetOutputs))
316 bool BuildTarget (string target_name, IDictionary targetOutputs)
318 if (target_name == null)
319 throw new ArgumentException ("targetNames cannot contain null strings");
321 if (!targets.Exists (target_name)) {
323 Console.WriteLine ("Target named '{0}' not found in the project.", target_name);
327 string key = GetKeyForTarget (target_name);
328 if (!targets [target_name].Build (key))
331 ITaskItem[] outputs = ParentEngine.BuiltTargetsOutputByName [key];
332 if (targetOutputs != null)
333 targetOutputs.Add (target_name, outputs);
337 internal string GetKeyForTarget (string target_name)
339 // target name is case insensitive
340 return fullFileName + ":" + target_name.ToLower () + ":" + GlobalPropertiesToString (GlobalProperties);
343 string GlobalPropertiesToString (BuildPropertyGroup bgp)
345 StringBuilder sb = new StringBuilder ();
346 foreach (BuildProperty bp in bgp)
347 sb.AppendFormat (" {0}:{1}", bp.Name, bp.FinalValue);
348 return sb.ToString ();
352 public string [] GetConditionedPropertyValues (string propertyName)
354 if (conditionedProperties.ContainsKey (propertyName))
355 return conditionedProperties [propertyName].ToArray ();
357 return new string [0];
360 public BuildItemGroup GetEvaluatedItemsByName (string itemName)
362 if (needToReevaluate) {
363 needToReevaluate = false;
367 if (evaluatedItemsByName.ContainsKey (itemName))
368 return evaluatedItemsByName [itemName];
370 return new BuildItemGroup (this);
373 public BuildItemGroup GetEvaluatedItemsByNameIgnoringCondition (string itemName)
375 if (needToReevaluate) {
376 needToReevaluate = false;
380 if (evaluatedItemsByNameIgnoringCondition.ContainsKey (itemName))
381 return evaluatedItemsByNameIgnoringCondition [itemName];
383 return new BuildItemGroup (this);
386 public string GetEvaluatedProperty (string propertyName)
388 if (needToReevaluate) {
389 needToReevaluate = false;
393 if (propertyName == null)
394 throw new ArgumentNullException ("propertyName");
396 BuildProperty bp = evaluatedProperties [propertyName];
398 return bp == null ? null : (string) bp;
401 [MonoTODO ("We should remember that node and not use XPath to get it")]
402 public string GetProjectExtensions (string id)
404 if (id == null || id == String.Empty)
407 XmlNode node = xmlDocument.SelectSingleNode (String.Format ("/tns:Project/tns:ProjectExtensions/tns:{0}", id), XmlNamespaceManager);
412 return node.InnerXml;
416 public void Load (string projectFileName)
418 this.fullFileName = Utilities.FromMSBuildPath (Path.GetFullPath (projectFileName));
420 string filename = fullFileName;
421 if (String.Compare (Path.GetExtension (fullFileName), ".sln", true) == 0) {
422 Project tmp_project = ParentEngine.CreateNewProject ();
423 SolutionParser sln_parser = new SolutionParser ();
424 sln_parser.ParseSolution (fullFileName, tmp_project, delegate (int errorNumber, string message) {
425 LogWarning (filename, message);
427 filename = fullFileName + ".proj";
429 tmp_project.Save (filename);
430 ParentEngine.RemoveLoadedProject (tmp_project);
431 DoLoad (new StreamReader (filename));
433 if (Environment.GetEnvironmentVariable ("XBUILD_EMIT_SOLUTION") == null)
434 File.Delete (filename);
437 DoLoad (new StreamReader (filename));
441 [MonoTODO ("Not tested")]
442 public void Load (TextReader textReader)
444 fullFileName = String.Empty;
448 public void LoadXml (string projectXml)
450 fullFileName = String.Empty;
451 DoLoad (new StringReader (projectXml));
452 MarkProjectAsDirty ();
456 public void MarkProjectAsDirty ()
459 timeOfLastDirty = DateTime.Now;
462 [MonoTODO ("Not tested")]
463 public void RemoveAllItemGroups ()
465 int length = ItemGroups.Count;
466 BuildItemGroup [] groups = new BuildItemGroup [length];
467 ItemGroups.CopyTo (groups, 0);
469 for (int i = 0; i < length; i++)
470 RemoveItemGroup (groups [i]);
472 MarkProjectAsDirty ();
476 [MonoTODO ("Not tested")]
477 public void RemoveAllPropertyGroups ()
479 int length = PropertyGroups.Count;
480 BuildPropertyGroup [] groups = new BuildPropertyGroup [length];
481 PropertyGroups.CopyTo (groups, 0);
483 for (int i = 0; i < length; i++)
484 RemovePropertyGroup (groups [i]);
486 MarkProjectAsDirty ();
491 public void RemoveItem (BuildItem itemToRemove)
493 if (itemToRemove == null)
494 throw new ArgumentNullException ("itemToRemove");
496 if (!itemToRemove.FromXml && !itemToRemove.HasParentItem)
497 throw new InvalidOperationException ("The object passed in is not part of the project.");
499 BuildItemGroup big = itemToRemove.ParentItemGroup;
501 if (big.Count == 1) {
502 // ParentItemGroup for items from xml and that have parent is the same
503 groupingCollection.Remove (big);
505 if (big.ParentProject != this)
506 throw new InvalidOperationException ("The object passed in is not part of the project.");
508 if (itemToRemove.FromXml)
509 big.RemoveItem (itemToRemove);
511 big.RemoveItem (itemToRemove.ParentItem);
514 MarkProjectAsDirty ();
518 [MonoTODO ("Not tested")]
519 public void RemoveItemGroup (BuildItemGroup itemGroupToRemove)
521 if (itemGroupToRemove == null)
522 throw new ArgumentNullException ("itemGroupToRemove");
524 groupingCollection.Remove (itemGroupToRemove);
525 MarkProjectAsDirty ();
529 // NOTE: does not modify imported projects
530 public void RemoveItemGroupsWithMatchingCondition (string matchingCondition)
532 throw new NotImplementedException ();
536 public void RemoveItemsByName (string itemName)
538 if (itemName == null)
539 throw new ArgumentNullException ("itemName");
541 throw new NotImplementedException ();
544 [MonoTODO ("Not tested")]
545 public void RemovePropertyGroup (BuildPropertyGroup propertyGroupToRemove)
547 if (propertyGroupToRemove == null)
548 throw new ArgumentNullException ("propertyGroupToRemove");
550 groupingCollection.Remove (propertyGroupToRemove);
551 MarkProjectAsDirty ();
555 // NOTE: does not modify imported projects
556 public void RemovePropertyGroupsWithMatchingCondition (string matchCondition)
558 throw new NotImplementedException ();
562 public void ResetBuildStatus ()
564 // hack to allow built targets to be removed
570 public void Save (string projectFileName)
572 Save (projectFileName, Encoding.Default);
576 [MonoTODO ("Ignores encoding")]
577 public void Save (string projectFileName, Encoding encoding)
579 xmlDocument.Save (projectFileName);
583 public void Save (TextWriter outTextWriter)
585 xmlDocument.Save (outTextWriter);
589 public void SetImportedProperty (string propertyName,
590 string propertyValue,
592 Project importProject)
594 SetImportedProperty (propertyName, propertyValue, condition, importProject,
595 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup);
598 public void SetImportedProperty (string propertyName,
599 string propertyValue,
601 Project importedProject,
602 PropertyPosition position)
604 SetImportedProperty (propertyName, propertyValue, condition, importedProject,
605 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
609 public void SetImportedProperty (string propertyName,
610 string propertyValue,
612 Project importedProject,
613 PropertyPosition position,
614 bool treatPropertyValueAsLiteral)
616 throw new NotImplementedException ();
619 public void SetProjectExtensions (string id, string xmlText)
622 throw new ArgumentNullException ("id");
624 throw new ArgumentNullException ("xmlText");
626 XmlNode projectExtensions, node;
628 projectExtensions = xmlDocument.SelectSingleNode ("/tns:Project/tns:ProjectExtensions", XmlNamespaceManager);
630 if (projectExtensions == null) {
631 projectExtensions = xmlDocument.CreateElement ("ProjectExtensions", XmlNamespace);
632 xmlDocument.DocumentElement.AppendChild (projectExtensions);
634 node = xmlDocument.CreateElement (id, XmlNamespace);
635 node.InnerXml = xmlText;
636 projectExtensions.AppendChild (node);
638 node = xmlDocument.SelectSingleNode (String.Format ("/tns:Project/tns:ProjectExtensions/tns:{0}", id), XmlNamespaceManager);
641 node = xmlDocument.CreateElement (id, XmlNamespace);
642 projectExtensions.AppendChild (node);
645 node.InnerXml = xmlText;
649 MarkProjectAsDirty ();
652 public void SetProperty (string propertyName,
653 string propertyValue)
655 SetProperty (propertyName, propertyValue, "true",
656 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
659 public void SetProperty (string propertyName,
660 string propertyValue,
663 SetProperty (propertyName, propertyValue, condition,
664 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup);
667 public void SetProperty (string propertyName,
668 string propertyValue,
670 PropertyPosition position)
672 SetProperty (propertyName, propertyValue, condition,
673 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
677 public void SetProperty (string propertyName,
678 string propertyValue,
680 PropertyPosition position,
681 bool treatPropertyValueAsLiteral)
683 throw new NotImplementedException ();
686 internal void Unload ()
691 internal void CheckUnloaded ()
694 throw new InvalidOperationException ("This project object has been unloaded from the MSBuild engine and is no longer valid.");
697 internal void NeedToReevaluate ()
699 needToReevaluate = true;
702 // Does the actual loading.
703 void DoLoad (TextReader textReader)
706 ParentEngine.RemoveLoadedProject (this);
708 XmlReaderSettings settings = new XmlReaderSettings ();
710 if (SchemaFile != null) {
711 settings.Schemas.Add (null, SchemaFile);
712 settings.ValidationType = ValidationType.Schema;
713 settings.ValidationEventHandler += new ValidationEventHandler (ValidationCallBack);
716 XmlReader xmlReader = XmlReader.Create (textReader, settings);
717 xmlDocument.Load (xmlReader);
719 if (xmlDocument.DocumentElement.Name == "VisualStudioProject")
720 throw new InvalidProjectFileException (String.Format (
721 "Project file '{0}' is a VS2003 project, which is not " +
722 "supported by xbuild. You need to convert it to msbuild " +
723 "format to build with xbuild.", fullFileName));
725 if (xmlDocument.DocumentElement.Name != "Project") {
726 throw new InvalidProjectFileException (String.Format (
727 "The element <{0}> is unrecognized, or not supported in this context.", xmlDocument.DocumentElement.Name));
730 if (xmlDocument.DocumentElement.GetAttribute ("xmlns") != ns) {
731 throw new InvalidProjectFileException (
732 @"The default XML namespace of the project must be the MSBuild XML namespace." +
733 " If the project is authored in the MSBuild 2003 format, please add " +
734 "xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\" to the <Project> element. " +
735 "If the project has been authored in the old 1.0 or 1.2 format, please convert it to MSBuild 2003 format. ");
738 ParentEngine.AddLoadedProject (this);
739 } catch (Exception e) {
740 throw new InvalidProjectFileException (String.Format ("{0}: {1}",
741 fullFileName, e.Message), e);
743 if (textReader != null)
755 groupingCollection = new GroupingCollection (this);
756 imports = new ImportCollection (groupingCollection);
757 usingTasks = new UsingTaskCollection (this);
758 itemGroups = new BuildItemGroupCollection (groupingCollection);
759 propertyGroups = new BuildPropertyGroupCollection (groupingCollection);
760 targets = new TargetCollection (this);
761 last_item_group_containing = new Dictionary <string, BuildItemGroup> ();
763 taskDatabase = new TaskDatabase ();
764 if (ParentEngine.DefaultTasksRegistered)
765 taskDatabase.CopyTasks (ParentEngine.DefaultTasks);
767 if (xmlDocument.DocumentElement.GetAttributeNode ("DefaultTargets") != null)
768 defaultTargets = xmlDocument.DocumentElement.GetAttribute ("DefaultTargets").Split (';');
770 defaultTargets = new string [0];
772 ProcessProjectAttributes (xmlDocument.DocumentElement.Attributes);
773 ProcessElements (xmlDocument.DocumentElement, null);
779 void ProcessProjectAttributes (XmlAttributeCollection attributes)
781 foreach (XmlAttribute attr in attributes) {
783 case "InitialTargets":
784 initialTargets = attr.Value.Split (new char [] {';'},
785 StringSplitOptions.RemoveEmptyEntries);
787 case "DefaultTargets":
788 defaultTargets = attr.Value.Split (new char [] {';'},
789 StringSplitOptions.RemoveEmptyEntries);
795 internal void ProcessElements (XmlElement rootElement, ImportedProject ip)
797 foreach (XmlNode xn in rootElement.ChildNodes) {
798 if (xn is XmlElement) {
799 XmlElement xe = (XmlElement) xn;
801 case "ProjectExtensions":
802 AddProjectExtensions (xe);
813 AddUsingTask (xe, ip);
819 AddItemGroup (xe, ip);
821 case "PropertyGroup":
822 AddPropertyGroup (xe, ip);
828 throw new InvalidProjectFileException ("Invalid element in project file.");
836 evaluatedItems = new BuildItemGroup (null, this, null, true);
837 evaluatedItemsIgnoringCondition = new BuildItemGroup (null, this, null, true);
838 evaluatedItemsByName = new Dictionary <string, BuildItemGroup> (StringComparer.InvariantCultureIgnoreCase);
839 evaluatedItemsByNameIgnoringCondition = new Dictionary <string, BuildItemGroup> (StringComparer.InvariantCultureIgnoreCase);
840 if (building && current_settings == BuildSettings.None)
841 RemoveBuiltTargets ();
843 InitializeProperties ();
845 groupingCollection.Evaluate ();
847 //FIXME: UsingTasks aren't really evaluated. (shouldn't use expressions or anything)
848 foreach (UsingTask usingTask in UsingTasks)
849 usingTask.Evaluate ();
852 // Removes entries of all earlier built targets for this project
853 void RemoveBuiltTargets ()
855 foreach (string key in builtTargetKeys)
856 ParentEngine.BuiltTargetsOutputByName.Remove (key);
859 void InitializeProperties ()
863 evaluatedProperties = new BuildPropertyGroup (null, null, null, true);
865 foreach (BuildProperty gp in GlobalProperties) {
866 bp = new BuildProperty (gp.Name, gp.Value, PropertyType.Global);
867 EvaluatedProperties.AddProperty (bp);
870 foreach (BuildProperty gp in GlobalProperties)
871 ParentEngine.GlobalProperties.AddProperty (gp);
873 // add properties that we dont have from parent engine's
875 foreach (BuildProperty gp in ParentEngine.GlobalProperties) {
876 if (EvaluatedProperties [gp.Name] == null) {
877 bp = new BuildProperty (gp.Name, gp.Value, PropertyType.Global);
878 EvaluatedProperties.AddProperty (bp);
882 foreach (DictionaryEntry de in Environment.GetEnvironmentVariables ()) {
883 bp = new BuildProperty ((string) de.Key, (string) de.Value, PropertyType.Environment);
884 EvaluatedProperties.AddProperty (bp);
887 EvaluatedProperties.AddProperty (new BuildProperty ("MSBuildProjectFile", Path.GetFileName (fullFileName),
888 PropertyType.Reserved));
889 EvaluatedProperties.AddProperty (new BuildProperty ("MSBuildProjectName",
890 Path.GetFileNameWithoutExtension (fullFileName),
891 PropertyType.Reserved));
892 EvaluatedProperties.AddProperty (new BuildProperty ("MSBuildBinPath", parentEngine.BinPath, PropertyType.Reserved));
893 EvaluatedProperties.AddProperty (new BuildProperty ("MSBuildToolsPath", parentEngine.BinPath, PropertyType.Reserved));
894 EvaluatedProperties.AddProperty (new BuildProperty ("MSBuildExtensionsPath", ExtensionsPath, PropertyType.Reserved));
895 EvaluatedProperties.AddProperty (new BuildProperty ("MSBuildProjectDefaultTargets", DefaultTargets, PropertyType.Reserved));
897 // FIXME: make some internal method that will work like GetDirectoryName but output String.Empty on null/String.Empty
899 if (FullFileName == String.Empty)
900 projectDir = Environment.CurrentDirectory;
902 projectDir = Path.GetDirectoryName (FullFileName);
904 EvaluatedProperties.AddProperty (new BuildProperty ("MSBuildProjectDirectory", projectDir, PropertyType.Reserved));
907 void AddProjectExtensions (XmlElement xmlElement)
911 void AddMessage (XmlElement xmlElement)
915 void AddTarget (XmlElement xmlElement, ImportedProject importedProject)
917 Target target = new Target (xmlElement, this, importedProject);
918 targets.AddTarget (target);
920 if (firstTargetName == null)
921 firstTargetName = target.Name;
924 void AddUsingTask (XmlElement xmlElement, ImportedProject importedProject)
928 usingTask = new UsingTask (xmlElement, this, importedProject);
929 UsingTasks.Add (usingTask);
932 void AddImport (XmlElement xmlElement, ImportedProject importingProject)
936 import = new Import (xmlElement, this, importingProject);
937 Imports.Add (import);
940 void AddItemGroup (XmlElement xmlElement, ImportedProject importedProject)
942 BuildItemGroup big = new BuildItemGroup (xmlElement, this, importedProject, false);
943 ItemGroups.Add (big);
946 void AddPropertyGroup (XmlElement xmlElement, ImportedProject importedProject)
948 BuildPropertyGroup bpg = new BuildPropertyGroup (xmlElement, this, importedProject, false);
949 PropertyGroups.Add (bpg);
952 void AddChoose (XmlElement xmlElement)
954 BuildChoose bc = new BuildChoose (xmlElement, this);
955 groupingCollection.Add (bc);
958 static void ValidationCallBack (object sender, ValidationEventArgs e)
960 Console.WriteLine ("Validation Error: {0}", e.Message);
963 public bool BuildEnabled {
968 buildEnabled = value;
973 public Encoding Encoding {
974 get { return encoding; }
977 public string DefaultTargets {
979 return xmlDocument.DocumentElement.GetAttribute ("DefaultTargets");
982 xmlDocument.DocumentElement.SetAttribute ("DefaultTargets", value);
983 defaultTargets = value.Split (new char [] {';'}, StringSplitOptions.RemoveEmptyEntries);
987 public BuildItemGroup EvaluatedItems {
989 if (needToReevaluate) {
990 needToReevaluate = false;
993 return evaluatedItems;
997 public BuildItemGroup EvaluatedItemsIgnoringCondition {
999 if (needToReevaluate) {
1000 needToReevaluate = false;
1003 return evaluatedItemsIgnoringCondition;
1007 internal IDictionary <string, BuildItemGroup> EvaluatedItemsByName {
1009 // FIXME: do we need to do this here?
1010 if (needToReevaluate) {
1011 needToReevaluate = false;
1014 return evaluatedItemsByName;
1018 internal IDictionary <string, BuildItemGroup> EvaluatedItemsByNameIgnoringCondition {
1020 // FIXME: do we need to do this here?
1021 if (needToReevaluate) {
1022 needToReevaluate = false;
1025 return evaluatedItemsByNameIgnoringCondition;
1029 // For batching implementation
1030 Dictionary<string, BuildItemGroup> perBatchItemsByName;
1031 Dictionary<string, BuildItemGroup> commonItemsByName;
1033 internal void SetBatchedItems (Dictionary<string, BuildItemGroup> perBatchItemsByName, Dictionary<string, BuildItemGroup> commonItemsByName)
1035 this.perBatchItemsByName = perBatchItemsByName;
1036 this.commonItemsByName = commonItemsByName;
1040 internal bool TryGetEvaluatedItemByNameBatched (string itemName, out BuildItemGroup group)
1042 if (perBatchItemsByName == null && commonItemsByName == null)
1043 return EvaluatedItemsByName.TryGetValue (itemName, out group);
1045 if (perBatchItemsByName != null)
1046 return perBatchItemsByName.TryGetValue (itemName, out group);
1048 if (commonItemsByName != null)
1049 return commonItemsByName.TryGetValue (itemName, out group);
1055 internal string GetMetadataBatched (string itemName, string metadataName)
1057 BuildItemGroup group = null;
1058 if (itemName == null) {
1059 //unqualified, all items in a batch(bucket) have the
1060 //same metadata values
1061 group = GetFirst<BuildItemGroup> (perBatchItemsByName.Values);
1063 group = GetFirst<BuildItemGroup> (commonItemsByName.Values);
1066 TryGetEvaluatedItemByNameBatched (itemName, out group);
1069 if (group != null) {
1070 foreach (BuildItem item in group) {
1071 if (item.HasMetadata (metadataName))
1072 return item.GetEvaluatedMetadata (metadataName);
1075 return String.Empty;
1078 internal IEnumerable<BuildItemGroup> GetAllItemGroups ()
1080 if (perBatchItemsByName == null && commonItemsByName == null)
1081 foreach (BuildItemGroup group in EvaluatedItemsByName.Values)
1084 if (perBatchItemsByName != null)
1085 foreach (BuildItemGroup group in perBatchItemsByName.Values)
1088 if (commonItemsByName != null)
1089 foreach (BuildItemGroup group in commonItemsByName.Values)
1093 T GetFirst<T> (ICollection<T> list)
1098 foreach (T t in list)
1104 void LogWarning (string filename, string message, params object[] messageArgs)
1106 BuildWarningEventArgs bwea = new BuildWarningEventArgs (
1107 null, null, filename, 0, 0, 0, 0, String.Format (message, messageArgs),
1109 ParentEngine.EventSource.FireWarningRaised (this, bwea);
1112 static string ExtensionsPath {
1114 if (extensions_path == null) {
1115 // NOTE: code from mcs/tools/gacutil/driver.cs
1116 PropertyInfo gac = typeof (System.Environment).GetProperty (
1117 "GacPath", BindingFlags.Static | BindingFlags.NonPublic);
1120 MethodInfo get_gac = gac.GetGetMethod (true);
1121 string gac_path = (string) get_gac.Invoke (null, null);
1122 extensions_path = Path.GetFullPath (Path.Combine (
1123 gac_path, Path.Combine ("..", "xbuild")));
1126 return extensions_path;
1130 public BuildPropertyGroup EvaluatedProperties {
1132 if (needToReevaluate) {
1133 needToReevaluate = false;
1136 return evaluatedProperties;
1140 public string FullFileName {
1141 get { return fullFileName; }
1142 set { fullFileName = value; }
1145 public BuildPropertyGroup GlobalProperties {
1146 get { return globalProperties; }
1149 throw new ArgumentNullException ("value");
1152 throw new InvalidOperationException ("GlobalProperties can not be set to persisted property group.");
1154 globalProperties = value;
1155 NeedToReevaluate ();
1159 public bool IsDirty {
1160 get { return isDirty; }
1163 public bool IsValidated {
1164 get { return isValidated; }
1165 set { isValidated = value; }
1168 public BuildItemGroupCollection ItemGroups {
1169 get { return itemGroups; }
1172 public ImportCollection Imports {
1173 get { return imports; }
1176 public string InitialTargets {
1178 return xmlDocument.DocumentElement.GetAttribute ("InitialTargets");
1181 xmlDocument.DocumentElement.SetAttribute ("InitialTargets", value);
1182 initialTargets = value.Split (new char [] {';'}, StringSplitOptions.RemoveEmptyEntries);
1186 public Engine ParentEngine {
1187 get { return parentEngine; }
1190 public BuildPropertyGroupCollection PropertyGroups {
1191 get { return propertyGroups; }
1194 public string SchemaFile {
1195 get { return schemaFile; }
1196 set { schemaFile = value; }
1199 public TargetCollection Targets {
1200 get { return targets; }
1203 public DateTime TimeOfLastDirty {
1204 get { return timeOfLastDirty; }
1207 public UsingTaskCollection UsingTasks {
1208 get { return usingTasks; }
1213 get { return xmlDocument.InnerXml; }
1216 internal List<string> BuiltTargetKeys {
1217 get { return builtTargetKeys; }
1220 internal Dictionary <string, BuildItemGroup> LastItemGroupContaining {
1221 get { return last_item_group_containing; }
1224 internal static XmlNamespaceManager XmlNamespaceManager {
1226 if (manager == null) {
1227 manager = new XmlNamespaceManager (new NameTable ());
1228 manager.AddNamespace ("tns", ns);
1235 internal TaskDatabase TaskDatabase {
1236 get { return taskDatabase; }
1239 internal XmlDocument XmlDocument {
1240 get { return xmlDocument; }
1243 internal static string XmlNamespace {