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 (String.Format ("Target {0} does not exist.", targetName));
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);
272 DoLoad (new StreamReader (projectFileName));
274 Console.WriteLine ("Failure to load: {0}", projectFileName);
279 public void Load (TextReader textReader)
281 fullFileName = String.Empty;
285 public void LoadXml (string projectXml)
287 fullFileName = String.Empty;
288 DoLoad (new StringReader (projectXml));
291 internal void Unload ()
296 internal void CheckUnloaded ()
299 throw new InvalidOperationException ("This project object is no longer valid.");
302 private void ProcessXml ()
304 XmlElement xmlElement = xmlDocument.DocumentElement;
305 if (xmlElement.Name != "Project")
306 throw new InvalidProjectFileException ("Invalid root element.");
307 if (xmlElement.GetAttributeNode ("DefaultTargets") != null)
308 defaultTargets = xmlElement.GetAttribute ("DefaultTargets").Split (';');
310 defaultTargets = new string [0];
312 ProcessElements (xmlElement, null);
318 private void InitializeProperties ()
322 foreach (BuildProperty gp in GlobalProperties) {
323 bp = new BuildProperty (gp.Name, gp.Value, PropertyType.Global);
324 EvaluatedProperties.AddProperty (bp);
327 foreach (DictionaryEntry de in Environment.GetEnvironmentVariables ()) {
328 bp = new BuildProperty ((string) de.Key, (string) de.Value, PropertyType.Environment);
329 EvaluatedProperties.AddProperty (bp);
332 bp = new BuildProperty ("MSBuildBinPath", parentEngine.BinPath, PropertyType.Reserved);
333 EvaluatedProperties.AddProperty (bp);
336 internal void Evaluate ()
338 evaluatedItems = new BuildItemGroup (null, this);
339 evaluatedItemsIgnoringCondition = new BuildItemGroup (null, this);
340 evaluatedItemsByName = new Dictionary <string, BuildItemGroup> (StringComparer.InvariantCultureIgnoreCase);
341 evaluatedItemsByNameIgnoringCondition = new Dictionary <string, BuildItemGroup> (StringComparer.InvariantCultureIgnoreCase);
342 evaluatedProperties = new BuildPropertyGroup ();
344 InitializeProperties ();
346 // FIXME: questionable order of evaluation
348 foreach (Import import in Imports)
351 foreach (BuildPropertyGroup bpg in PropertyGroups) {
352 if (bpg.Condition == String.Empty)
355 ConditionExpression ce = ConditionParser.ParseCondition (bpg.Condition);
356 if (ce.BoolEvaluate (this))
361 foreach (BuildItemGroup big in ItemGroups) {
362 if (big.Condition == String.Empty)
365 ConditionExpression ce = ConditionParser.ParseCondition (big.Condition);
366 if (ce.BoolEvaluate (this))
371 foreach (UsingTask usingTask in UsingTasks)
372 usingTask.Evaluate ();
375 public void MarkProjectAsDirty ()
381 public void RemoveAllItemGroups ()
383 throw new NotImplementedException ();
387 public void RemoveAllPropertyGroups ()
389 throw new NotImplementedException ();
393 public void RemoveItem (BuildItem itemToRemove)
395 throw new NotImplementedException ();
399 public void RemoveItemGroup (BuildItemGroup itemGroupToRemove)
401 throw new NotImplementedException ();
405 // NOTE: does not modify imported projects
406 public void RemoveItemGroupsWithMatchingCondition (string matchingCondition)
408 throw new NotImplementedException ();
412 public void RemoveItemsByName (string itemName)
414 throw new NotImplementedException ();
418 public void RemovePropertyGroup (BuildPropertyGroup propertyGroupToRemove)
420 throw new NotImplementedException ();
424 // NOTE: does not modify imported projects
425 public void RemovePropertyGroupsWithMatchingCondition (string matchCondition)
427 throw new NotImplementedException ();
431 public void ResetBuildStatus ()
433 throw new NotImplementedException ();
436 public void Save (string projectFileName)
438 Save (projectFileName, Encoding.Default);
441 public void Save (string projectFileName, Encoding encoding)
443 xmlDocument.Save (projectFileName);
446 public void Save (TextWriter outTextWriter)
448 xmlDocument.Save (outTextWriter);
452 public void SetImportedProperty (string propertyName,
453 string propertyValue,
455 Project importProject)
457 SetImportedProperty (propertyName, propertyValue, condition, importProject,
458 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup);
462 public void SetImportedProperty (string propertyName,
463 string propertyValue,
465 Project importedProject,
466 PropertyPosition position)
468 SetImportedProperty (propertyName, propertyValue, condition, importedProject,
469 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
473 public void SetImportedProperty (string propertyName,
474 string propertyValue,
476 Project importedProject,
477 PropertyPosition position,
478 bool treatPropertyValueAsLiteral)
480 throw new NotImplementedException ();
484 public void SetProjectExtensions (string id, string xmlText)
486 throw new NotImplementedException ();
490 public void SetProperty (string propertyName,
491 string propertyValue)
493 SetProperty (propertyName, propertyValue, "true",
494 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
498 public void SetProperty (string propertyName,
499 string propertyValue,
502 SetProperty (propertyName, propertyValue, condition,
503 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup);
507 public void SetProperty (string propertyName,
508 string propertyValue,
510 PropertyPosition position)
512 SetProperty (propertyName, propertyValue, condition,
513 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
517 public void SetProperty (string propertyName,
518 string propertyValue,
520 PropertyPosition position,
521 bool treatPropertyValueAsLiteral)
523 throw new NotImplementedException ();
526 internal void ProcessElements (XmlElement rootElement, ImportedProject ip)
528 foreach (XmlNode xn in rootElement.ChildNodes) {
529 if (xn is XmlElement) {
530 XmlElement xe = (XmlElement) xn;
532 case "ProjectExtensions":
533 AddProjectExtensions (xe);
544 AddUsingTask (xe, ip);
552 case "PropertyGroup":
553 AddPropertyGroup (xe);
559 throw new InvalidProjectFileException ("Invalid element in project file.");
565 private void AddProjectExtensions (XmlElement xmlElement)
567 if (xmlElement == null)
568 throw new ArgumentNullException ("xmlElement");
571 private void AddMessage (XmlElement xmlElement)
573 if (xmlElement == null)
574 throw new ArgumentNullException ("xmlElement");
577 private void AddTarget (XmlElement xmlElement, ImportedProject importedProject)
579 if (xmlElement == null)
580 throw new ArgumentNullException ("xmlElement");
581 Target target = new Target (xmlElement, this);
582 targets.AddTarget (target);
583 if (importedProject == null) {
584 target.IsImported = false;
585 if (firstTargetName == null)
586 firstTargetName = target.Name;
588 target.IsImported = true;
591 private void AddUsingTask (XmlElement xmlElement, ImportedProject importedProject)
595 usingTask = new UsingTask (xmlElement, this, importedProject);
596 UsingTasks.Add (usingTask);
599 private void AddImport (XmlElement xmlElement, ImportedProject importingProject)
603 import = new Import (xmlElement, this, importingProject);
604 Imports.Add (import);
607 private void AddItemGroup (XmlElement xmlElement)
609 if (xmlElement == null)
610 throw new ArgumentNullException ("xmlElement");
611 BuildItemGroup big = new BuildItemGroup (xmlElement, this);
612 ItemGroups.Add (big);
616 private void AddPropertyGroup (XmlElement xmlElement)
618 if (xmlElement == null)
619 throw new ArgumentNullException ("xmlElement");
620 BuildPropertyGroup bpg = new BuildPropertyGroup (xmlElement, this);
621 PropertyGroups.Add (bpg);
625 private void AddChoose (XmlElement xmlElement)
627 if (xmlElement == null)
628 throw new ArgumentNullException ("xmlElement");
630 BuildChoose bc = new BuildChoose (xmlElement, this);
635 private static void ValidationCallBack (object sender, ValidationEventArgs e)
637 Console.WriteLine ("Validation Error: {0}", e.Message);
640 public bool BuildEnabled {
645 buildEnabled = value;
649 public Encoding Encoding {
650 get { return encoding; }
653 public string DefaultTargets {
655 return xmlDocument.DocumentElement.GetAttribute ("DefaultTargets");
658 xmlDocument.DocumentElement.SetAttribute ("DefaultTargets", value);
659 defaultTargets = value.Split (';');
663 public BuildItemGroup EvaluatedItems {
664 get { return evaluatedItems; }
667 public BuildItemGroup EvaluatedItemsIgnoringCondition {
668 get { return evaluatedItemsIgnoringCondition; }
671 internal IDictionary EvaluatedItemsByName {
672 get { return evaluatedItemsByName; }
675 internal IDictionary EvaluatedItemsByNameIgnoringCondition {
676 get { return evaluatedItemsByNameIgnoringCondition; }
679 public BuildPropertyGroup EvaluatedProperties {
680 get { return evaluatedProperties; }
683 public string FullFileName {
684 get { return fullFileName; }
685 set { fullFileName = value; }
688 public BuildPropertyGroup GlobalProperties {
689 get { return globalProperties; }
692 throw new ArgumentNullException ("value");
695 throw new InvalidOperationException ("Can't do that.");
697 globalProperties = value;
701 public bool IsDirty {
702 get { return isDirty; }
705 public bool IsValidated {
706 get { return isValidated; }
707 set { isValidated = value; }
710 public BuildItemGroupCollection ItemGroups {
711 get { return itemGroups; }
714 public ImportCollection Imports {
715 get { return imports; }
718 public string InitialTargets {
719 get { return initialTargets; }
720 set { initialTargets = value; }
723 public Engine ParentEngine {
724 get { return parentEngine; }
727 public BuildPropertyGroupCollection PropertyGroups {
728 get { return propertyGroups; }
731 public string SchemaFile {
732 get { return schemaFile; }
733 set { schemaFile = value; }
736 public TargetCollection Targets {
737 get { return targets; }
740 public DateTime TimeOfLastDirty {
741 get { return timeOfLastDirty; }
744 public UsingTaskCollection UsingTasks {
745 get { return usingTasks; }
750 get { return xmlDocument.InnerXml; }
753 internal TaskDatabase TaskDatabase {
754 get { return taskDatabase; }