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;
37 using System.Xml.Schema;
38 using Microsoft.Build.Framework;
39 using Mono.XBuild.Framework;
41 namespace Microsoft.Build.BuildEngine {
42 public class Project {
45 //IDictionary conditionedProperties;
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 groups;
60 BuildItemGroupCollection itemGroups;
61 ImportCollection imports;
62 string initialTargets;
64 BuildPropertyGroupCollection propertyGroups;
66 TaskDatabase taskDatabase;
67 TargetCollection targets;
68 DateTime timeOfLastDirty;
69 UsingTaskCollection usingTasks;
70 XmlDocument xmlDocument;
74 : this (Engine.GlobalEngine)
78 public Project (Engine engine)
80 parentEngine = engine;
81 xmlDocument = new XmlDocument ();
82 groups = new GroupingCollection ();
83 imports = new ImportCollection (this);
84 usingTasks = new UsingTaskCollection (this);
85 itemGroups = new BuildItemGroupCollection (groups);
86 propertyGroups = new BuildPropertyGroupCollection (groups);
87 targets = new TargetCollection (this);
89 taskDatabase = new TaskDatabase ();
90 if (engine.DefaultTasksRegistered == true)
91 taskDatabase.CopyTasks (engine.DefaultTasks);
93 globalProperties = new BuildPropertyGroup ();
94 fullFileName = String.Empty;
96 foreach (BuildProperty bp in parentEngine.GlobalProperties) {
97 GlobalProperties.AddProperty (bp.Clone (true));
100 // You can evaluate an empty project.
105 public void AddNewImport (string importLocation,
106 string importCondition)
108 throw new NotImplementedException ();
112 public BuildItem AddNewItem (string itemName,
115 return AddNewItem (itemName, itemInclude, false);
119 public BuildItem AddNewItem (string itemName,
121 bool treatItemIncludeAsLiteral)
123 throw new NotImplementedException ();
127 public BuildItemGroup AddNewItemGroup ()
129 throw new NotImplementedException ();
133 public BuildPropertyGroup AddNewPropertyGroup (bool insertAtEndOfProject)
135 throw new NotImplementedException ();
139 public void AddNewUsingTaskFromAssemblyFile (string taskName,
142 throw new NotImplementedException ();
146 public void AddNewUsingTaskFromAssemblyName (string taskName,
149 throw new NotImplementedException ();
159 public bool Build (string targetName)
161 if (targets.Exists (targetName) == false)
162 throw new Exception ("Target specified to build does not exist.");
164 return this.targets [targetName].Build ();
168 public bool Build (string[] targetNames)
170 return Build (targetNames, new Hashtable ());
174 public bool Build (string[] targetNames,
175 IDictionary targetOutputs)
177 return Build (targetNames, new Hashtable (), BuildSettings.None);
181 public bool Build (string[] targetNames,
182 IDictionary targetOutputs,
183 BuildSettings buildFlags)
187 if (targetNames.Length == 0) {
188 if (defaultTargets.Length != 0) {
189 targetNames = defaultTargets;
191 else if (firstTargetName != null) {
192 targetNames = new string [1] { firstTargetName};
197 foreach (string target in targetNames) {
198 if (Build (target) == false) {
206 public string[] GetConditionedPropertyValues (string propertyName)
208 if (conditionedProperties.ContainsKey (propertyName))
209 return conditionedProperties [propertyName].ToArray ();
211 return new string [0];
214 public BuildItemGroup GetEvaluatedItemsByName (string itemName)
216 if (evaluatedItemsByName.ContainsKey (itemName))
217 return evaluatedItemsByName [itemName];
222 public BuildItemGroup GetEvaluatedItemsByNameIgnoringCondition (string itemName)
224 if (evaluatedItemsByNameIgnoringCondition.ContainsKey (itemName))
225 return evaluatedItemsByNameIgnoringCondition [itemName];
230 public string GetEvaluatedProperty (string propertyName)
232 return (string) evaluatedProperties [propertyName];
236 public string GetProjectExtensions (string id)
238 throw new NotImplementedException ();
241 // Does the actual loading.
242 private void DoLoad (TextReader textReader)
244 ParentEngine.RemoveLoadedProject (this);
246 XmlReaderSettings settings = new XmlReaderSettings ();
248 if (SchemaFile != null) {
249 settings.Schemas.Add (null, SchemaFile);
250 settings.ValidationType = ValidationType.Schema;
251 settings.ValidationEventHandler += new ValidationEventHandler (ValidationCallBack);
254 XmlReader xmlReader = XmlReader.Create (textReader, settings);
255 xmlDocument.Load (xmlReader);
257 if (xmlDocument.DocumentElement.GetAttribute ("xmlns") != "http://schemas.microsoft.com/developer/msbuild/2003") {
258 throw new InvalidProjectFileException (
259 @"The default XML namespace of the project must be the MSBuild XML namespace." +
260 " If the project is authored in the MSBuild 2003 format, please add " +
261 "xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\" to the <Project> element. " +
262 "If the project has been authored in the old 1.0 or 1.2 format, please convert it to MSBuild 2003 format. ");
265 ParentEngine.AddLoadedProject (this);
268 public void Load (string projectFileName)
270 this.fullFileName = Path.GetFullPath (projectFileName);
271 DoLoad (new StreamReader (projectFileName));
275 public void Load (TextReader textReader)
277 fullFileName = String.Empty;
281 public void LoadXml (string projectXml)
283 fullFileName = String.Empty;
284 DoLoad (new StringReader (projectXml));
287 internal void Unload ()
292 internal void CheckUnloaded ()
295 throw new InvalidOperationException ("This project object is no longer valid.");
298 private void ProcessXml ()
300 XmlElement xmlElement = xmlDocument.DocumentElement;
301 if (xmlElement.Name != "Project")
302 throw new InvalidProjectFileException ("Invalid root element.");
303 if (xmlElement.GetAttributeNode ("DefaultTargets") != null)
304 defaultTargets = xmlElement.GetAttribute ("DefaultTargets").Split (';');
306 defaultTargets = new string [0];
308 ProcessElements (xmlElement, null);
314 private void InitializeProperties ()
318 foreach (BuildProperty gp in GlobalProperties) {
319 bp = new BuildProperty (gp.Name, gp.Value, PropertyType.Global);
320 EvaluatedProperties.AddProperty (bp);
323 foreach (DictionaryEntry de in Environment.GetEnvironmentVariables ()) {
324 bp = new BuildProperty ((string) de.Key, (string) de.Value, PropertyType.Environment);
325 EvaluatedProperties.AddProperty (bp);
328 bp = new BuildProperty ("MSBuildBinPath", parentEngine.BinPath, PropertyType.Reserved);
329 EvaluatedProperties.AddProperty (bp);
332 internal void Evaluate ()
334 evaluatedItems = new BuildItemGroup (null, this);
335 evaluatedItemsIgnoringCondition = new BuildItemGroup (null, this);
336 evaluatedItemsByName = new Dictionary <string, BuildItemGroup> (StringComparer.InvariantCultureIgnoreCase);
337 evaluatedItemsByNameIgnoringCondition = new Dictionary <string, BuildItemGroup> (StringComparer.InvariantCultureIgnoreCase);
338 evaluatedProperties = new BuildPropertyGroup ();
340 InitializeProperties ();
342 // FIXME: questionable order of evaluation
344 foreach (Import import in Imports)
347 foreach (BuildPropertyGroup bpg in PropertyGroups) {
348 if (bpg.Condition == String.Empty)
351 ConditionExpression ce = ConditionParser.ParseCondition (bpg.Condition);
352 if (ce.BoolEvaluate (this))
357 foreach (BuildItemGroup big in ItemGroups) {
358 if (big.Condition == String.Empty)
361 ConditionExpression ce = ConditionParser.ParseCondition (big.Condition);
362 if (ce.BoolEvaluate (this))
367 foreach (UsingTask usingTask in UsingTasks)
368 usingTask.Evaluate ();
371 public void MarkProjectAsDirty ()
377 public void RemoveAllItemGroups ()
379 throw new NotImplementedException ();
383 public void RemoveAllPropertyGroups ()
385 throw new NotImplementedException ();
389 public void RemoveItem (BuildItem itemToRemove)
391 throw new NotImplementedException ();
395 public void RemoveItemGroup (BuildItemGroup itemGroupToRemove)
397 throw new NotImplementedException ();
401 // NOTE: does not modify imported projects
402 public void RemoveItemGroupsWithMatchingCondition (string matchingCondition)
404 throw new NotImplementedException ();
408 public void RemoveItemsByName (string itemName)
410 throw new NotImplementedException ();
414 public void RemovePropertyGroup (BuildPropertyGroup propertyGroupToRemove)
416 throw new NotImplementedException ();
420 // NOTE: does not modify imported projects
421 public void RemovePropertyGroupsWithMatchingCondition (string matchCondition)
423 throw new NotImplementedException ();
427 public void ResetBuildStatus ()
429 throw new NotImplementedException ();
432 public void Save (string projectFileName)
434 Save (projectFileName, Encoding.Default);
437 public void Save (string projectFileName, Encoding encoding)
439 xmlDocument.Save (projectFileName);
442 public void Save (TextWriter outTextWriter)
444 xmlDocument.Save (outTextWriter);
448 public void SetImportedProperty (string propertyName,
449 string propertyValue,
451 Project importProject)
453 SetImportedProperty (propertyName, propertyValue, condition, importProject,
454 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup);
458 public void SetImportedProperty (string propertyName,
459 string propertyValue,
461 Project importedProject,
462 PropertyPosition position)
464 SetImportedProperty (propertyName, propertyValue, condition, importedProject,
465 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
469 public void SetImportedProperty (string propertyName,
470 string propertyValue,
472 Project importedProject,
473 PropertyPosition position,
474 bool treatPropertyValueAsLiteral)
476 throw new NotImplementedException ();
480 public void SetProjectExtensions (string id, string xmlText)
482 throw new NotImplementedException ();
486 public void SetProperty (string propertyName,
487 string propertyValue)
489 SetProperty (propertyName, propertyValue, "true",
490 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
494 public void SetProperty (string propertyName,
495 string propertyValue,
498 SetProperty (propertyName, propertyValue, condition,
499 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup);
503 public void SetProperty (string propertyName,
504 string propertyValue,
506 PropertyPosition position)
508 SetProperty (propertyName, propertyValue, condition,
509 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
513 public void SetProperty (string propertyName,
514 string propertyValue,
516 PropertyPosition position,
517 bool treatPropertyValueAsLiteral)
519 throw new NotImplementedException ();
522 internal void ProcessElements (XmlElement rootElement, ImportedProject ip)
524 foreach (XmlNode xn in rootElement.ChildNodes) {
525 if (xn is XmlElement) {
526 XmlElement xe = (XmlElement) xn;
528 case "ProjectExtensions":
529 AddProjectExtensions (xe);
540 AddUsingTask (xe, ip);
548 case "PropertyGroup":
549 AddPropertyGroup (xe);
555 throw new InvalidProjectFileException ("Invalid element in project file.");
561 private void AddProjectExtensions (XmlElement xmlElement)
563 if (xmlElement == null)
564 throw new ArgumentNullException ("xmlElement");
567 private void AddMessage (XmlElement xmlElement)
569 if (xmlElement == null)
570 throw new ArgumentNullException ("xmlElement");
573 private void AddTarget (XmlElement xmlElement, ImportedProject importedProject)
575 if (xmlElement == null)
576 throw new ArgumentNullException ("xmlElement");
577 Target target = new Target (xmlElement, this);
578 targets.AddTarget (target);
579 if (importedProject == null) {
580 target.IsImported = false;
581 if (firstTargetName == null)
582 firstTargetName = target.Name;
584 target.IsImported = true;
587 private void AddUsingTask (XmlElement xmlElement, ImportedProject importedProject)
591 usingTask = new UsingTask (xmlElement, this, importedProject);
592 UsingTasks.Add (usingTask);
595 private void AddImport (XmlElement xmlElement, ImportedProject importingProject)
599 import = new Import (xmlElement, this, importingProject);
600 Imports.Add (import);
603 private void AddItemGroup (XmlElement xmlElement)
605 if (xmlElement == null)
606 throw new ArgumentNullException ("xmlElement");
607 BuildItemGroup big = new BuildItemGroup (xmlElement, this);
608 ItemGroups.Add (big);
612 private void AddPropertyGroup (XmlElement xmlElement)
614 if (xmlElement == null)
615 throw new ArgumentNullException ("xmlElement");
616 BuildPropertyGroup bpg = new BuildPropertyGroup (xmlElement, this);
617 PropertyGroups.Add (bpg);
621 private void AddChoose (XmlElement xmlElement)
623 if (xmlElement == null)
624 throw new ArgumentNullException ("xmlElement");
626 BuildChoose bc = new BuildChoose (xmlElement, this);
631 private static void ValidationCallBack (object sender, ValidationEventArgs e)
633 Console.WriteLine ("Validation Error: {0}", e.Message);
636 public bool BuildEnabled {
641 buildEnabled = value;
645 public Encoding Encoding {
646 get { return encoding; }
649 public string DefaultTargets {
651 return xmlDocument.DocumentElement.GetAttribute ("DefaultTargets");
654 xmlDocument.DocumentElement.SetAttribute ("DefaultTargets", value);
655 defaultTargets = value.Split (';');
659 public BuildItemGroup EvaluatedItems {
660 get { return evaluatedItems; }
663 public BuildItemGroup EvaluatedItemsIgnoringCondition {
664 get { return evaluatedItemsIgnoringCondition; }
667 internal IDictionary EvaluatedItemsByName {
668 get { return evaluatedItemsByName; }
671 internal IDictionary EvaluatedItemsByNameIgnoringCondition {
672 get { return evaluatedItemsByNameIgnoringCondition; }
675 public BuildPropertyGroup EvaluatedProperties {
676 get { return evaluatedProperties; }
679 public string FullFileName {
680 get { return fullFileName; }
681 set { fullFileName = value; }
684 public BuildPropertyGroup GlobalProperties {
685 get { return globalProperties; }
688 throw new ArgumentNullException ("value");
691 throw new InvalidOperationException ("Can't do that.");
693 globalProperties = value;
697 public bool IsDirty {
698 get { return isDirty; }
701 public bool IsValidated {
702 get { return isValidated; }
703 set { isValidated = value; }
706 public BuildItemGroupCollection ItemGroups {
707 get { return itemGroups; }
710 public ImportCollection Imports {
711 get { return imports; }
714 public string InitialTargets {
715 get { return initialTargets; }
716 set { initialTargets = value; }
719 public Engine ParentEngine {
720 get { return parentEngine; }
723 public BuildPropertyGroupCollection PropertyGroups {
724 get { return propertyGroups; }
727 public string SchemaFile {
728 get { return schemaFile; }
729 set { schemaFile = value; }
732 public TargetCollection Targets {
733 get { return targets; }
736 public DateTime TimeOfLastDirty {
737 get { return timeOfLastDirty; }
740 public UsingTaskCollection UsingTasks {
741 get { return usingTasks; }
746 get { return xmlDocument.InnerXml; }
749 internal TaskDatabase TaskDatabase {
750 get { return taskDatabase; }