/// <summary> /// This method adds cached results for each target results for which are contained inside /// the build result. This method is thread safe. /// </summary> internal void AddCacheEntryForBuildResults(BuildResult buildResult) { ErrorUtilities.VerifyThrow(buildResult != null, "Expect a non-null build result"); // Don't cache results if they are marked as uncacheable if (!buildResult.UseResultCache) { return; } cacheScopeReaderWriterLock.AcquireWriterLock(Timeout.Infinite); try { if (!ContainsCacheEntry(Constants.defaultTargetCacheName)) { // If the project file is malformed the build may fail without initializing the initialtargets or // the default targests fields. The retrieval code expects non-null values // so it is necessary to replace null with empty string ErrorUtilities.VerifyThrow(!buildResult.EvaluationResult || (buildResult.InitialTargets != null && buildResult.DefaultTargets != null), "Expect initial targets to be non-null for successful builds"); string defaultTargets = buildResult.DefaultTargets ?? String.Empty; PropertyCacheEntry defaultTargetsCacheEntry = new PropertyCacheEntry(Constants.defaultTargetCacheName, defaultTargets); AddCacheEntryInternal(defaultTargetsCacheEntry); string initialTargets = buildResult.InitialTargets ?? String.Empty; PropertyCacheEntry initialTargetsCacheEntry = new PropertyCacheEntry(Constants.initialTargetCacheName, initialTargets); AddCacheEntryInternal(initialTargetsCacheEntry); } if (!ContainsCacheEntry(Constants.projectIdCacheName)) { PropertyCacheEntry projectIdCacheEntry = new PropertyCacheEntry(Constants.projectIdCacheName, buildResult.ProjectId.ToString(CultureInfo.InvariantCulture)); AddCacheEntryInternal(projectIdCacheEntry); } IDictionary outputsByTargetName = buildResult.OutputsByTarget; //Create single entry for each target in the request foreach (DictionaryEntry entry in buildResult.ResultByTarget) { Target.BuildState buildState = (Target.BuildState)entry.Value; // Only cache successful and failed targets if ((buildState == Target.BuildState.CompletedSuccessfully) || (buildState == Target.BuildState.CompletedUnsuccessfully)) { BuildItem[] targetOutputs = null; // Only cache output items for successful targets if (buildState == Target.BuildState.CompletedSuccessfully) { ErrorUtilities.VerifyThrow(buildResult.OutputsByTarget.Contains(entry.Key), "We must have build results for successful targets"); BuildItem[] outputItems = (BuildItem[])buildResult.OutputsByTarget[entry.Key]; // It's essential that we clear out any pointers to the project from the BuildItem; // otherwise the cache will hold onto the project, and not save any memory. if (outputItems != null) { for (int i = 0; i < outputItems.Length; i++) { outputItems[i] = outputItems[i].VirtualClone(true /* remove references to minimise transitive size */); } } targetOutputs = (BuildItem[])buildResult.OutputsByTarget[entry.Key]; } BuildResultCacheEntry cacheEntry = new BuildResultCacheEntry((string)entry.Key, targetOutputs, buildState == Target.BuildState.CompletedSuccessfully); if (Engine.debugMode) { Console.WriteLine("+++Adding cache entry for " + (string)entry.Key + " in " + this.ScopeName + " result: " + (buildState == Target.BuildState.CompletedSuccessfully)); } AddCacheEntryInternal(cacheEntry); } } } finally { cacheScopeReaderWriterLock.ReleaseWriterLock(); } }
/// <summary> /// Overridden to verify that the potential parent and siblings /// are acceptable. Throws InvalidOperationException if they are not. /// </summary> internal override void VerifyThrowInvalidOperationAcceptableLocation(ProjectElementContainer parent, ProjectElement previousSibling, ProjectElement nextSibling) { ErrorUtilities.VerifyThrowInvalidOperation(parent is ProjectTaskElement, "OM_CannotAcceptParent"); }
public void GetObjectData(SerializationInfo info, StreamingContext context) { ErrorUtilities.VerifyThrowArgumentNull(info, "info"); info.AddValue("fileState", instanceLocalFileStateCache); }
/// <summary> /// Gets the entry with the specified index /// </summary> internal void GetEntry(int index, out string assemblyPath, out string typeLibraryPath) { ErrorUtilities.VerifyThrow((index >= 0) && (index < _assemblies.Count), "Invalid index in the call to AssemblyRegistrationCache.GetEntry"); assemblyPath = _assemblies[index]; typeLibraryPath = _typeLibraries[index]; }
/// <summary> /// Static factory for component creation. /// </summary> static internal IBuildComponent CreateComponent(BuildComponentType componentType) { ErrorUtilities.VerifyThrow(componentType == BuildComponentType.OutOfProcTaskHostNodeProvider, "Factory cannot create components of type {0}", componentType); return(new NodeProviderOutOfProcTaskHost()); }
/// <summary> /// The thread procedure executes the tasks and calls callback once it is done /// </summary> virtual internal void ExecuteTask() { bool taskExecutedSuccessfully = true; Exception thrownException = null; bool dontPostOutputs = false; if (profileExecution) { startTime = DateTime.Now.Ticks; } try { TaskEngine taskEngine = new TaskEngine( taskXmlNode, hostObject, projectFileOfTaskNode, parentProjectFullFileName, loggingService, handleId, parentModule, buildEventContext); // Set the directory to the one appropriate for the task if (FileUtilities.GetCurrentDirectoryStaticBuffer(currentDirectoryBuffer) != executionDirectory) { Directory.SetCurrentDirectory(executionDirectory); } // if we're skipping task execution because the target is up-to-date, we // need to go ahead and infer all the outputs that would have been emitted; // alternatively, if we're doing an incremental build, we need to infer the // outputs that would have been produced if all the up-to-date items had // been built by the task if ((howToExecuteTask & TaskExecutionMode.InferOutputsOnly) != TaskExecutionMode.Invalid) { bool targetInferenceSuccessful = false; targetInferenceSuccessful = TaskEngineExecuteTask (taskEngine, TaskExecutionMode.InferOutputsOnly, lookupForInference ); ErrorUtilities.VerifyThrow(targetInferenceSuccessful, "A task engine should never fail to infer its task's up-to-date outputs."); } // execute the task using the items that need to be (re)built if ((howToExecuteTask & TaskExecutionMode.ExecuteTaskAndGatherOutputs) != TaskExecutionMode.Invalid) { taskExecutedSuccessfully = TaskEngineExecuteTask (taskEngine, TaskExecutionMode.ExecuteTaskAndGatherOutputs, lookupForExecution ); } } // We want to catch all exceptions and pass them on to the engine catch (Exception e) { thrownException = e; taskExecutedSuccessfully = false; // In single threaded mode the exception can be thrown on the current thread if (parentModule.RethrowTaskExceptions()) { dontPostOutputs = true; throw; } } finally { if (!dontPostOutputs) { long executionTime = profileExecution ? DateTime.Now.Ticks - startTime : 0; // Post the outputs to the engine parentModule.PostTaskOutputs(handleId, taskExecutedSuccessfully, thrownException, executionTime); } } }
internal void VerifyCallback(Uri callback) { ErrorUtilities.VerifyProtocol(MessagingUtilities.AreEquivalentConstantTime(this.CallbackHash, CalculateCallbackHash(callback)), Protocol.redirect_uri_mismatch); }
/// <summary> /// Log that a project has started if it has no parent (the first project) /// </summary> /// <param name="requestEntry">The build request entry for this project.</param> /// <returns>The BuildEventContext to use for this project.</returns> internal ProjectLoggingContext LogProjectStarted(BuildRequestEntry requestEntry) { ErrorUtilities.VerifyThrow(this.IsValid, "Build not started."); return(new ProjectLoggingContext(this, requestEntry)); }
/// <summary> /// Gathers toolset data from the registry and configuration file, if any. /// NOTE: this method is internal for unit testing purposes only. /// </summary> internal static string ReadAllToolsets ( Dictionary <string, Toolset> toolsets, ToolsetRegistryReader registryReader, ToolsetConfigurationReader configurationReader, PropertyDictionary <ProjectPropertyInstance> environmentProperties, PropertyDictionary <ProjectPropertyInstance> globalProperties, ToolsetDefinitionLocations locations ) { PropertyDictionary <ProjectPropertyInstance> initialProperties = new PropertyDictionary <ProjectPropertyInstance>(environmentProperties); initialProperties.ImportProperties(globalProperties); // The ordering here is important because the configuration file should have greater precedence // than the registry, and we do a check and don't read in the new toolset if there's already one. string defaultToolsVersionFromConfiguration = null; string overrideTasksPathFromConfiguration = null; string defaultOverrideToolsVersionFromConfiguration = null; if ((locations & ToolsetDefinitionLocations.ConfigurationFile) == ToolsetDefinitionLocations.ConfigurationFile) { if (configurationReader == null && ToolsetConfigurationReaderHelpers.ConfigurationFileMayHaveToolsets()) { // We haven't been passed in a fake configuration reader by a unit test, // and it looks like we have a .config file to read, so create a real // configuration reader configurationReader = new ToolsetConfigurationReader(environmentProperties, globalProperties); } if (configurationReader != null) { // Accumulation of properties is okay in the config file because it's deterministically ordered defaultToolsVersionFromConfiguration = configurationReader.ReadToolsets(toolsets, globalProperties, initialProperties, true /* accumulate properties */, out overrideTasksPathFromConfiguration, out defaultOverrideToolsVersionFromConfiguration); } } string defaultToolsVersionFromRegistry = null; string overrideTasksPathFromRegistry = null; string defaultOverrideToolsVersionFromRegistry = null; if ((locations & ToolsetDefinitionLocations.Registry) == ToolsetDefinitionLocations.Registry) { // If we haven't been provided a registry reader (i.e. unit tests), create one registryReader = registryReader ?? new ToolsetRegistryReader(environmentProperties, globalProperties); // We do not accumulate properties when reading them from the registry, because the order // in which values are returned to us is essentially random: so we disallow one property // in the registry to refer to another also in the registry defaultToolsVersionFromRegistry = registryReader.ReadToolsets(toolsets, globalProperties, initialProperties, false /* do not accumulate properties */, out overrideTasksPathFromRegistry, out defaultOverrideToolsVersionFromRegistry); } // The 2.0 .NET Framework installer did not write a ToolsVersion key for itself in the registry. // The 3.5 installer writes one for 2.0, but 3.5 might not be installed. // The 4.0 and subsequent installers can't keep writing the 2.0 one, because (a) it causes SxS issues and (b) we // don't want it unless 2.0 is installed. // So if the 2.0 framework is actually installed, we're reading the registry, and either the registry or the config // file have not already created the 2.0 toolset, mock up a fake one. if ( ((locations & ToolsetDefinitionLocations.Registry) != 0) && !toolsets.ContainsKey("2.0") && FrameworkLocationHelper.PathToDotNetFrameworkV20 != null ) { Toolset synthetic20Toolset = new Toolset("2.0", FrameworkLocationHelper.PathToDotNetFrameworkV20, environmentProperties, globalProperties, null /* 2.0 did not have override tasks */, null /* 2.0 did not have a default override toolsversion */); toolsets.Add("2.0", synthetic20Toolset); } // We'll use the path from the configuration file if it was specified, otherwise we'll try // the one from the registry. It's possible (and valid) that neither the configuration file // nor the registry specify a override in which case we'll just return null. string overrideTasksPath = overrideTasksPathFromConfiguration ?? overrideTasksPathFromRegistry; // We'll use the path from the configuration file if it was specified, otherwise we'll try // the one from the registry. It's possible (and valid) that neither the configuration file // nor the registry specify a override in which case we'll just return null. string defaultOverrideToolsVersion = defaultOverrideToolsVersionFromConfiguration ?? defaultOverrideToolsVersionFromRegistry; // We'll use the default from the configuration file if it was specified, otherwise we'll try // the one from the registry. It's possible (and valid) that neither the configuration file // nor the registry specify a default, in which case we'll just return null. string defaultToolsVersion = defaultToolsVersionFromConfiguration ?? defaultToolsVersionFromRegistry; // If we got a default version from the registry or config file, and it // actually exists, fine. // Otherwise we have to come up with one. if (defaultToolsVersion == null || !toolsets.ContainsKey(defaultToolsVersion)) { // We're going to choose a hard coded default tools version of 2.0. defaultToolsVersion = Constants.defaultToolsVersion; // But don't overwrite any existing tools path for this default we're choosing. if (!toolsets.ContainsKey(Constants.defaultToolsVersion)) { // There's no tools path already for 2.0, so use the path to the v2.0 .NET Framework. // If an old-fashioned caller sets BinPath property, or passed a BinPath to the constructor, // that will overwrite what we're setting here. ErrorUtilities.VerifyThrow(Constants.defaultToolsVersion == "2.0", "Getting 2.0 FX path so default should be 2.0"); string pathToFramework = FrameworkLocationHelper.PathToDotNetFrameworkV20; // We could not find the default toolsversion because it was not installed on the machine. Fallback to the // one we expect to always be there when running msbuild 4.0. if (pathToFramework == null) { pathToFramework = FrameworkLocationHelper.PathToDotNetFrameworkV40; defaultToolsVersion = Constants.defaultFallbackToolsVersion; } // Again don't overwrite any existing tools path for this default we're choosing. if (!toolsets.ContainsKey(defaultToolsVersion)) { Toolset defaultToolset = new Toolset(defaultToolsVersion, pathToFramework, environmentProperties, globalProperties, overrideTasksPath, defaultOverrideToolsVersion); toolsets.Add(defaultToolsVersion, defaultToolset); } } } return(defaultToolsVersion); }
/// <summary> /// ICollection member method for copying the contents of this collection into an array /// </summary> /// <param name="array"></param> /// <param name="index"></param> /// <owner>LukaszG</owner> public void CopyTo(Array array, int index) { ErrorUtilities.VerifyThrow(this.usingTasks != null, "UsingTaskCollection's ArrayList not initialized!"); this.usingTasks.CopyTo(array, index); }
public void Consume(BuildEventArgs buildEvent) { switch (buildEvent) { case BuildMessageEventArgs buildMessageEvent: RaiseMessageEvent(null, buildMessageEvent); break; case TaskStartedEventArgs taskStartedEvent: RaiseTaskStartedEvent(null, taskStartedEvent); break; case TaskFinishedEventArgs taskFinishedEvent: RaiseTaskFinishedEvent(null, taskFinishedEvent); break; case TargetStartedEventArgs targetStartedEvent: RaiseTargetStartedEvent(null, targetStartedEvent); break; case TargetFinishedEventArgs targetFinishedEvent: RaiseTargetFinishedEvent(null, targetFinishedEvent); break; case ProjectStartedEventArgs projectStartedEvent: RaiseProjectStartedEvent(null, projectStartedEvent); break; case ProjectFinishedEventArgs projectFinishedEvent: RaiseProjectFinishedEvent(null, projectFinishedEvent); break; case BuildStartedEventArgs buildStartedEvent: HaveLoggedBuildStartedEvent = true; RaiseBuildStartedEvent(null, buildStartedEvent); break; case BuildFinishedEventArgs buildFinishedEvent: HaveLoggedBuildFinishedEvent = true; RaiseBuildFinishedEvent(null, buildFinishedEvent); break; case CustomBuildEventArgs customBuildEvent: RaiseCustomEvent(null, customBuildEvent); break; case BuildStatusEventArgs buildStatusEvent: RaiseStatusEvent(null, buildStatusEvent); break; case BuildWarningEventArgs buildWarningEvent: RaiseWarningEvent(null, buildWarningEvent); break; case BuildErrorEventArgs buildErrorEvent: RaiseErrorEvent(null, buildErrorEvent); break; case TelemetryEventArgs telemetryEvent: RaiseTelemetryEvent(null, telemetryEvent); break; default: ErrorUtilities.ThrowInternalError("Unknown event args type."); break; } }
/// <summary> /// IEnumerable member method for returning the enumerator /// </summary> /// <returns></returns> /// <owner>LukaszG</owner> public IEnumerator GetEnumerator() { ErrorUtilities.VerifyThrow(this.usingTasks != null, "UsingTaskCollection's ArrayList not initialized!"); return(this.usingTasks.GetEnumerator()); }
/// <summary> /// Adds a new UsingTask to this collection. Does not alter the parent project's XML. /// </summary> /// <param name="usingTask"></param> /// <owner>LukaszG</owner> internal void Add(UsingTask usingTask) { ErrorUtilities.VerifyThrow(this.usingTasks != null, "UsingTaskCollection's ArrayList not initialized!"); this.usingTasks.Add(usingTask); }
/// <summary> /// Get a cached build result if available for the given request. This method is thread safe. /// </summary> /// <param name="buildRequest"></param> /// <param name="actuallyBuiltTargets"></param> /// <returns></returns> internal BuildResult GetCachedBuildResult(BuildRequest buildRequest, out ArrayList actuallyBuiltTargets) { actuallyBuiltTargets = null; PropertyCacheEntry defaultTargetsCacheEntry, initialTargetsCacheEntry, projectIdCacheEntry; // No writes here, but since we're reading multiple values we want to get a consistent view of the cache cacheScopeReaderWriterLock.AcquireReaderLock(Timeout.Infinite); try { defaultTargetsCacheEntry = (PropertyCacheEntry)GetCacheEntry(Constants.defaultTargetCacheName); initialTargetsCacheEntry = (PropertyCacheEntry)GetCacheEntry(Constants.initialTargetCacheName); projectIdCacheEntry = (PropertyCacheEntry)GetCacheEntry(Constants.projectIdCacheName); } finally { cacheScopeReaderWriterLock.ReleaseReaderLock(); } // If we ever built anything in this project we must have the default and initial targets. if (defaultTargetsCacheEntry == null && initialTargetsCacheEntry == null) { return(null); } ErrorUtilities.VerifyThrow(projectIdCacheEntry != null, "We should always have the projectId cache entry"); ErrorUtilities.VerifyThrow(defaultTargetsCacheEntry != null && initialTargetsCacheEntry != null, "We should have both the initial and default targets in the cache"); ArrayList targetsToBuild = new ArrayList(initialTargetsCacheEntry.Value.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries)); if (buildRequest.TargetNames == null || buildRequest.TargetNames.Length == 0) { targetsToBuild.AddRange(defaultTargetsCacheEntry.Value.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries)); } else { targetsToBuild.AddRange(buildRequest.TargetNames); } // Create variable to hold the cached outputs Hashtable outputsByTargetName = new Hashtable(targetsToBuild.Count); Hashtable resultByTarget = new Hashtable(targetsToBuild.Count, StringComparer.OrdinalIgnoreCase); bool overallSuccess = true; bool missingValues = false; // No writes here, but since we're reading multiple values we want to get a consistent view of the cache cacheScopeReaderWriterLock.AcquireReaderLock(Timeout.Infinite); try { for (int i = 0; i < targetsToBuild.Count; i++) { string targetName = EscapingUtilities.UnescapeAll((string)targetsToBuild[i]); if (ContainsCacheEntry(targetName)) { BuildResultCacheEntry cacheEntry = (BuildResultCacheEntry)GetCacheEntry(targetName); overallSuccess = overallSuccess && cacheEntry.BuildResult; resultByTarget[targetName] = (cacheEntry.BuildResult) ? Target.BuildState.CompletedSuccessfully : Target.BuildState.CompletedUnsuccessfully; // Restore output items for successful targets if (cacheEntry.BuildResult) { outputsByTargetName[targetName] = cacheEntry.BuildItems; } // We found a failed target - cut the loop short else { break; } } else { missingValues = true; break; } } } finally { cacheScopeReaderWriterLock.ReleaseReaderLock(); } if (missingValues) { return(null); } actuallyBuiltTargets = targetsToBuild; return(new BuildResult(outputsByTargetName, resultByTarget, overallSuccess, buildRequest.HandleId, buildRequest.RequestId, int.Parse(projectIdCacheEntry.Value, CultureInfo.InvariantCulture), false /* use results cache */, defaultTargetsCacheEntry.Value, initialTargetsCacheEntry.Value, 0, 0, 0)); }
/// <summary> /// Creates an item with the specified include and include before wildcard expansion. /// This is to support creating items from an include that may have a wildcard expression in it. /// </summary> /// <comments> /// NOTE: defining project is ignored because we already know the ItemElement associated with /// this item, and use that for where it is defined. /// </comments> public ProjectItem CreateItem(string evaluatedIncludeEscaped, string evaluatedIncludeBeforeWildcardExpansion, string definingProject) { ErrorUtilities.VerifyThrowInternalNull(_xml, "xml"); return(new ProjectItem(_project, _xml, evaluatedIncludeEscaped, evaluatedIncludeBeforeWildcardExpansion, null /* no metadata */, null /* no inherited definition metadata */)); }
/// <summary> /// Executes the task. /// </summary> public bool Execute() { // log that we are about to spawn the task host string runtime = _taskHostParameters[XMakeAttributes.runtime]; string architecture = _taskHostParameters[XMakeAttributes.architecture]; _taskLoggingContext.LogComment(MessageImportance.Low, "ExecutingTaskInTaskHost", _taskType.Type.Name, _taskType.Assembly.AssemblyLocation, runtime, architecture); // set up the node lock (_taskHostLock) { _taskHostProvider = (NodeProviderOutOfProcTaskHost)_buildComponentHost.GetComponent(BuildComponentType.OutOfProcTaskHostNodeProvider); ErrorUtilities.VerifyThrowInternalNull(_taskHostProvider, "taskHostProvider"); } TaskHostConfiguration hostConfiguration = new TaskHostConfiguration ( _buildComponentHost.BuildParameters.NodeId, NativeMethodsShared.GetCurrentDirectory(), CommunicationsUtilities.GetEnvironmentVariables(), _buildComponentHost.BuildParameters.Culture, _buildComponentHost.BuildParameters.UICulture, #if FEATURE_APPDOMAIN _appDomainSetup, #endif BuildEngine.LineNumberOfTaskNode, BuildEngine.ColumnNumberOfTaskNode, BuildEngine.ProjectFileOfTaskNode, BuildEngine.ContinueOnError, _taskType.Type.FullName, AssemblyUtilities.GetAssemblyLocation(_taskType.Type.GetTypeInfo().Assembly), _setParameters, new Dictionary <string, string>(_buildComponentHost.BuildParameters.GlobalProperties), _taskLoggingContext.GetWarningsAsErrors(), _taskLoggingContext.GetWarningsAsMessages() ); try { lock (_taskHostLock) { _requiredContext = CommunicationsUtilities.GetHandshakeOptions(taskHost: true, taskHostParameters: _taskHostParameters); _connectedToTaskHost = _taskHostProvider.AcquireAndSetUpHost(_requiredContext, this, this, hostConfiguration); } if (_connectedToTaskHost) { try { bool taskFinished = false; while (!taskFinished) { _packetReceivedEvent.WaitOne(); INodePacket packet = null; // Handle the packet that's coming in while (_receivedPackets.TryDequeue(out packet)) { if (packet != null) { HandlePacket(packet, out taskFinished); } } } } finally { lock (_taskHostLock) { _taskHostProvider.DisconnectFromHost(_requiredContext); _connectedToTaskHost = false; } } } else { LogErrorUnableToCreateTaskHost(_requiredContext, runtime, architecture, null); } } catch (BuildAbortedException) { LogErrorUnableToCreateTaskHost(_requiredContext, runtime, architecture, null); } catch (NodeFailedToLaunchException e) { LogErrorUnableToCreateTaskHost(_requiredContext, runtime, architecture, e); } return(_taskExecutionSucceeded); }
/// <summary> /// Initialize a ProjectItemDefinitionElement instance from a node read from a project file /// </summary> internal ProjectItemDefinitionElement(XmlElement xmlElement, ProjectItemDefinitionGroupElement parent, ProjectRootElement containingProject) : base(xmlElement, parent, containingProject) { ErrorUtilities.VerifyThrowArgumentNull(parent, nameof(parent)); }
/// <summary> /// Parses the loaded xml file, creates toolSwitches and adds them to the properties list /// </summary> internal bool ParseXmlDocument(XmlDocument xmlDocument) { ErrorUtilities.VerifyThrow(xmlDocument != null, nameof(xmlDocument)); // find the root element XmlNode node = xmlDocument.FirstChild; while (!IsXmlRootElement(node)) { node = node.NextSibling; } // now we know that we've found the root; verify it is the task element // verify the namespace if (String.IsNullOrEmpty(node.NamespaceURI) || !String.Equals(node.NamespaceURI, xmlNamespace, StringComparison.OrdinalIgnoreCase)) { LogError("InvalidNamespace", xmlNamespace); return(false); } // verify that the element name is "task" if (!VerifyNodeName(node)) { LogError("MissingRootElement", relations); return(false); } else if (!VerifyAttributeExists(node, nameProperty) && !_isImport) { // we must have the name attribute if it not an import LogError("MissingAttribute", task, nameProperty); return(false); } // TODO verify resource namespace exists // we now know that that there is indeed a name attribute // assign prefix, toolname if they exist foreach (XmlAttribute attribute in node.Attributes) { if (String.Equals(attribute.Name, prefixString, StringComparison.OrdinalIgnoreCase)) { DefaultPrefix = attribute.InnerText; } else if (String.Equals(attribute.Name, toolNameString, StringComparison.OrdinalIgnoreCase)) { ToolName = attribute.InnerText; } else if (String.Equals(attribute.Name, nameProperty, StringComparison.OrdinalIgnoreCase)) { GeneratedTaskName = attribute.InnerText; } else if (String.Equals(attribute.Name, baseClassAttribute, StringComparison.OrdinalIgnoreCase)) { BaseClass = attribute.InnerText; } else if (String.Equals(attribute.Name, namespaceAttribute, StringComparison.OrdinalIgnoreCase)) { Namespace = attribute.InnerText; } else if (String.Equals(attribute.Name, resourceNamespaceAttribute, StringComparison.OrdinalIgnoreCase)) { ResourceNamespace = attribute.InnerText; } } // parse the child nodes if it has any if (node.HasChildNodes) { return(ParseSwitchGroupOrSwitch(node.FirstChild, SwitchRelationsList, null)); } else { LogError("NoChildren"); return(false); } }
private static IChannelBindingElement[] InitializeBindingElements <T>(IAssociationStore <T> associationStore, INonceStore nonceStore, SecuritySettings securitySettings, bool nonVerifying) { Contract.Requires <ArgumentNullException>(securitySettings != null); Contract.Requires <ArgumentException>(!nonVerifying || securitySettings is RelyingPartySecuritySettings); var rpSecuritySettings = securitySettings as RelyingPartySecuritySettings; var opSecuritySettings = securitySettings as ProviderSecuritySettings; ErrorUtilities.VerifyInternal(rpSecuritySettings != null || opSecuritySettings != null, "Expected an RP or OP security settings instance."); ErrorUtilities.VerifyInternal(!nonVerifying || rpSecuritySettings != null, "Non-verifying channels can only be constructed for relying parties."); bool isRelyingPartyRole = rpSecuritySettings != null; var rpAssociationStore = associationStore as IAssociationStore <Uri>; var opAssociationStore = associationStore as IAssociationStore <AssociationRelyingPartyType>; ErrorUtilities.VerifyInternal(isRelyingPartyRole || opAssociationStore != null, "Providers MUST have an association store."); SigningBindingElement signingElement; if (isRelyingPartyRole) { signingElement = nonVerifying ? null : new SigningBindingElement(rpAssociationStore); } else { signingElement = new SigningBindingElement(opAssociationStore, opSecuritySettings); } var extensionFactory = OpenIdExtensionFactoryAggregator.LoadFromConfiguration(); List <IChannelBindingElement> elements = new List <IChannelBindingElement>(8); elements.Add(new ExtensionsBindingElement(extensionFactory, securitySettings)); if (isRelyingPartyRole) { elements.Add(new RelyingPartySecurityOptions(rpSecuritySettings)); elements.Add(new BackwardCompatibilityBindingElement()); ReturnToNonceBindingElement requestNonceElement = null; if (associationStore != null) { if (nonceStore != null) { // There is no point in having a ReturnToNonceBindingElement without // a ReturnToSignatureBindingElement because the nonce could be // artificially changed without it. requestNonceElement = new ReturnToNonceBindingElement(nonceStore, rpSecuritySettings); elements.Add(requestNonceElement); } // It is important that the return_to signing element comes last // so that the nonce is included in the signature. elements.Add(new ReturnToSignatureBindingElement(rpAssociationStore, rpSecuritySettings)); } ErrorUtilities.VerifyOperation(!rpSecuritySettings.RejectUnsolicitedAssertions || requestNonceElement != null, OpenIdStrings.UnsolicitedAssertionRejectionRequiresNonceStore); } else { // Providers must always have a nonce store. ErrorUtilities.VerifyArgumentNotNull(nonceStore, "nonceStore"); } if (nonVerifying) { elements.Add(new SkipSecurityBindingElement()); } else { if (nonceStore != null) { elements.Add(new StandardReplayProtectionBindingElement(nonceStore, true)); } elements.Add(new StandardExpirationBindingElement()); elements.Add(signingElement); } return(elements.ToArray()); }
/// <summary> /// Instructs the MSBuild engine to build one or more project files whose locations are specified by the /// <see cref="Projects"/> property. /// </summary> /// <returns>true if all projects build successfully; false if any project fails</returns> public override bool Execute() { // If no projects were passed in, just return success. if ((Projects == null) || (Projects.Length == 0)) { return(true); } // We have been asked to unescape all escaped characters before processing if (this.TargetAndPropertyListSeparators != null && this.TargetAndPropertyListSeparators.Length > 0) { ExpandAllTargetsAndProperties(); } // Parse the global properties into a hashtable. Hashtable propertiesTable; if (!PropertyParser.GetTableWithEscaping(Log, ResourceUtilities.FormatResourceString("General.GlobalProperties"), "Properties", this.Properties, out propertiesTable)) { return(false); } // Parse out the properties to undefine, if any. string[] undefinePropertiesArray = null; if (!String.IsNullOrEmpty(_undefineProperties)) { Log.LogMessageFromResources(MessageImportance.Low, "General.UndefineProperties"); undefinePropertiesArray = _undefineProperties.Split(new char[] { ';' }); foreach (string property in undefinePropertiesArray) { Log.LogMessageFromText(String.Format(CultureInfo.InvariantCulture, " {0}", property), MessageImportance.Low); } } bool isRunningMultipleNodes = BuildEngine2.IsRunningMultipleNodes; // If we are in single proc mode and stopOnFirstFailure is true, we cannot build in parallel because // building in parallel sends all of the projects to the engine at once preventing us from not sending // any more projects after the first failure. Therefore, to preserve compatibility with whidby if we are in this situation disable buildInParallel. if (!isRunningMultipleNodes && _stopOnFirstFailure && _buildInParallel) { _buildInParallel = false; Log.LogMessageFromResources(MessageImportance.Low, "MSBuild.NotBuildingInParallel"); } // When the condition below is met, provide an information message indicating stopOnFirstFailure // will have no effect. The reason there will be no effect is, when buildInParallel is true // All project files will be submitted to the engine all at once, this mean there is no stopping for failures between projects. // When RunEachTargetSpearately is false, all targets will be submitted to the engine at once, this means there is no way to stop between target failures. // therefore the first failure seen will be the only failure seen. if (isRunningMultipleNodes && _buildInParallel && _stopOnFirstFailure && !_runEachTargetSeparately) { Log.LogMessageFromResources(MessageImportance.Low, "MSBuild.NoStopOnFirstFailure"); } // This is a list of string[]. That is, each element in the list is a string[]. Each // string[] represents a set of target names to build. Depending on the value // of the RunEachTargetSeparately parameter, we each just call the engine to run all // the targets together, or we call the engine separately for each target. ArrayList targetLists = CreateTargetLists(this.Targets, this.RunEachTargetSeparately); bool success = true; ITaskItem[] singleProject = null; bool[] skipProjects = null; if (_buildInParallel) { skipProjects = new bool[Projects.Length]; for (int i = 0; i < skipProjects.Length; i++) { skipProjects[i] = true; } } else { singleProject = new ITaskItem[1]; } // Read in each project file. If there are any errors opening the file or parsing the XML, // raise an event and return False. If any one of the projects fails to build, return False, // otherwise return True. If parallel build is requested we first check for file existence so // that we don't pass a non-existent file to IBuildEngine causing an exception for (int i = 0; i < Projects.Length; i++) { ITaskItem project = Projects[i]; string projectPath = FileUtilities.AttemptToShortenPath(project.ItemSpec); if (_stopOnFirstFailure && !success) { // Inform the user that we skipped the remaining projects because StopOnFirstFailure=true. Log.LogMessageFromResources(MessageImportance.Low, "MSBuild.SkippingRemainingProjects"); // We have encountered a failure. Caller has requested that we not // continue with remaining projects. break; } if (File.Exists(projectPath) || (_skipNonexistentProjects == SkipNonexistentProjectsBehavior.Build)) { if (FileUtilities.IsVCProjFilename(projectPath)) { Log.LogErrorWithCodeFromResources("MSBuild.ProjectUpgradeNeededToVcxProj", project.ItemSpec); success = false; continue; } // If we are building in parallel we want to only make one call to // ExecuteTargets once we verified that all projects exist if (!_buildInParallel) { singleProject[0] = project; if (!ExecuteTargets ( singleProject, propertiesTable, undefinePropertiesArray, targetLists, StopOnFirstFailure, RebaseOutputs, BuildEngine3, Log, _targetOutputs, _useResultsCache, _unloadProjectsOnCompletion, ToolsVersion ) ) { success = false; } } else { skipProjects[i] = false; } } else { if (_skipNonexistentProjects == SkipNonexistentProjectsBehavior.Skip) { Log.LogMessageFromResources(MessageImportance.High, "MSBuild.ProjectFileNotFoundMessage", project.ItemSpec); } else { ErrorUtilities.VerifyThrow(_skipNonexistentProjects == SkipNonexistentProjectsBehavior.Error, "skipNonexistentProjects has unexpected value {0}", _skipNonexistentProjects); Log.LogErrorWithCodeFromResources("MSBuild.ProjectFileNotFound", project.ItemSpec); success = false; } } } // We need to build all the projects that were not skipped if (_buildInParallel) { success = BuildProjectsInParallel(propertiesTable, undefinePropertiesArray, targetLists, success, skipProjects); } return(success); }
/// <summary> /// Called when the Provider is preparing to send a response to an authentication request. /// </summary> /// <param name="request">The request that is configured to generate the outgoing response.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns> /// <c>true</c> if this behavior owns this request and wants to stop other behaviors /// from handling it; <c>false</c> to allow other behaviors to process this request. /// </returns> async Task <bool> IProviderBehavior.OnOutgoingResponseAsync(Provider.IAuthenticationRequest request, CancellationToken cancellationToken) { bool result = false; // Nothing to do for negative assertions. if (!request.IsAuthenticated.Value) { return(result); } var requestInternal = (Provider.AuthenticationRequest)request; var responseMessage = (IProtocolMessageWithExtensions)await requestInternal.GetResponseAsync(cancellationToken); // Only apply our special policies if the RP requested it. var papeRequest = request.GetExtension <PolicyRequest>(); if (papeRequest != null) { var papeResponse = responseMessage.Extensions.OfType <PolicyResponse>().SingleOrDefault(); if (papeResponse == null) { request.AddResponseExtension(papeResponse = new PolicyResponse()); } if (papeRequest.PreferredPolicies.Contains(AuthenticationPolicies.USGovernmentTrustLevel1)) { result = true; if (!papeResponse.ActualPolicies.Contains(AuthenticationPolicies.USGovernmentTrustLevel1)) { papeResponse.ActualPolicies.Add(AuthenticationPolicies.USGovernmentTrustLevel1); } // The spec requires that the OP perform discovery and if that fails, it must either sternly // warn the user of a potential threat or just abort the authentication. // We can't verify that the OP displayed anything to the user at this level, but we can // at least verify that the OP performed the discovery on the realm and halt things if it didn't. ErrorUtilities.VerifyHost(requestInternal.HasRealmDiscoveryBeenPerformed, BehaviorStrings.RealmDiscoveryNotPerformed); } if (papeRequest.PreferredPolicies.Contains(AuthenticationPolicies.PrivatePersonalIdentifier)) { ErrorUtilities.VerifyProtocol(request.ClaimedIdentifier == request.LocalIdentifier, OpenIdStrings.DelegatingIdentifiersNotAllowed); // Mask the user's identity with a PPID. ErrorUtilities.VerifyHost(PpidIdentifierProvider != null, BehaviorStrings.PpidProviderNotGiven); Identifier ppidIdentifier = PpidIdentifierProvider.GetIdentifier(request.LocalIdentifier, request.Realm); requestInternal.ResetClaimedAndLocalIdentifiers(ppidIdentifier); // Indicate that the RP is receiving a PPID claimed_id if (!papeResponse.ActualPolicies.Contains(AuthenticationPolicies.PrivatePersonalIdentifier)) { papeResponse.ActualPolicies.Add(AuthenticationPolicies.PrivatePersonalIdentifier); } } if (papeRequest.PreferredPolicies.Contains(AuthenticationPolicies.NoPersonallyIdentifiableInformation)) { ErrorUtilities.VerifyProtocol( !responseMessage.Extensions.OfType <ClaimsResponse>().Any() && !responseMessage.Extensions.OfType <FetchResponse>().Any(), BehaviorStrings.PiiIncludedWithNoPiiPolicy); // If no PII is given in extensions, and the claimed_id is a PPID, then we can state we issue no PII. if (papeResponse.ActualPolicies.Contains(AuthenticationPolicies.PrivatePersonalIdentifier)) { if (!papeResponse.ActualPolicies.Contains(AuthenticationPolicies.NoPersonallyIdentifiableInformation)) { papeResponse.ActualPolicies.Add(AuthenticationPolicies.NoPersonallyIdentifiableInformation); } } } Reporting.RecordEventOccurrence(this, "OP"); } return(result); }
public TaskHostConfiguration ( int nodeId, string startupDirectory, IDictionary <string, string> buildProcessEnvironment, CultureInfo culture, CultureInfo uiCulture, #if FEATURE_APPDOMAIN AppDomainSetup appDomainSetup, #endif int lineNumberOfTask, int columnNumberOfTask, string projectFileOfTask, bool continueOnError, string taskName, string taskLocation, bool isTaskInputLoggingEnabled, IDictionary <string, object> taskParameters, Dictionary <string, string> globalParameters, ICollection <string> warningsAsErrors, ICollection <string> warningsNotAsErrors, ICollection <string> warningsAsMessages ) { ErrorUtilities.VerifyThrowInternalLength(taskName, nameof(taskName)); ErrorUtilities.VerifyThrowInternalLength(taskLocation, nameof(taskLocation)); _nodeId = nodeId; _startupDirectory = startupDirectory; if (buildProcessEnvironment != null) { _buildProcessEnvironment = buildProcessEnvironment as Dictionary <string, string>; if (_buildProcessEnvironment == null) { _buildProcessEnvironment = new Dictionary <string, string>(buildProcessEnvironment); } } _culture = culture; _uiCulture = uiCulture; #if FEATURE_APPDOMAIN _appDomainSetup = appDomainSetup; #endif _lineNumberOfTask = lineNumberOfTask; _columnNumberOfTask = columnNumberOfTask; _projectFileOfTask = projectFileOfTask; _continueOnError = continueOnError; _taskName = taskName; _taskLocation = taskLocation; _isTaskInputLoggingEnabled = isTaskInputLoggingEnabled; _warningsAsErrors = warningsAsErrors; _warningsNotAsErrors = warningsNotAsErrors; _warningsAsMessages = warningsAsMessages; if (taskParameters != null) { _taskParameters = new Dictionary <string, TaskParameter>(StringComparer.OrdinalIgnoreCase); foreach (KeyValuePair <string, object> parameter in taskParameters) { _taskParameters[parameter.Key] = new TaskParameter(parameter.Value); } } _globalParameters = globalParameters ?? new Dictionary <string, string>(); }
/// <summary> /// Sends data to the specified node. /// </summary> /// <param name="hostContext">The node to which data shall be sent.</param> /// <param name="packet">The packet to send.</param> public void SendData(TaskHostContext hostContext, INodePacket packet) { ErrorUtilities.VerifyThrow(_nodeContexts.ContainsKey(hostContext), "Invalid host context specified: {0}.", hostContext.ToString()); SendData(_nodeContexts[hostContext], packet); }
/// <summary> /// Constructor /// </summary> internal WrapperForProjectRootElement(ProjectRootElement containingProject) { ErrorUtilities.VerifyThrowInternalNull(containingProject, "containingProject"); this.ContainingProject = containingProject; }
/// <summary> /// Given a TaskHostContext, return the appropriate location of the /// executable (MSBuild or MSBuildTaskHost) that we wish to use, or null /// if that location cannot be resolved. /// </summary> internal static string GetMSBuildLocationFromHostContext(TaskHostContext hostContext) { string toolName = GetTaskHostNameFromHostContext(hostContext); string toolPath = null; s_baseTaskHostPath = BuildEnvironmentHelper.Instance.MSBuildToolsDirectory32; s_baseTaskHostPath64 = BuildEnvironmentHelper.Instance.MSBuildToolsDirectory64; switch (hostContext) { case TaskHostContext.X32CLR2: if (s_pathToX32Clr2 == null) { s_pathToX32Clr2 = Environment.GetEnvironmentVariable("MSBUILDTASKHOSTLOCATION"); if (s_pathToX32Clr2 == null || !FileUtilities.FileExistsNoThrow(Path.Combine(s_pathToX32Clr2, toolName))) { s_pathToX32Clr2 = s_baseTaskHostPath; } } toolPath = s_pathToX32Clr2; break; case TaskHostContext.X64CLR2: if (s_pathToX64Clr2 == null) { s_pathToX64Clr2 = Environment.GetEnvironmentVariable("MSBUILDTASKHOSTLOCATION64"); if (s_pathToX64Clr2 == null || !FileUtilities.FileExistsNoThrow(Path.Combine(s_pathToX64Clr2, toolName))) { s_pathToX64Clr2 = s_baseTaskHostPath64; } } toolPath = s_pathToX64Clr2; break; case TaskHostContext.X32CLR4: if (s_pathToX32Clr4 == null) { s_pathToX32Clr4 = s_baseTaskHostPath; } toolPath = s_pathToX32Clr4; break; case TaskHostContext.X64CLR4: if (s_pathToX64Clr4 == null) { s_pathToX64Clr4 = s_baseTaskHostPath64; } toolPath = s_pathToX64Clr4; break; default: ErrorUtilities.ThrowInternalErrorUnreachable(); break; } if (toolName != null && toolPath != null) { return(Path.Combine(toolPath, toolName)); } return(null); }
/// <summary> /// Dummy required implementation /// </summary> internal override void VerifyThrowInvalidOperationAcceptableLocation(ProjectElementContainer parent, ProjectElement previousSibling, ProjectElement nextSibling) { ErrorUtilities.ThrowInternalErrorUnreachable(); }
/// <summary> /// Initialize a parented ProjectOutputElement /// </summary> internal ProjectOutputElement(XmlElement xmlElement, ProjectTaskElement parent, ProjectRootElement containingProject) : base(xmlElement, parent, containingProject) { ErrorUtilities.VerifyThrowArgumentNull(parent, nameof(parent)); }
/// <summary> /// Helper unregistration method /// </summary> private bool Unregister(string assemblyPath, string typeLibPath) { ErrorUtilities.VerifyThrowArgumentNull(typeLibPath, "typeLibPath"); Log.LogMessageFromResources(MessageImportance.Low, "UnregisterAssembly.UnregisteringAssembly", assemblyPath); if (FileSystems.Default.FileExists(assemblyPath)) { try { // Load the specified assembly. Assembly asm = Assembly.UnsafeLoadFrom(assemblyPath); var comRegistrar = new RegistrationServices(); try { s_unregisteringLock.WaitOne(); // Unregister the assembly if (!comRegistrar.UnregisterAssembly(asm)) { // If the assembly doesn't contain any types that could be registered for COM interop, // warn the user about it Log.LogWarningWithCodeFromResources("UnregisterAssembly.NoValidTypes", assemblyPath); } } finally { s_unregisteringLock.ReleaseMutex(); } } catch (ArgumentNullException e) { Log.LogErrorWithCodeFromResources("UnregisterAssembly.CantUnregisterAssembly", assemblyPath, e.Message); return(false); } catch (InvalidOperationException e) { Log.LogErrorWithCodeFromResources("UnregisterAssembly.CantUnregisterAssembly", assemblyPath, e.Message); return(false); } catch (TargetInvocationException e) { Log.LogErrorWithCodeFromResources("UnregisterAssembly.CantUnregisterAssembly", assemblyPath, e.Message); return(false); } catch (IOException e) { Log.LogErrorWithCodeFromResources("UnregisterAssembly.CantUnregisterAssembly", assemblyPath, e.Message); return(false); } catch (TypeLoadException e) { Log.LogErrorWithCodeFromResources("UnregisterAssembly.CantUnregisterAssembly", assemblyPath, e.Message); return(false); } catch (UnauthorizedAccessException e) { Log.LogErrorWithCodeFromResources("UnregisterAssembly.UnauthorizedAccess", assemblyPath, e.Message); return(false); } catch (BadImageFormatException) { Log.LogErrorWithCodeFromResources("General.InvalidAssembly", assemblyPath); return(false); } catch (SecurityException e) // running as normal user { Log.LogErrorWithCodeFromResources("UnregisterAssembly.UnauthorizedAccess", assemblyPath, e.Message); return(false); } } else { Log.LogWarningWithCodeFromResources("UnregisterAssembly.UnregisterAsmFileDoesNotExist", assemblyPath); } Log.LogMessageFromResources(MessageImportance.Low, "UnregisterAssembly.UnregisteringTypeLib", typeLibPath); if (FileSystems.Default.FileExists(typeLibPath)) { try { ITypeLib typeLibrary = (ITypeLib)NativeMethods.LoadTypeLibEx(typeLibPath, (int)NativeMethods.REGKIND.REGKIND_NONE); // Get the library attributes so we can unregister it IntPtr pTlibAttr = IntPtr.Zero; try { typeLibrary.GetLibAttr(out pTlibAttr); if (pTlibAttr != IntPtr.Zero) { // Unregister the type library System.Runtime.InteropServices.ComTypes.TYPELIBATTR tlibattr = (System.Runtime.InteropServices.ComTypes.TYPELIBATTR)Marshal.PtrToStructure(pTlibAttr, typeof(System.Runtime.InteropServices.ComTypes.TYPELIBATTR)); NativeMethods.UnregisterTypeLib(ref tlibattr.guid, tlibattr.wMajorVerNum, tlibattr.wMinorVerNum, tlibattr.lcid, tlibattr.syskind); } } finally { typeLibrary.ReleaseTLibAttr(pTlibAttr); Marshal.ReleaseComObject(typeLibrary); } } catch (COMException ex) { // if the typelib to be unregistered is not registered, then we don't have anything left to do if (ex.ErrorCode == NativeMethods.TYPE_E_REGISTRYACCESS) { Log.LogWarningWithCodeFromResources("UnregisterAssembly.UnregisterTlbFileNotRegistered", typeLibPath); } // if the typelib can't be loaded (say because it's not a valid typelib file) we should report an error else if (ex.ErrorCode == NativeMethods.TYPE_E_CANTLOADLIBRARY) { Log.LogErrorWithCodeFromResources("UnregisterAssembly.UnregisterTlbCantLoadFile", typeLibPath); return(false); } // rethrow other exceptions else { #if DEBUG Debug.Assert(false, "Unexpected exception in UnregisterAssembly.DoExecute. " + "Please log a MSBuild bug specifying the steps to reproduce the problem."); #endif throw; } } } else { Log.LogMessageFromResources(MessageImportance.Low, "UnregisterAssembly.UnregisterTlbFileDoesNotExist", typeLibPath); } return(true); }
/// <summary> /// Constructor. /// Only stores file name: does not grab the file state until first request. /// </summary> internal FileState(string filename) { ErrorUtilities.VerifyThrowArgumentLength(filename, "filename"); _filename = filename; }
/// <summary> /// Determines how many times the batchable object needs to be executed (each execution is termed a "batch"), and prepares /// buckets of items to pass to the object in each batch. /// </summary> /// <param name="elementLocation"></param> /// <param name="batchableObjectParameters"></param> /// <param name="lookup"></param> /// <param name="implicitBatchableItemType">Any item type that can be considered an implicit input to this batchable object. /// This is useful for items inside targets, where the item name is plainly an item type that's an "input" to the object.</param> /// <returns>List containing ItemBucket objects, each one representing an execution batch.</returns> internal static List <ItemBucket> PrepareBatchingBuckets ( List <string> batchableObjectParameters, Lookup lookup, string implicitBatchableItemType, ElementLocation elementLocation ) { if (batchableObjectParameters == null) { ErrorUtilities.ThrowInternalError("Need the parameters of the batchable object to determine if it can be batched."); } if (lookup == null) { ErrorUtilities.ThrowInternalError("Need to specify the lookup."); } ItemsAndMetadataPair pair = ExpressionShredder.GetReferencedItemNamesAndMetadata(batchableObjectParameters); // All the @(itemname) item list references in the tag, including transforms, etc. HashSet <string> consumedItemReferences = pair.Items; // All the %(itemname.metadataname) references in the tag (not counting those embedded // inside item transforms), and note that the itemname portion is optional. // The keys in the returned hash table are the qualified metadata names (e.g. "EmbeddedResource.Culture" // or just "Culture"). The values are MetadataReference structs, which simply split out the item // name (possibly null) and the actual metadata name. Dictionary <string, MetadataReference> consumedMetadataReferences = pair.Metadata; List <ItemBucket> buckets = null; if (consumedMetadataReferences?.Count > 0) { // Add any item types that we were explicitly told to assume. if (implicitBatchableItemType != null) { consumedItemReferences ??= new HashSet <string>(MSBuildNameIgnoreCaseComparer.Default); consumedItemReferences.Add(implicitBatchableItemType); } // This method goes through all the item list references and figures out which ones // will be participating in batching, and which ones won't. We get back a hashtable // where the key is the item name that will be participating in batching. The values // are all String.Empty (not used). This method may return additional item names // that weren't represented in "consumedItemReferences"... this would happen if there // were qualified metadata references in the consumedMetadataReferences table, such as // %(EmbeddedResource.Culture). Dictionary <string, ICollection <ProjectItemInstance> > itemListsToBeBatched = GetItemListsToBeBatched(consumedMetadataReferences, consumedItemReferences, lookup, elementLocation); // At this point, if there were any metadata references in the tag, but no item // references to batch on, we've got a problem because we can't figure out which // item lists the user wants us to batch. if (itemListsToBeBatched.Count == 0) { foreach (string unqualifiedMetadataName in consumedMetadataReferences.Keys) { // Of course, since this throws an exception, there's no way we're ever going // to really loop here... it's just that the foreach is the only way I can // figure out how to get data out of the hashtable without knowing any of the // keys! ProjectErrorUtilities.VerifyThrowInvalidProject(false, elementLocation, "CannotReferenceItemMetadataWithoutItemName", unqualifiedMetadataName); } } else { // If the batchable object consumes item metadata as well as items to be batched, // we need to partition the items consumed by the object. buckets = BucketConsumedItems(lookup, itemListsToBeBatched, consumedMetadataReferences, elementLocation); } } // if the batchable object does not consume any item metadata or items, or if the item lists it consumes are all // empty, then the object does not need to be batched if ((buckets == null) || (buckets.Count == 0)) { // create a default bucket that references the project items and properties -- this way we always have a bucket buckets = new List <ItemBucket>(1); buckets.Add(new ItemBucket(null, null, lookup, buckets.Count)); } return(buckets); }