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.Specialized;
36 using System.Xml.Schema;
37 using Microsoft.Build.Framework;
38 using Mono.XBuild.Framework;
40 namespace Microsoft.Build.BuildEngine {
41 public class Project {
42 static string separator = ";";
45 IDictionary conditionedProperties;
46 string[] defaultTargets;
47 IList directlyImportedProjects;
49 BuildPropertyGroup environmentProperties;
50 BuildItemGroup evaluatedItems;
51 BuildItemGroup evaluatedItemsIgnoringCondition;
52 IDictionary evaluatedItemsByName;
53 IDictionary evaluatedItemsByNameIgnoringCondition;
54 BuildPropertyGroup evaluatedProperties;
55 string firstTargetName;
57 BuildPropertyGroup globalProperties;
58 GroupingCollection groups;
62 BuildItemGroupCollection itemGroups;
63 IDictionary importedProjects;
65 BuildPropertyGroupCollection propertyGroups;
66 BuildPropertyGroup reservedProperties;
68 TaskDatabase taskDatabase;
69 TargetCollection targets;
70 DateTime timeOfLastDirty;
71 IList usingTaskElements;
72 XmlDocument xmlDocument;
73 XmlElement xmlElement;
80 public Project (Engine engine)
82 parentEngine = engine;
83 xmlDocument = new XmlDocument ();
84 evaluatedItems = new BuildItemGroup (this);
85 evaluatedItemsByName = CollectionsUtil.CreateCaseInsensitiveHashtable ();
86 evaluatedItemsByNameIgnoringCondition = CollectionsUtil.CreateCaseInsensitiveHashtable ();
87 evaluatedItemsIgnoringCondition = new BuildItemGroup (this);
88 evaluatedProperties = new BuildPropertyGroup (false, null);
89 groups = new GroupingCollection ();
90 itemGroups = new BuildItemGroupCollection (groups);
91 propertyGroups = new BuildPropertyGroupCollection (groups);
92 targets = new TargetCollection (this);
93 usingTaskElements = new ArrayList ();
94 taskDatabase = new TaskDatabase ();
98 public void AddNewImport (string importLocation,
99 string importCondition)
101 throw new NotImplementedException ();
105 public BuildItem AddNewItem (string itemName,
108 return AddNewItem (itemName, itemInclude, false);
112 public BuildItem AddNewItem (string itemName,
114 bool treatItemIncludeAsLiteral)
116 throw new NotImplementedException ();
120 public BuildItemGroup AddNewItemGroup ()
122 throw new NotImplementedException ();
126 public BuildPropertyGroup AddNewPropertyGroup (bool insertAtEndOfProject)
128 throw new NotImplementedException ();
138 public bool Build (string targetName)
140 if (targets.Exists (targetName) == false)
141 throw new Exception ("Target specified to build does not exist.");
143 this.targets [targetName].Build ();
148 public bool Build (string[] targetNames)
150 return Build (targetNames, new Hashtable ());
154 public bool Build (string[] targetNames,
155 IDictionary targetOutputs)
157 return Build (targetNames, new Hashtable (), BuildSettings.None);
161 public bool Build (string[] targetNames,
162 IDictionary targetOutputs,
163 BuildSettings buildFlags)
166 if (targetNames.Length == 0) {
167 if (defaultTargets.Length != 0) {
168 targetNames = defaultTargets;
170 else if (firstTargetName != null) {
171 targetNames = new string [1] { firstTargetName};
176 foreach (string target in targetNames) {
177 if (Build (target) == false) {
184 public string[] GetConditionedPropertyValues (string propertyName)
186 StringCollection sc = (StringCollection) conditionedProperties [propertyName];
187 string[] propertyValues = new string [sc.Count];
189 foreach (string propertyValue in sc)
190 propertyValues [i++] = propertyValue;
191 return propertyValues;
194 public BuildItemGroup GetEvaluatedItemsByName (string itemName)
196 return (BuildItemGroup) evaluatedItemsByName [itemName];
199 public BuildItemGroup GetEvaluatedItemsByNameIgnoringCondition (string itemName)
201 return (BuildItemGroup) evaluatedItemsByNameIgnoringCondition [itemName];
204 public string GetEvaluatedProperty (string propertyName)
206 return evaluatedProperties [propertyName];
210 public string GetProjectExtensions (string id)
212 throw new NotImplementedException ();
215 public void Load (string projectFileName)
217 this.fullFileName = Path.GetFullPath (projectFileName);
218 XmlSchemaCollection xmlSchemaCollection = null;
219 XmlTextReader xmlTextReader = null;
220 XmlValidatingReader xmlValidatingReader = null;
222 if (this.schemaFile != null) {
223 xmlSchemaCollection = new XmlSchemaCollection ();
224 xmlSchemaCollection.ValidationEventHandler += new ValidationEventHandler (ValidationCallBack);
225 xmlSchemaCollection.Add (null, this.schemaFile);
226 if (xmlSchemaCollection.Count > 0) {
227 xmlTextReader = new XmlTextReader (projectFileName);
228 xmlValidatingReader = new XmlValidatingReader (xmlTextReader);
229 xmlValidatingReader.ValidationType = ValidationType.Schema;
230 xmlValidatingReader.Schemas.Add (xmlSchemaCollection);
231 xmlValidatingReader.ValidationEventHandler += new ValidationEventHandler (ValidationCallBack);
234 xmlTextReader = new XmlTextReader (projectFileName);
236 if (xmlValidatingReader != null)
237 xmlDocument.Load (xmlValidatingReader);
238 else if (xmlTextReader != null)
239 xmlDocument.Load (xmlTextReader);
241 throw new Exception ();
242 xmlElement = xmlDocument.DocumentElement;
243 if (xmlElement.Name != "Project")
244 throw new InvalidProjectFileException ("Invalid root element.");
245 if (xmlElement.GetAttributeNode ("DefaultTargets") != null)
246 defaultTargets = xmlElement.GetAttribute ("DefaultTargets").Split (';');
248 defaultTargets = new string [0];
250 ProcessElements (xmlElement, null);
256 public void Load (TextWriter textWriter)
258 throw new NotImplementedException ();
261 public void LoadFromXml (XmlDocument projectXml)
264 xmlDocument = projectXml;
265 xmlElement = xmlDocument.DocumentElement;
266 if (xmlElement.Name != "Project")
267 throw new InvalidProjectFileException ("Invalid root element.");
268 if (xmlElement.GetAttributeNode ("DefaultTargets") != null)
269 defaultTargets = xmlElement.GetAttribute ("DefaultTargets").Split (';');
271 defaultTargets = new string [0];
273 ProcessElements (xmlElement, null);
278 public void MarkProjectAsDirty ()
284 public void RemoveAllItemGroups ()
286 throw new NotImplementedException ();
290 public void RemoveAllPropertyGroups ()
292 throw new NotImplementedException ();
296 public void RemoveAllPropertyGroupsByCondition (string condition)
298 throw new NotImplementedException ();
302 public void RemoveItem (BuildItem itemToRemove)
304 throw new NotImplementedException ();
308 public void RemoveItemGroup (BuildItemGroup itemGroupToRemove)
310 throw new NotImplementedException ();
314 // NOTE: does not modify imported projects
315 public void RemoveItemGroupsWithMatchingCondition (string matchingCondition)
317 throw new NotImplementedException ();
321 public void RemoveItemsByName (string itemName)
323 throw new NotImplementedException ();
327 public void RemovePropertyGroup (BuildPropertyGroup propertyGroupToRemove)
329 throw new NotImplementedException ();
333 // NOTE: does not modify imported projects
334 public void RemovePropertyGroupsWithMatchingCondition (string matchCondition)
336 throw new NotImplementedException ();
340 public void ResetBuildStatus ()
342 throw new NotImplementedException ();
345 public void Save (string projectFileName)
347 Save (projectFileName, Encoding.Default);
350 public void Save (string projectFileName, Encoding encoding)
352 xmlDocument.Save (projectFileName);
355 public void Save (TextWriter outTextWriter)
357 xmlDocument.Save (outTextWriter);
361 public void SetImportedProperty (string propertyName,
362 string propertyValue,
364 Project importProject)
366 SetImportedProperty (propertyName, propertyValue, condition, importProject,
367 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup);
371 public void SetImportedProperty (string propertyName,
372 string propertyValue,
374 Project importedProject,
375 PropertyPosition position)
377 SetImportedProperty (propertyName, propertyValue, condition, importedProject,
378 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
382 public void SetImportedProperty (string propertyName,
383 string propertyValue,
385 Project importedProject,
386 PropertyPosition position,
387 bool treatPropertyValueAsLiteral)
389 throw new NotImplementedException ();
393 public void SetProjectExtensions (string id, string xmlText)
395 throw new NotImplementedException ();
399 public void SetProperty (string propertyName,
400 string propertyValue,
403 SetProperty (propertyName, propertyValue, condition,
404 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup);
408 public void SetProperty (string propertyName,
409 string propertyValue,
411 PropertyPosition position)
413 SetProperty (propertyName, propertyValue, condition,
414 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
418 public void SetProperty (string propertyName,
419 string propertyValue,
421 PropertyPosition position,
422 bool treatPropertyValueAsLiteral)
424 throw new NotImplementedException ();
427 private void ProcessElements (XmlElement rootElement, ImportedProject ip)
429 foreach (XmlNode xn in rootElement.ChildNodes) {
430 if (xn is XmlElement) {
431 XmlElement xe = (XmlElement) xn;
433 case "ProjectExtensions":
434 AddProjectExtensions (xe);
445 AddUsingTask (xe, ip);
453 case "PropertyGroup":
454 AddPropertyGroup (xe);
460 throw new InvalidProjectFileException ("Invalid element in project file.");
466 private void AddProjectExtensions (XmlElement xmlElement)
468 if (xmlElement == null)
469 throw new ArgumentNullException ("xmlElement");
472 private void AddMessage (XmlElement xmlElement)
474 if (xmlElement == null)
475 throw new ArgumentNullException ("xmlElement");
478 private void AddTarget (XmlElement xmlElement, ImportedProject importedProject)
480 if (xmlElement == null)
481 throw new ArgumentNullException ("xmlElement");
482 Target target = targets.AddNewTarget (xmlElement.GetAttribute ("Name"));
483 target.BindToXml (xmlElement);
484 if (importedProject == null) {
485 target.IsImported = false;
486 if (firstTargetName == null)
487 firstTargetName = target.Name;
489 target.IsImported = true;
492 private void AddUsingTask (XmlElement xmlElement, ImportedProject importedProject)
494 if (xmlElement == null)
495 throw new ArgumentNullException ("xmlElement");
497 if (xmlElement.GetAttribute ("TaskName") == String.Empty)
498 throw new InvalidProjectFileException ("TaskName attribute must be specified.");
500 usingTaskElements.Add (xmlElement);
502 AssemblyLoadInfo loadInfo = null;
503 string filename = null;
505 string taskName = xmlElement.GetAttribute ("TaskName");
507 if (xmlElement.GetAttribute ("AssemblyName") != String.Empty) {
508 name = xmlElement.GetAttribute ("AssemblyName");
509 loadInfo = new AssemblyLoadInfo (name, taskName);
510 taskDatabase.RegisterTask (taskName, loadInfo);
511 } else if (xmlElement.GetAttribute ("AssemblyFile") != String.Empty) {
512 filename = xmlElement.GetAttribute ("AssemblyFile");
513 if (Path.IsPathRooted (filename) == false) {
514 if (importedProject == null)
515 filename = Path.Combine (Path.GetDirectoryName (fullFileName), filename);
517 filename = Path.Combine (Path.GetDirectoryName (importedProject.FullFileName), filename);
519 loadInfo = new AssemblyLoadInfo (LoadInfoType.AssemblyFilename, filename, null, null, null, null, taskName);
520 taskDatabase.RegisterTask (taskName, loadInfo);
522 throw new InvalidProjectFileException ("AssemblyName or AssemblyFile attribute must be specified.");
525 private void AddImport (XmlElement xmlElement, ImportedProject importingProject)
527 if (xmlElement == null)
528 throw new ArgumentNullException ("xmlElement");
531 Expression importedFileExpr;
532 ImportedProject ImportedProject;
534 importedFileExpr = new Expression (this, xmlElement.GetAttribute ("Project"));
535 importedFile = (string) importedFileExpr.ToNonArray (typeof (string));
537 if (importedFile == String.Empty)
538 throw new InvalidProjectFileException ("Project attribute must be specified.");
540 if (Path.IsPathRooted (importedFile) == false) {
541 if (importingProject == null)
542 importedFile = Path.Combine (Path.GetDirectoryName (fullFileName), importedFile);
544 importedFile = Path.Combine (Path.GetDirectoryName (importingProject.FullFileName), importedFile);
547 ImportedProject importedProject = new ImportedProject ();
549 importedProject.Load (importedFile);
550 ProcessElements (importedProject.XmlDocument.DocumentElement, importedProject);
552 catch (Exception ex) {
553 Console.WriteLine (ex);
557 private void AddItemGroup (XmlElement xmlElement)
559 if (xmlElement == null)
560 throw new ArgumentNullException ("xmlElement");
561 BuildItemGroup big = new BuildItemGroup (this);
562 big.BindToXml (xmlElement);
563 itemGroups.Add (big);
566 private void AddPropertyGroup (XmlElement xmlElement)
568 if (xmlElement == null)
569 throw new ArgumentNullException ("xmlElement");
570 BuildPropertyGroup bpg = new BuildPropertyGroup (true, this);
571 bpg.BindToXml (xmlElement);
572 propertyGroups.Add (bpg);
575 private void AddChoose (XmlElement xmlElement)
577 if (xmlElement == null)
578 throw new ArgumentNullException ("xmlElement");
581 private static void ValidationCallBack (object sender, ValidationEventArgs e)
583 Console.WriteLine ("Validation Error: {0}", e.Message);
586 public bool BuildEnabled {
591 buildEnabled = value;
595 public Encoding Encoding {
596 get { return encoding; }
599 public string DefaultTargets {
600 get { return xmlElement.GetAttribute ("DefaultTargets"); }
602 xmlElement.SetAttribute ("DefaultTargets",value);
603 defaultTargets = value.Split (';');
607 public BuildItemGroup EvaluatedItems {
608 get { return evaluatedItems; }
611 public BuildItemGroup EvaluatedItemsIgnoringCondition {
612 get { return evaluatedItemsIgnoringCondition; }
615 internal IDictionary EvaluatedItemsByName {
616 get { return evaluatedItemsByName; }
619 internal IDictionary EvaluatedItemsByNameIgnoringCondition {
620 get { return evaluatedItemsByNameIgnoringCondition; }
623 public BuildPropertyGroup EvaluatedProperties {
624 get { return evaluatedProperties; }
627 public string FullFileName {
628 get { return fullFileName; }
629 set { fullFileName = value; }
632 public BuildPropertyGroup GlobalProperties {
633 get { return globalProperties; }
635 globalProperties = value;
636 foreach (BuildProperty bp in globalProperties)
637 evaluatedProperties.AddFromExistingProperty (bp);
641 public bool IsDirty {
642 get { return isDirty; }
645 public bool IsValidated {
646 get { return isValidated; }
647 set { isValidated = value; }
650 public BuildItemGroupCollection ItemGroups {
651 get { return itemGroups; }
654 public Engine ParentEngine {
655 get { return parentEngine; }
658 public BuildPropertyGroupCollection PropertyGroups {
659 get { return propertyGroups; }
662 public string SchemaFile {
663 get { return schemaFile; }
664 set { schemaFile = value; }
667 public TargetCollection Targets {
668 get { return targets; }
671 public DateTime TimeOfLastDirty {
672 get { return timeOfLastDirty; }
677 get { return xmlDocument.InnerXml; }
680 internal TaskDatabase TaskDatabase {
681 get { return taskDatabase; }
684 internal BuildPropertyGroup EnvironmentProperties {
686 environmentProperties = value;
687 foreach (BuildProperty bp in environmentProperties)
688 evaluatedProperties.AddFromExistingProperty (bp);
692 internal BuildPropertyGroup ReservedProperties {
694 reservedProperties = value;
695 foreach (BuildProperty bp in reservedProperties)
696 evaluatedProperties.AddFromExistingProperty (bp);