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>Class containing data for a build request.</summary> 6 //----------------------------------------------------------------------- 7 8 using System; 9 using System.Collections.Generic; 10 using System.Diagnostics; 11 using System.Text; 12 using Microsoft.Build.Shared; 13 using Microsoft.Build.Framework; 14 using Microsoft.Build.Execution; 15 16 using Constants = Microsoft.Build.Internal.Constants; 17 18 namespace Microsoft.Build.BackEnd 19 { 20 /// <summary> 21 /// A build request contains information about the configuration used to build as well 22 /// as which targets need to be built. 23 /// </summary> 24 internal class BuildRequest : INodePacket 25 { 26 /// <summary> 27 /// The invalid global request id 28 /// </summary> 29 public const int InvalidGlobalRequestId = -1; 30 31 /// <summary> 32 /// The invalid node request id 33 /// </summary> 34 public const int InvalidNodeRequestId = 0; 35 36 /// <summary> 37 /// The results transfer request id 38 /// </summary> 39 public const int ResultsTransferNodeRequestId = -1; 40 41 /// <summary> 42 /// The submission with which this request is associated. 43 /// </summary> 44 private int _submissionId; 45 46 /// <summary> 47 /// The configuration id. 48 /// </summary> 49 private int _configurationId; 50 51 /// <summary> 52 /// The global build request id, assigned by the Build Manager 53 /// </summary> 54 private int _globalRequestId; 55 56 /// <summary> 57 /// The global request id of the request which spawned this one. 58 /// </summary> 59 private int _parentGlobalRequestId; 60 61 /// <summary> 62 /// The build request id assigned by the node originating this request. 63 /// </summary> 64 private int _nodeRequestId; 65 66 /// <summary> 67 /// The targets specified when the request was made. Doesn't include default or initial targets. 68 /// </summary> 69 private List<string> _targets; 70 71 /// <summary> 72 /// The route for host-aware tasks back to the host 73 /// </summary> 74 private HostServices _hostServices; 75 76 /// <summary> 77 /// The build event context of the parent 78 /// </summary> 79 private BuildEventContext _parentBuildEventContext; 80 81 /// <summary> 82 /// The build event context of this request 83 /// </summary> 84 private BuildEventContext _buildEventContext; 85 86 /// <summary> 87 /// Whether or not the <see cref="BuildResult"/> issued in response to this request should include <see cref="BuildResult.ProjectStateAfterBuild"/>. 88 /// </summary> 89 private BuildRequestDataFlags _buildRequestDataFlags; 90 91 /// <summary> 92 /// Filter describing properties, items, and metadata of interest for this request. 93 /// </summary> 94 private RequestedProjectState _requestedProjectState; 95 96 /// <summary> 97 /// If set, skip targets that are not defined in the projects to be built. 98 /// </summary> 99 private bool _skipNonexistentTargets; 100 101 /// <summary> 102 /// Constructor for serialization. 103 /// </summary> BuildRequest()104 public BuildRequest() 105 { 106 } 107 108 /// <summary> 109 /// Initializes a build request with a parent context. 110 /// </summary> 111 /// <param name="submissionId">The id of the build submission.</param> 112 /// <param name="nodeRequestId">The id of the node issuing the request</param> 113 /// <param name="configurationId">The configuration id to use.</param> 114 /// <param name="escapedTargets">The targets to be built</param> 115 /// <param name="hostServices">Host services if any. May be null.</param> 116 /// <param name="parentBuildEventContext">The build event context of the parent project.</param> 117 /// <param name="parentRequest">The parent build request, if any.</param> 118 /// <param name="buildRequestDataFlags">Additional flags for the request.</param> 119 /// <param name="requestedProjectState">Filter for desired build results.</param> BuildRequest( int submissionId, int nodeRequestId, int configurationId, ICollection<string> escapedTargets, HostServices hostServices, BuildEventContext parentBuildEventContext, BuildRequest parentRequest, BuildRequestDataFlags buildRequestDataFlags = BuildRequestDataFlags.None, RequestedProjectState requestedProjectState = null)120 public BuildRequest( 121 int submissionId, 122 int nodeRequestId, 123 int configurationId, 124 ICollection<string> escapedTargets, 125 HostServices hostServices, 126 BuildEventContext parentBuildEventContext, 127 BuildRequest parentRequest, 128 BuildRequestDataFlags buildRequestDataFlags = BuildRequestDataFlags.None, 129 RequestedProjectState requestedProjectState = null) 130 { 131 ErrorUtilities.VerifyThrowArgumentNull(escapedTargets, "targets"); 132 ErrorUtilities.VerifyThrowArgumentNull(parentBuildEventContext, "parentBuildEventContext"); 133 134 _submissionId = submissionId; 135 _configurationId = configurationId; 136 137 // When targets come into a build request, we unescape them. 138 _targets = new List<string>(escapedTargets.Count); 139 foreach (string target in escapedTargets) 140 { 141 _targets.Add(EscapingUtilities.UnescapeAll(target)); 142 } 143 144 _hostServices = hostServices; 145 _buildEventContext = BuildEventContext.Invalid; 146 _parentBuildEventContext = parentBuildEventContext; 147 _globalRequestId = InvalidGlobalRequestId; 148 _parentGlobalRequestId = parentRequest?.GlobalRequestId ?? InvalidGlobalRequestId; 149 150 _nodeRequestId = nodeRequestId; 151 _buildRequestDataFlags = buildRequestDataFlags; 152 _requestedProjectState = requestedProjectState; 153 } 154 155 /// <summary> 156 /// Private constructor for deserialization 157 /// </summary> BuildRequest(INodePacketTranslator translator)158 private BuildRequest(INodePacketTranslator translator) 159 { 160 Translate(translator); 161 } 162 163 /// <summary> 164 /// Returns true if the configuration has been resolved, false otherwise. 165 /// </summary> 166 public bool IsConfigurationResolved 167 { 168 [DebuggerStepThrough] 169 get 170 { return _configurationId > 0; } 171 } 172 173 /// <summary> 174 /// Returns the submission id 175 /// </summary> 176 public int SubmissionId 177 { 178 [DebuggerStepThrough] 179 get 180 { return _submissionId; } 181 } 182 183 /// <summary> 184 /// Returns the configuration id 185 /// </summary> 186 public int ConfigurationId 187 { 188 [DebuggerStepThrough] 189 get 190 { return _configurationId; } 191 } 192 193 /// <summary> 194 /// Gets the global request id 195 /// </summary> 196 public int GlobalRequestId 197 { 198 [DebuggerStepThrough] 199 get 200 { 201 return _globalRequestId; 202 } 203 204 set 205 { 206 ErrorUtilities.VerifyThrow(_globalRequestId == InvalidGlobalRequestId, "Global Request ID cannot be set twice."); 207 _globalRequestId = value; 208 } 209 } 210 211 /// <summary> 212 /// Gets the global request id of the parent request. 213 /// </summary> 214 public int ParentGlobalRequestId 215 { 216 [DebuggerStepThrough] 217 get 218 { return _parentGlobalRequestId; } 219 } 220 221 /// <summary> 222 /// Gets the node request id 223 /// </summary> 224 public int NodeRequestId 225 { 226 [DebuggerStepThrough] 227 get 228 { return _nodeRequestId; } 229 230 [DebuggerStepThrough] 231 set 232 { _nodeRequestId = value; } 233 } 234 235 /// <summary> 236 /// Returns the set of unescaped targets to be built 237 /// </summary> 238 public List<string> Targets 239 { 240 [DebuggerStepThrough] 241 get 242 { return _targets; } 243 } 244 245 /// <summary> 246 /// Returns the type of packet. 247 /// </summary> 248 public NodePacketType Type 249 { 250 [DebuggerStepThrough] 251 get 252 { return NodePacketType.BuildRequest; } 253 } 254 255 /// <summary> 256 /// Returns the build event context of the parent, if any. 257 /// </summary> 258 public BuildEventContext ParentBuildEventContext 259 { 260 [DebuggerStepThrough] 261 get 262 { return _parentBuildEventContext; } 263 } 264 265 /// <summary> 266 /// Returns the build event context for this request, if any. 267 /// </summary> 268 public BuildEventContext BuildEventContext 269 { 270 [DebuggerStepThrough] 271 get 272 { 273 return _buildEventContext; 274 } 275 276 set 277 { 278 ErrorUtilities.VerifyThrow(_buildEventContext == BuildEventContext.Invalid, "The build event context is already set."); 279 _buildEventContext = value; 280 } 281 } 282 283 /// <summary> 284 /// The set of flags specified in the BuildRequestData for this request. 285 /// </summary> 286 public BuildRequestDataFlags BuildRequestDataFlags 287 { 288 get { return _buildRequestDataFlags; } 289 set { _buildRequestDataFlags = value; } 290 } 291 292 /// <summary> 293 /// Filter describing properties, items, and metadata of interest for this request. 294 /// </summary> 295 public RequestedProjectState RequestedProjectState 296 { 297 get { return _requestedProjectState; } 298 set { _requestedProjectState = value; } 299 } 300 301 302 /// <summary> 303 /// The route for host-aware tasks back to the host 304 /// </summary> 305 internal HostServices HostServices 306 { 307 [DebuggerStepThrough] 308 get 309 { return _hostServices; } 310 } 311 312 /// <summary> 313 /// Returns true if this is a root request (one which has no parent.) 314 /// </summary> 315 internal bool IsRootRequest 316 { 317 [DebuggerStepThrough] 318 get 319 { return _parentGlobalRequestId == InvalidGlobalRequestId; } 320 } 321 322 /// <summary> 323 /// If set, skip targets that are not defined in the projects to be built. 324 /// </summary> 325 internal bool SkipNonexistentTargets 326 { 327 get { return _skipNonexistentTargets; } 328 set { _skipNonexistentTargets = value; } 329 } 330 331 /// <summary> 332 /// Sets the configuration id to a resolved id. 333 /// </summary> 334 /// <param name="newConfigId">The new configuration id for this request.</param> ResolveConfiguration(int newConfigId)335 public void ResolveConfiguration(int newConfigId) 336 { 337 ErrorUtilities.VerifyThrow(!IsConfigurationResolved, "Configuration already resolved"); 338 _configurationId = newConfigId; 339 ErrorUtilities.VerifyThrow(IsConfigurationResolved, "Configuration not resolved"); 340 } 341 342 #region INodePacket Members 343 344 /// <summary> 345 /// Reads/writes this packet 346 /// </summary> Translate(INodePacketTranslator translator)347 public void Translate(INodePacketTranslator translator) 348 { 349 translator.Translate(ref _submissionId); 350 translator.Translate(ref _configurationId); 351 translator.Translate(ref _globalRequestId); 352 translator.Translate(ref _parentGlobalRequestId); 353 translator.Translate(ref _nodeRequestId); 354 translator.Translate(ref _targets); 355 translator.Translate(ref _parentBuildEventContext); 356 translator.Translate(ref _buildEventContext); 357 translator.TranslateEnum(ref _buildRequestDataFlags, (int)_buildRequestDataFlags); 358 translator.Translate(ref _skipNonexistentTargets); 359 translator.Translate(ref _requestedProjectState); 360 361 // UNDONE: (Compat) Serialize the host object. 362 } 363 364 /// <summary> 365 /// Factory for serialization. 366 /// </summary> FactoryForDeserialization(INodePacketTranslator translator)367 internal static INodePacket FactoryForDeserialization(INodePacketTranslator translator) 368 { 369 return new BuildRequest(translator); 370 } 371 372 #endregion 373 /// <summary> 374 /// Returns true if the result applies to this request. 375 /// </summary> DoesResultApplyToRequest(BuildResult result)376 internal bool DoesResultApplyToRequest(BuildResult result) 377 { 378 return _globalRequestId == result.GlobalRequestId && _nodeRequestId == result.NodeRequestId; 379 } 380 } 381 } 382