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 : IProject {
42 static string separator = ";";
45 IDictionary conditionedProperties;
46 Encoding currentEncoding;
47 string[] defaultTargets;
48 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 throw new NotImplementedException ();
112 public BuildItemGroup AddNewItemGroup ()
114 throw new NotImplementedException ();
118 public BuildPropertyGroup AddNewPropertyGroup (bool insertAtEndOfProject)
120 throw new NotImplementedException ();
123 public bool Build (string[] targetNamesToBuild,
124 IDictionary targetOutputs)
126 if (targetNamesToBuild.Length == 0) {
127 if (defaultTargets.Length != 0) {
128 targetNamesToBuild = defaultTargets;
130 else if (firstTargetName != null) {
131 targetNamesToBuild = new string [1] { firstTargetName};
136 foreach (string target in targetNamesToBuild) {
137 if (BuildTarget (target, targetOutputs) == false) {
144 public bool BuildTarget (string targetName,
145 IDictionary targetOutputs)
147 return BuildTargetWithFlags (targetName, targetOutputs, BuildSettings.None);
150 public bool BuildTargetWithFlags (string targetName,
151 IDictionary targetOutputs,
152 BuildSettings buildFlags)
154 if (targets.Exists (targetName) == false)
155 throw new Exception ("Target specified to build does not exist.");
157 this.targets [targetName].Build ();
161 public string[] GetConditionedPropertyValues (string propertyName)
163 StringCollection sc = (StringCollection) conditionedProperties [propertyName];
164 string[] propertyValues = new string [sc.Count];
166 foreach (string propertyValue in sc)
167 propertyValues [i++] = propertyValue;
168 return propertyValues;
171 public string[] GetDirectlyImportedProjects ()
173 string[] dip = new string [directlyImportedProjects.Count];
175 foreach (string importedProject in directlyImportedProjects)
176 dip [i++] = importedProject;
180 public BuildItemGroup GetEvaluatedItemsByName (string itemName)
182 return (BuildItemGroup) evaluatedItemsByName [itemName];
185 public BuildItemGroup GetEvaluatedItemsByNameIgnoringCondition (string itemName)
187 return (BuildItemGroup) evaluatedItemsByNameIgnoringCondition [itemName];
190 public string GetEvaluatedProperty (string propertyName)
192 return evaluatedProperties [propertyName];
196 public string[] GetNonImportedItemNames ()
198 throw new NotImplementedException ();
202 public string[] GetNonImportedPropertyNames ()
204 throw new NotImplementedException ();
207 public string[] GetNonImportedTargetNames ()
209 ArrayList temporaryNonImportedTargets = new ArrayList ();
210 foreach (Target target in targets)
211 if (target.IsImported == false)
212 temporaryNonImportedTargets.Add (target);
213 string[] nonImportedTargetNames = new string [temporaryNonImportedTargets.Count];
215 foreach (Target target in temporaryNonImportedTargets)
216 nonImportedTargetNames [i++] = target.Name;
217 return nonImportedTargetNames;
221 public string[] GetNonImportedUsingTasks ()
223 throw new NotImplementedException ();
227 public string GetProjectExtensions (string id)
229 throw new NotImplementedException ();
232 public void LoadFromFile (string projectFileName)
234 this.fullFileName = Path.GetFullPath (projectFileName);
235 XmlSchemaCollection xmlSchemaCollection = null;
236 XmlTextReader xmlTextReader = null;
237 XmlValidatingReader xmlValidatingReader = null;
239 if (this.schemaFile != null) {
240 xmlSchemaCollection = new XmlSchemaCollection ();
241 xmlSchemaCollection.ValidationEventHandler += new ValidationEventHandler (ValidationCallBack);
242 xmlSchemaCollection.Add (null, this.schemaFile);
243 if (xmlSchemaCollection.Count > 0) {
244 xmlTextReader = new XmlTextReader (projectFileName);
245 xmlValidatingReader = new XmlValidatingReader (xmlTextReader);
246 xmlValidatingReader.ValidationType = ValidationType.Schema;
247 xmlValidatingReader.Schemas.Add (xmlSchemaCollection);
248 xmlValidatingReader.ValidationEventHandler += new ValidationEventHandler (ValidationCallBack);
251 xmlTextReader = new XmlTextReader (projectFileName);
253 if (xmlValidatingReader != null)
254 xmlDocument.Load (xmlValidatingReader);
255 else if (xmlTextReader != null)
256 xmlDocument.Load (xmlTextReader);
258 throw new Exception ();
259 xmlElement = xmlDocument.DocumentElement;
260 if (xmlElement.Name != "Project")
261 throw new InvalidProjectFileException ("Invalid root element.");
262 if (xmlElement.GetAttributeNode ("DefaultTargets") != null)
263 defaultTargets = xmlElement.GetAttribute ("DefaultTargets").Split (';');
265 defaultTargets = new string [0];
267 ProcessElements (xmlElement, null);
272 public void LoadFromXml (XmlDocument projectXml)
275 xmlDocument = projectXml;
276 xmlElement = xmlDocument.DocumentElement;
277 if (xmlElement.Name != "Project")
278 throw new InvalidProjectFileException ("Invalid root element.");
279 if (xmlElement.GetAttributeNode ("DefaultTargets") != null)
280 defaultTargets = xmlElement.GetAttribute ("DefaultTargets").Split (';');
282 defaultTargets = new string [0];
284 ProcessElements (xmlElement, null);
289 public void MarkProjectAsDirty ()
295 public void RemoveAllItemGroups ()
297 throw new NotImplementedException ();
301 public void RemoveAllItemsGroupsByCondition (string condition)
303 throw new NotImplementedException ();
307 public void RemoveAllPropertyGroups ()
309 throw new NotImplementedException ();
313 public void RemoveAllPropertyGroupsByCondition (string condition)
315 throw new NotImplementedException ();
319 public void RemoveItem (BuildItem itemToRemove)
321 throw new NotImplementedException ();
325 public void RemoveItemGroup (BuildItemGroup itemGroupToRemove)
327 throw new NotImplementedException ();
331 public void RemoveItemsByName (string itemName)
333 throw new NotImplementedException ();
337 public void RemovePropertyGroup (BuildPropertyGroup propertyGroupToRemove)
339 throw new NotImplementedException ();
343 public void ResetBuildStatus ()
345 throw new NotImplementedException ();
348 public void SaveToFile (string projectFileName)
350 xmlDocument.Save (projectFileName);
353 public void SaveToFile (string projectFileName,
354 ProjectFileEncoding encoding)
356 SaveToFile (projectFileName);
359 public void SaveToTextWriter (TextWriter outTextWriter)
361 xmlDocument.Save (outTextWriter);
365 public void SetImportedProperty (string propertyName,
366 string propertyValue,
368 Project importProject)
370 throw new NotImplementedException ();
374 public void SetImportedPropertyAt (string propertyName,
375 string propertyValue,
377 Project importedProject,
378 PropertyPosition position)
380 throw new NotImplementedException ();
384 public void SetProjectExtensions (string id, string xmlText)
386 throw new NotImplementedException ();
390 public void SetProperty (string propertyName,
391 string propertyValue,
394 throw new NotImplementedException ();
398 public void SetPropertyAt (string propertyName,
399 string propertyValue,
401 PropertyPosition position)
403 throw new NotImplementedException ();
407 public void Unload ()
409 throw new NotImplementedException ();
412 private void ProcessElements (XmlElement rootElement, ImportedProject ip)
414 foreach (XmlNode xn in rootElement.ChildNodes) {
415 if (xn is XmlElement) {
416 XmlElement xe = (XmlElement) xn;
418 case "ProjectExtensions":
419 AddProjectExtensions (xe);
430 AddUsingTask (xe, ip);
438 case "PropertyGroup":
439 AddPropertyGroup (xe);
445 throw new InvalidProjectFileException ("Invalid element in project file.");
451 private void AddProjectExtensions (XmlElement xmlElement)
453 if (xmlElement == null)
454 throw new ArgumentNullException ("xmlElement");
457 private void AddMessage (XmlElement xmlElement)
459 if (xmlElement == null)
460 throw new ArgumentNullException ("xmlElement");
463 private void AddTarget (XmlElement xmlElement, ImportedProject importedProject)
465 if (xmlElement == null)
466 throw new ArgumentNullException ("xmlElement");
467 Target target = targets.AddNewTarget (xmlElement.GetAttribute ("Name"));
468 target.BindToXml (xmlElement);
469 if (importedProject == null) {
470 target.IsImported = false;
471 if (firstTargetName == null)
472 firstTargetName = target.Name;
474 target.IsImported = true;
477 private void AddUsingTask (XmlElement xmlElement, ImportedProject importedProject)
479 if (xmlElement == null)
480 throw new ArgumentNullException ("xmlElement");
482 if (xmlElement.GetAttribute ("TaskName") == String.Empty)
483 throw new InvalidProjectFileException ("TaskName attribute must be specified.");
485 usingTaskElements.Add (xmlElement);
487 AssemblyLoadInfo loadInfo = null;
488 string filename = null;
490 string taskName = xmlElement.GetAttribute ("TaskName");
492 if (xmlElement.GetAttribute ("AssemblyName") != String.Empty) {
493 name = xmlElement.GetAttribute ("AssemblyName");
494 loadInfo = new AssemblyLoadInfo (name, taskName);
495 taskDatabase.RegisterTask (taskName, loadInfo);
496 } else if (xmlElement.GetAttribute ("AssemblyFile") != String.Empty) {
497 filename = xmlElement.GetAttribute ("AssemblyFile");
498 if (Path.IsPathRooted (filename) == false) {
499 if (importedProject == null)
500 filename = Path.Combine (Path.GetDirectoryName (fullFileName), filename);
502 filename = Path.Combine (Path.GetDirectoryName (importedProject.FullFileName), filename);
504 loadInfo = new AssemblyLoadInfo (LoadInfoType.AssemblyFilename, filename, null, null, null, null, taskName);
505 taskDatabase.RegisterTask (taskName, loadInfo);
507 throw new InvalidProjectFileException ("AssemblyName or AssemblyFile attribute must be specified.");
510 private void AddImport (XmlElement xmlElement, ImportedProject importingProject)
512 if (xmlElement == null)
513 throw new ArgumentNullException ("xmlElement");
516 Expression importedFileExpr;
517 ImportedProject ImportedProject;
519 importedFileExpr = new Expression (this, xmlElement.GetAttribute ("Project"));
520 importedFile = (string) importedFileExpr.ToNonArray (typeof (string));
522 if (importedFile == String.Empty)
523 throw new InvalidProjectFileException ("Project attribute must be specified.");
525 if (Path.IsPathRooted (importedFile) == false) {
526 if (importingProject == null)
527 importedFile = Path.Combine (Path.GetDirectoryName (fullFileName), importedFile);
529 importedFile = Path.Combine (Path.GetDirectoryName (importingProject.FullFileName), importedFile);
532 ImportedProject importedProject = new ImportedProject ();
534 importedProject.Load (importedFile);
535 ProcessElements (importedProject.XmlDocument.DocumentElement, importedProject);
537 catch (Exception ex) {
538 Console.WriteLine (ex);
542 private void AddItemGroup (XmlElement xmlElement)
544 if (xmlElement == null)
545 throw new ArgumentNullException ("xmlElement");
546 BuildItemGroup big = new BuildItemGroup (this);
547 big.BindToXml (xmlElement);
548 itemGroups.Add (big);
551 private void AddPropertyGroup (XmlElement xmlElement)
553 if (xmlElement == null)
554 throw new ArgumentNullException ("xmlElement");
555 BuildPropertyGroup bpg = new BuildPropertyGroup (true, this);
556 bpg.BindToXml (xmlElement);
557 propertyGroups.Add (bpg);
560 private void AddChoose (XmlElement xmlElement)
562 if (xmlElement == null)
563 throw new ArgumentNullException ("xmlElement");
566 private static void ValidationCallBack (object sender, ValidationEventArgs e)
568 Console.WriteLine ("Validation Error: {0}", e.Message);
571 public bool BuildEnabled {
576 buildEnabled = value;
580 public ProjectFileEncoding CurrentProjectFileEncoding {
582 if (currentEncoding == Encoding.UTF8)
583 return ProjectFileEncoding.Utf8;
584 if (currentEncoding == Encoding.Unicode)
585 return ProjectFileEncoding.Unicode;
586 if (currentEncoding == Encoding.GetEncoding ("ANSI"))
587 return ProjectFileEncoding.Ansi;
588 throw new Exception ();
592 public string DefaultTargets {
593 get { return xmlElement.GetAttribute ("DefaultTargets"); }
595 xmlElement.SetAttribute ("DefaultTargets",value);
596 defaultTargets = value.Split (';');
600 public BuildItemGroup EvaluatedItems {
601 get { return evaluatedItems; }
604 public BuildItemGroup EvaluatedItemsIgnoringCondition {
605 get { return evaluatedItemsIgnoringCondition; }
608 internal IDictionary EvaluatedItemsByName {
609 get { return evaluatedItemsByName; }
612 internal IDictionary EvaluatedItemsByNameIgnoringCondition {
613 get { return evaluatedItemsByNameIgnoringCondition; }
616 public BuildPropertyGroup EvaluatedProperties {
617 get { return evaluatedProperties; }
620 public string FullFileName {
621 get { return fullFileName; }
622 set { fullFileName = value; }
625 public BuildPropertyGroup GlobalProperties {
626 get { return globalProperties; }
628 globalProperties = value;
629 foreach (BuildProperty bp in globalProperties)
630 evaluatedProperties.AddFromExistingProperty (bp);
634 public bool IsDirty {
635 get { return isDirty; }
638 public bool IsValidated {
639 get { return isValidated; }
640 set { isValidated = value; }
643 public BuildItemGroupCollection ItemGroups {
644 get { return itemGroups; }
647 public Engine ParentEngine {
648 get { return parentEngine; }
651 public BuildPropertyGroupCollection PropertyGroups {
652 get { return propertyGroups; }
655 public string SchemaFile {
656 get { return schemaFile; }
657 set { schemaFile = value; }
660 public TargetCollection Targets {
661 get { return targets; }
664 public DateTime TimeOfLastDirty {
665 get { return timeOfLastDirty; }
668 public XmlDocument Xml {
669 get { return xmlDocument; }
672 internal TaskDatabase TaskDatabase {
673 get { return taskDatabase; }
676 internal BuildPropertyGroup EnvironmentProperties {
678 environmentProperties = value;
679 foreach (BuildProperty bp in environmentProperties)
680 evaluatedProperties.AddFromExistingProperty (bp);
684 internal BuildPropertyGroup ReservedProperties {
686 reservedProperties = value;
687 foreach (BuildProperty bp in reservedProperties)
688 evaluatedProperties.AddFromExistingProperty (bp);