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 // </copyright> 5 // <summary>Wraps a task element.</summary> 6 //----------------------------------------------------------------------- 7 8 using System.Collections.Generic; 9 using Microsoft.Build.Construction; 10 using Microsoft.Build.Collections; 11 using Microsoft.Build.Shared; 12 using System.Diagnostics; 13 using System; 14 using Microsoft.Build.BackEnd; 15 16 namespace Microsoft.Build.Execution 17 { 18 /// <summary> 19 /// Wraps a task element 20 /// </summary> 21 /// <remarks> 22 /// This is an immutable class 23 /// </remarks> 24 [DebuggerDisplay("Name={_name} Condition={_condition} ContinueOnError={_continueOnError} MSBuildRuntime={MSBuildRuntime} MSBuildArchitecture={MSBuildArchitecture} #Parameters={_parameters.Count} #Outputs={_outputs.Count}")] 25 public sealed class ProjectTaskInstance : ProjectTargetInstanceChild, INodePacketTranslatable 26 { 27 /// <summary> 28 /// Name of the task, possibly qualified, as it appears in the project 29 /// </summary> 30 private string _name; 31 32 /// <summary> 33 /// Condition on the task, if any 34 /// May be empty string 35 /// </summary> 36 private string _condition; 37 38 /// <summary> 39 /// Continue on error on the task, if any 40 /// May be empty string 41 /// </summary> 42 private string _continueOnError; 43 44 /// <summary> 45 /// Runtime on the task, if any 46 /// May be empty string 47 /// </summary> 48 private string _msbuildRuntime; 49 50 /// <summary> 51 /// Architecture on the task, if any 52 /// May be empty string 53 /// </summary> 54 private string _msbuildArchitecture; 55 56 /// <summary> 57 /// Unordered set of task parameter names and unevaluated values. 58 /// This is a dead, read-only collection. 59 /// </summary> 60 private CopyOnWriteDictionary<string, Tuple<string, ElementLocation>> _parameters; 61 62 /// <summary> 63 /// Output properties and items below this task. This is an ordered collection 64 /// as one may depend on another. 65 /// This is a dead, read-only collection. 66 /// </summary> 67 private List<ProjectTaskInstanceChild> _outputs; 68 69 /// <summary> 70 /// Location of this element 71 /// </summary> 72 private ElementLocation _location; 73 74 /// <summary> 75 /// Location of the condition, if any 76 /// </summary> 77 private ElementLocation _conditionLocation; 78 79 /// <summary> 80 /// Location of the continueOnError attribute, if any 81 /// </summary> 82 private ElementLocation _continueOnErrorLocation; 83 84 /// <summary> 85 /// Location of the MSBuildRuntime attribute, if any 86 /// </summary> 87 private ElementLocation _msbuildRuntimeLocation; 88 89 /// <summary> 90 /// Location of the MSBuildArchitecture attribute, if any 91 /// </summary> 92 private ElementLocation _msbuildArchitectureLocation; 93 94 /// <summary> 95 /// Constructor called by Evaluator. 96 /// All parameters are in the unevaluated state. 97 /// Locations other than the main location may be null. 98 /// </summary> ProjectTaskInstance( ProjectTaskElement element, IList<ProjectTaskInstanceChild> outputs )99 internal ProjectTaskInstance 100 ( 101 ProjectTaskElement element, 102 IList<ProjectTaskInstanceChild> outputs 103 ) 104 { 105 ErrorUtilities.VerifyThrowInternalNull(element, "element"); 106 ErrorUtilities.VerifyThrowInternalNull(outputs, "outputs"); 107 108 // These are all immutable 109 _name = element.Name; 110 _condition = element.Condition; 111 _continueOnError = element.ContinueOnError; 112 _msbuildArchitecture = element.MSBuildArchitecture; 113 _msbuildRuntime = element.MSBuildRuntime; 114 _location = element.Location; 115 _conditionLocation = element.ConditionLocation; 116 _continueOnErrorLocation = element.ContinueOnErrorLocation; 117 _msbuildRuntimeLocation = element.MSBuildRuntimeLocation; 118 _msbuildArchitectureLocation = element.MSBuildArchitectureLocation; 119 _parameters = element.ParametersForEvaluation; 120 _outputs = new List<ProjectTaskInstanceChild>(outputs); 121 } 122 123 /// <summary> 124 /// Creates a new task instance directly. Used for generating instances on-the-fly. 125 /// </summary> 126 /// <param name="name">The task name.</param> 127 /// <param name="location">The location for this task.</param> 128 /// <param name="condition">The unevaluated condition.</param> 129 /// <param name="continueOnError">The unevaluated continue on error.</param> 130 /// <param name="msbuildRuntime">The MSBuild runtime.</param> 131 /// <param name="msbuildArchitecture">The MSBuild architecture.</param> ProjectTaskInstance( string name, ElementLocation location, string condition, string continueOnError, string msbuildRuntime, string msbuildArchitecture )132 internal ProjectTaskInstance( 133 string name, 134 ElementLocation location, 135 string condition, 136 string continueOnError, 137 string msbuildRuntime, 138 string msbuildArchitecture 139 ) : this( 140 name, 141 condition, 142 continueOnError, 143 msbuildRuntime, 144 msbuildArchitecture, 145 new CopyOnWriteDictionary<string, Tuple<string, ElementLocation>>(8, StringComparer.OrdinalIgnoreCase), 146 new List<ProjectTaskInstanceChild>(), 147 location, 148 condition == string.Empty ? null : ElementLocation.EmptyLocation, 149 continueOnError == string.Empty ? null : ElementLocation.EmptyLocation, 150 msbuildRuntime == string.Empty ? null : ElementLocation.EmptyLocation, 151 msbuildArchitecture == string.Empty ? null : ElementLocation.EmptyLocation) 152 { 153 } 154 ProjectTaskInstance( string name, string condition, string continueOnError, string msbuildRuntime, string msbuildArchitecture, CopyOnWriteDictionary<string, Tuple<string, ElementLocation>> parameters, List<ProjectTaskInstanceChild> outputs, ElementLocation location, ElementLocation conditionLocation, ElementLocation continueOnErrorElementLocation, ElementLocation msbuildRuntimeLocation, ElementLocation msbuildArchitectureLocation)155 internal ProjectTaskInstance 156 ( 157 string name, 158 string condition, 159 string continueOnError, 160 string msbuildRuntime, 161 string msbuildArchitecture, 162 CopyOnWriteDictionary<string, Tuple<string, ElementLocation>> parameters, 163 List<ProjectTaskInstanceChild> outputs, 164 ElementLocation location, 165 ElementLocation conditionLocation, 166 ElementLocation continueOnErrorElementLocation, 167 ElementLocation msbuildRuntimeLocation, 168 ElementLocation msbuildArchitectureLocation) 169 { 170 ErrorUtilities.VerifyThrowArgumentLength(name, "name"); 171 ErrorUtilities.VerifyThrowArgumentNull(condition, "condition"); 172 ErrorUtilities.VerifyThrowArgumentNull(continueOnError, "continueOnError"); 173 174 _name = name; 175 _condition = condition; 176 _continueOnError = continueOnError; 177 _msbuildRuntime = msbuildRuntime; 178 _msbuildArchitecture = msbuildArchitecture; 179 _location = location; 180 _conditionLocation = conditionLocation; 181 _continueOnErrorLocation = continueOnErrorElementLocation; 182 _msbuildArchitectureLocation = msbuildArchitectureLocation; 183 _msbuildRuntimeLocation = msbuildRuntimeLocation; 184 _parameters = parameters; 185 _outputs = outputs; 186 } 187 ProjectTaskInstance()188 private ProjectTaskInstance() 189 { 190 } 191 192 /// <summary> 193 /// Name of the task, possibly qualified, as it appears in the project 194 /// </summary> 195 public string Name 196 { 197 get { return _name; } 198 } 199 200 /// <summary> 201 /// Unevaluated condition on the task 202 /// May be empty string. 203 /// </summary> 204 public override string Condition 205 { 206 get { return _condition; } 207 } 208 209 /// <summary> 210 /// Unevaluated ContinueOnError on the task. 211 /// May be empty string. 212 /// </summary> 213 public string ContinueOnError 214 { 215 get { return _continueOnError; } 216 } 217 218 /// <summary> 219 /// Unevaluated MSBuildRuntime on the task. 220 /// May be empty string. 221 /// </summary> 222 public string MSBuildRuntime 223 { 224 get { return _msbuildRuntime; } 225 } 226 227 /// <summary> 228 /// Unevaluated MSBuildArchitecture on the task. 229 /// May be empty string. 230 /// </summary> 231 public string MSBuildArchitecture 232 { 233 get { return _msbuildArchitecture; } 234 } 235 236 /// <summary> 237 /// Read-only dead unordered set of task parameter names and unevaluated values. 238 /// Condition and ContinueOnError, which have their own properties, are not included in this collection. 239 /// </summary> 240 public IDictionary<string, string> Parameters 241 { 242 get 243 { 244 Dictionary<string, string> filteredParameters = new Dictionary<string, string>(_parameters.Count, StringComparer.OrdinalIgnoreCase); 245 foreach (KeyValuePair<string, Tuple<string, ElementLocation>> parameter in _parameters) 246 { 247 filteredParameters[parameter.Key] = parameter.Value.Item1; 248 } 249 250 return filteredParameters; 251 } 252 } 253 254 internal IDictionary<string, Tuple<string, ElementLocation>> TestGetParameters => _parameters; 255 256 /// <summary> 257 /// Ordered set of output property and item objects. 258 /// This is a read-only dead collection. 259 /// </summary> 260 public IList<ProjectTaskInstanceChild> Outputs 261 { 262 get { return _outputs; } 263 } 264 265 /// <summary> 266 /// Location of the ContinueOnError attribute, if any 267 /// </summary> 268 public ElementLocation ContinueOnErrorLocation 269 { 270 get { return _continueOnErrorLocation; } 271 } 272 273 /// <summary> 274 /// Location of the MSBuildRuntime attribute, if any 275 /// </summary> 276 public ElementLocation MSBuildRuntimeLocation 277 { 278 get { return _msbuildRuntimeLocation; } 279 } 280 281 /// <summary> 282 /// Location of the MSBuildArchitecture attribute, if any 283 /// </summary> 284 public ElementLocation MSBuildArchitectureLocation 285 { 286 get { return _msbuildArchitectureLocation; } 287 } 288 289 /// <summary> 290 /// Location of the original element 291 /// </summary> 292 public override ElementLocation Location 293 { 294 get { return _location; } 295 } 296 297 /// <summary> 298 /// Location of the condition, if any 299 /// </summary> 300 public override ElementLocation ConditionLocation 301 { 302 get { return _conditionLocation; } 303 } 304 305 /// <summary> 306 /// Retrieves the parameters dictionary as used during the build. 307 /// </summary> 308 internal IDictionary<string, Tuple<string, ElementLocation>> ParametersForBuild 309 { 310 get { return _parameters; } 311 } 312 313 /// <summary> 314 /// Returns the value of a named parameter, or null if there is no such parameter. 315 /// </summary> 316 /// <param name="parameterName">The name of the parameter to retrieve.</param> 317 /// <returns>The parameter value, or null if it does not exist.</returns> GetParameter(string parameterName)318 internal string GetParameter(string parameterName) 319 { 320 Tuple<string, ElementLocation> parameterValue = null; 321 if (_parameters.TryGetValue(parameterName, out parameterValue)) 322 { 323 return parameterValue.Item1; 324 } 325 326 return null; 327 } 328 329 /// <summary> 330 /// Sets the unevaluated value for the specified parameter. 331 /// </summary> 332 /// <param name="parameterName">The name of the parameter to set.</param> 333 /// <param name="unevaluatedValue">The unevaluated value for the parameter.</param> SetParameter(string parameterName, string unevaluatedValue)334 internal void SetParameter(string parameterName, string unevaluatedValue) 335 { 336 _parameters[parameterName] = new Tuple<string, ElementLocation>(unevaluatedValue, ElementLocation.EmptyLocation); 337 } 338 339 /// <summary> 340 /// Adds an output item to the task. 341 /// </summary> 342 /// <param name="taskOutputParameterName">The name of the parameter on the task which produces the output.</param> 343 /// <param name="itemName">The item which will receive the output.</param> 344 /// <param name="condition">The condition.</param> AddOutputItem(string taskOutputParameterName, string itemName, string condition)345 internal void AddOutputItem(string taskOutputParameterName, string itemName, string condition) 346 { 347 ErrorUtilities.VerifyThrowArgumentLength(taskOutputParameterName, "taskOutputParameterName"); 348 ErrorUtilities.VerifyThrowArgumentLength(itemName, "itemName"); 349 _outputs.Add(new ProjectTaskOutputItemInstance(itemName, taskOutputParameterName, condition ?? String.Empty, ElementLocation.EmptyLocation, ElementLocation.EmptyLocation, ElementLocation.EmptyLocation, condition == null ? null : ElementLocation.EmptyLocation)); 350 } 351 352 /// <summary> 353 /// Adds an output property to the task. 354 /// </summary> 355 /// <param name="taskOutputParameterName">The name of the parameter on the task which produces the output.</param> 356 /// <param name="propertyName">The property which will receive the output.</param> 357 /// <param name="condition">The condition.</param> AddOutputProperty(string taskOutputParameterName, string propertyName, string condition)358 internal void AddOutputProperty(string taskOutputParameterName, string propertyName, string condition) 359 { 360 ErrorUtilities.VerifyThrowArgumentLength(taskOutputParameterName, "taskOutputParameterName"); 361 ErrorUtilities.VerifyThrowArgumentLength(propertyName, "propertyName"); 362 _outputs.Add(new ProjectTaskOutputPropertyInstance(propertyName, taskOutputParameterName, condition ?? String.Empty, ElementLocation.EmptyLocation, ElementLocation.EmptyLocation, ElementLocation.EmptyLocation, condition == null ? null : ElementLocation.EmptyLocation)); 363 } 364 INodePacketTranslatable.Translate(INodePacketTranslator translator)365 void INodePacketTranslatable.Translate(INodePacketTranslator translator) 366 { 367 if (translator.Mode == TranslationDirection.WriteToStream) 368 { 369 var typeName = this.GetType().FullName; 370 translator.Translate(ref typeName); 371 } 372 373 translator.Translate(ref _name); 374 translator.Translate(ref _condition); 375 translator.Translate(ref _continueOnError); 376 translator.Translate(ref _msbuildRuntime); 377 translator.Translate(ref _msbuildArchitecture); 378 translator.Translate(ref _outputs, ProjectTaskInstanceChild.FactoryForDeserialization); 379 translator.Translate(ref _location, ElementLocation.FactoryForDeserialization); 380 translator.Translate(ref _conditionLocation, ElementLocation.FactoryForDeserialization); 381 translator.Translate(ref _continueOnErrorLocation, ElementLocation.FactoryForDeserialization); 382 translator.Translate(ref _msbuildRuntimeLocation, ElementLocation.FactoryForDeserialization); 383 translator.Translate(ref _msbuildArchitectureLocation, ElementLocation.FactoryForDeserialization); 384 385 IDictionary<string, Tuple<string, ElementLocation>> localParameters = _parameters; 386 translator.TranslateDictionary( 387 ref localParameters, 388 ParametersKeyTranslator, 389 ParametersValueTranslator, 390 count => new CopyOnWriteDictionary<string, Tuple<string, ElementLocation>>(count)); 391 392 if (translator.Mode == TranslationDirection.ReadFromStream && localParameters != null) 393 { 394 _parameters = (CopyOnWriteDictionary<string, Tuple<string, ElementLocation>>) localParameters; 395 } 396 } 397 ParametersKeyTranslator(ref string key, INodePacketTranslator translator)398 private static void ParametersKeyTranslator(ref string key, INodePacketTranslator translator) 399 { 400 translator.Translate(ref key); 401 } 402 ParametersValueTranslator(ref Tuple<string, ElementLocation> value, INodePacketTranslator translator)403 private static void ParametersValueTranslator(ref Tuple<string, ElementLocation> value, INodePacketTranslator translator) 404 { 405 if (translator.Mode == TranslationDirection.WriteToStream) 406 { 407 var item1 = value.Item1; 408 var item2 = value.Item2; 409 410 translator.Translate(ref item1); 411 translator.Translate(ref item2, ElementLocation.FactoryForDeserialization); 412 } 413 else 414 { 415 var item1 = default(string); 416 var item2 = default(ElementLocation); 417 418 translator.Translate(ref item1); 419 translator.Translate(ref item2, ElementLocation.FactoryForDeserialization); 420 421 value = Tuple.Create(item1, item2); 422 } 423 } 424 FactoryForDeserialization(INodePacketTranslator translator)425 internal new static ProjectTaskInstance FactoryForDeserialization(INodePacketTranslator translator) 426 { 427 return translator.FactoryForDeserializingTypeWithName<ProjectTaskInstance>(); 428 } 429 } 430 } 431