1 // Copyright (c) Microsoft. All rights reserved. 2 // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 4 using System; 5 using System.Collections.Generic; 6 using System.Text; 7 using System.Xml; 8 9 using Microsoft.Build.BuildEngine.Shared; 10 11 namespace Microsoft.Build.BuildEngine 12 { 13 /// <summary> 14 /// This class represents a single Import element in a project file 15 /// </summary> 16 /// <owner>LukaszG</owner> 17 public class Import : IItemPropertyGrouping 18 { 19 #region Properties 20 21 private Project parentProject = null; 22 23 /// <summary> 24 /// Returns the parent MSBuild Project object. 25 /// </summary> 26 internal Project ParentProject 27 { 28 get { return this.parentProject; } 29 set { this.parentProject = value; } 30 } 31 32 private XmlElement importElement = null; 33 34 /// <summary> 35 /// Returns the source XmlElement this Import is based on. 36 /// </summary> 37 internal XmlElement ImportElement 38 { 39 get { return this.importElement; } 40 } 41 42 private bool importedFromAnotherProject; 43 44 /// <summary> 45 /// Returns true if this Import came from an imported project 46 /// </summary> 47 /// <owner>LukaszG</owner> 48 public bool IsImported 49 { 50 get { return this.importedFromAnotherProject; } 51 } 52 53 private XmlAttribute projectPathAttribute = null; 54 55 /// <summary> 56 /// Returns the original import path from the Import element 57 /// </summary> 58 /// <owner>LukaszG</owner> 59 public string ProjectPath 60 { 61 get 62 { 63 return (this.projectPathAttribute != null) ? this.projectPathAttribute.Value : null; 64 } 65 set 66 { 67 ImportElement.SetAttribute(XMakeAttributes.project, value); 68 ParentProject.MarkProjectAsDirtyForReprocessXml(); 69 } 70 } 71 72 /// <summary> 73 /// Internal accessor for the project path XML attribute 74 /// </summary> 75 /// <owner>LukaszG</owner> 76 internal XmlAttribute ProjectPathAttribute 77 { 78 get { return this.projectPathAttribute; } 79 } 80 81 private string evaluatedProjectPath = null; 82 83 /// <summary> 84 /// Returns the full evaluated import path 85 /// </summary> 86 /// <owner>LukaszG</owner> 87 public string EvaluatedProjectPath 88 { 89 get { return this.evaluatedProjectPath; } 90 } 91 92 private XmlAttribute conditionAttribute = null; 93 94 /// <summary> 95 /// The condition string for this UsingTask 96 /// </summary> 97 /// <owner>LukaszG</owner> 98 public string Condition 99 { 100 get 101 { 102 return (this.conditionAttribute != null) ? this.conditionAttribute.Value : null; 103 } 104 set 105 { 106 ImportElement.SetAttribute(XMakeAttributes.condition, value); 107 if (conditionAttribute == null) 108 { 109 conditionAttribute = ImportElement.Attributes[XMakeAttributes.condition]; 110 } 111 ParentProject.MarkProjectAsDirtyForReprocessXml(); 112 } 113 } 114 115 /// <summary> 116 /// Internal accessor for the condition XML attribute 117 /// </summary> 118 internal XmlAttribute ConditionAttribute 119 { 120 get { return this.conditionAttribute; } 121 } 122 123 #endregion 124 125 #region Constructors 126 127 /// <summary> 128 /// Internal constructor 129 /// </summary> 130 /// <param name="importElement"></param> 131 /// <param name="isImported"></param> 132 /// <owner>LukaszG</owner> Import(XmlElement importElement, Project parentProject, bool isImported)133 internal Import(XmlElement importElement, Project parentProject, bool isImported) 134 { 135 this.importedFromAnotherProject = isImported; 136 137 // Make sure the <Import> node has been given to us. 138 ErrorUtilities.VerifyThrow(importElement != null, 139 "Need an XML node representing the <Import> element."); 140 141 this.importElement = importElement; 142 143 // Make sure we have a valid parent Project 144 ErrorUtilities.VerifyThrow(parentProject != null, 145 "Need a parent Project object to instantiate an Import."); 146 147 this.parentProject = parentProject; 148 149 // Make sure this really is the <Import> node. 150 ProjectXmlUtilities.VerifyThrowElementName(importElement, XMakeElements.import); 151 152 // Loop through the list of attributes on the <Import> element. 153 foreach (XmlAttribute importAttribute in importElement.Attributes) 154 { 155 switch (importAttribute.Name) 156 { 157 // The "project" attribute points us at the project file to import. 158 case XMakeAttributes.project: 159 // Just store the attribute value at this point. We want to make sure that we evaluate any 160 // Condition attribute before looking at the Project attribute - if the Condition is going to be false, 161 // it's legitimate for the value of the Project attribute to be completely invalid. 162 // For example, <Import Project="$(A)" Condition="$(A)!=''"/> should not cause an error 163 // that the Project attribute is empty. 164 this.projectPathAttribute = importAttribute; 165 break; 166 167 // If the "condition" attribute is present, then it must evaluate to "true". 168 case XMakeAttributes.condition: 169 this.conditionAttribute = importAttribute; 170 break; 171 172 // We've come across an attribute in the <Import> element that we 173 // don't recognize. Fail due to invalid project file. 174 default: 175 ProjectXmlUtilities.ThrowProjectInvalidAttribute(importAttribute); 176 break; 177 } 178 } 179 180 ProjectErrorUtilities.VerifyThrowInvalidProject((this.projectPathAttribute != null) && (this.projectPathAttribute.Value.Length != 0), 181 importElement, "MissingRequiredAttribute", 182 XMakeAttributes.project, XMakeElements.import); 183 184 // Make sure this node has no children. Our schema doesn't support having 185 // children beneath the <Import> element. 186 if (importElement.HasChildNodes) 187 { 188 // Don't put the "if" condition inside the first parameter to 189 // VerifyThrow..., because we'll get null reference exceptions, 190 // since the parameter importElement.FirstChild.Name is being 191 // passed in regardless of whether the condition holds true or not. 192 ProjectXmlUtilities.ThrowProjectInvalidChildElement(importElement.FirstChild); 193 } 194 } 195 196 #endregion 197 198 /// <summary> 199 /// Sets the full evaluated project path for this import. 200 /// </summary> 201 /// <param name="newEvaluatedProjectPath"></param> 202 /// <owner>LukaszG</owner> SetEvaluatedProjectPath(string newEvaluatedProjectPath)203 internal void SetEvaluatedProjectPath(string newEvaluatedProjectPath) 204 { 205 this.evaluatedProjectPath = newEvaluatedProjectPath; 206 } 207 } 208 } 209