public void BasicProxying() { BuildItemGroup ig = new BuildItemGroup(); BuildItem i1 = new BuildItem("name1", "value1"); i1.SetMetadata("myMetaName", "myMetaValue"); BuildItem i2 = new BuildItem("name2", "value2"); ig.AddItem(i1); ig.AddItem(i2); BuildItemGroupProxy proxy = new BuildItemGroupProxy(ig); // Gather everything into our own table Hashtable list = new Hashtable(StringComparer.OrdinalIgnoreCase); foreach (DictionaryEntry item in proxy) { list.Add(item.Key, item.Value); } // Check we got all the items Assertion.AssertEquals(2, list.Count); Assertion.AssertEquals("value1", ((TaskItem)list["name1"]).ItemSpec); Assertion.AssertEquals("value2", ((TaskItem)list["name2"]).ItemSpec); // Check they have all their metadata int builtInMetadata = FileUtilities.ItemSpecModifiers.All.Length; Assertion.AssertEquals(1 + builtInMetadata, ((TaskItem)list["name1"]).MetadataCount); Assertion.AssertEquals(0 + builtInMetadata, ((TaskItem)list["name2"]).MetadataCount); Assertion.AssertEquals("myMetaValue", ((TaskItem)list["name1"]).GetMetadata("myMetaName")); }
public void CantModifyThroughEnumerator() { BuildItemGroup ig = new BuildItemGroup(); BuildItem i1 = new BuildItem("name1", "value1"); i1.SetMetadata("myMetaName", "myMetaValue"); ig.AddItem(i1); BuildItemGroupProxy proxy = new BuildItemGroupProxy(ig); Hashtable list = new Hashtable(StringComparer.OrdinalIgnoreCase); foreach (DictionaryEntry item in proxy) { list.Add(item.Key, item.Value); } // Change the item Assertion.AssertEquals("value1", ((TaskItem)list["name1"]).ItemSpec); ((TaskItem)list["name1"]).ItemSpec = "newItemSpec"; ((TaskItem)list["name1"]).SetMetadata("newMetadata", "newMetadataValue"); // We did change our copy Assertion.AssertEquals("newItemSpec", ((TaskItem)list["name1"]).ItemSpec); Assertion.AssertEquals("newMetadataValue", ((TaskItem)list["name1"]).GetMetadata("newMetadata")); Assertion.AssertEquals("myMetaValue", ((TaskItem)list["name1"]).GetMetadata("myMetaName")); // But get the item again list = new Hashtable(StringComparer.OrdinalIgnoreCase); foreach (DictionaryEntry item in proxy) { list.Add(item.Key, item.Value); } // Item value and metadata hasn't changed Assertion.AssertEquals("value1", ((TaskItem)list["name1"]).ItemSpec); Assertion.AssertEquals("", ((TaskItem)list["name1"]).GetMetadata("newMetadata")); Assertion.AssertEquals("myMetaValue", ((TaskItem)list["name1"]).GetMetadata("myMetaName")); }
private ProjectBuildState InitializeForBuildingTargets(BuildRequest buildRequest) { ProjectBuildState buildContext = null; string[] targetNamesToBuild = buildRequest.TargetNames; // Initialize to the parent requests project context id int projectContextId = buildRequest.ParentBuildEventContext.ProjectContextId; BuildEventContext buildEventContext = null; // Determine if a project started event is required to be fired, if so we may need a new projectContextId if (buildRequest.FireProjectStartedFinishedEvents) { //If we have not already used the context from the project yet, lets use that as our first event context if (!haveUsedInitialProjectContextId) { buildEventContext = projectBuildEventContext; haveUsedInitialProjectContextId = true; } else // We are going to need a new Project context Id and a new buildEventContext { projectContextId = parentEngine.GetNextProjectId(); } } if (buildEventContext == null) { buildEventContext = new BuildEventContext ( projectBuildEventContext.NodeId, projectBuildEventContext.TargetId, projectContextId, projectBuildEventContext.TaskId ); } bool exitedDueToError = true; try { // Refreshing (reevaluating) a project may end up calling ResetBuildStatus which will mark // IsReset=true. This is legitimate because when a project is being reevaluated, we want // to be explicit in saying that any targets that had run previously are no longer valid, // and we must rebuild them on the next build. this.RefreshProjectIfDirty(); // Only log the project started event after making sure the project is reevaluated if necessary, // otherwise we could log stale item/property information. if (!ParentEngine.LoggingServices.OnlyLogCriticalEvents && buildRequest.FireProjectStartedFinishedEvents) { string joinedTargetNamesToBuild = null; if (targetNamesToBuild != null && targetNamesToBuild.Length > 0) { joinedTargetNamesToBuild = EscapingUtilities.UnescapeAll(String.Join(";", targetNamesToBuild)); } // Flag the start of the project build. // // This also passes all the current properties/items and their values. The logger might want to use the // object it gets from this event to see updated property/item values later in the build: so be // careful to use the original "evaluatedProperties" and "evaluatedItems" table, not the clone // "EvaluatedProperties" or "EvaluatedItems" table. It's fine to pass these live tables, because we're // wrapping them in read-only proxies. BuildPropertyGroup propertyGroupForStartedEvent = this.evaluatedProperties; // If we are on the child process we need to fiure out which properties we need to serialize if (ParentEngine.Router.ChildMode) { // Initially set it to empty so that we do not serialize all properties if we are on a child node propertyGroupForStartedEvent = new BuildPropertyGroup(); // Get the list of properties to serialize to the parent node string[] propertyListToSerialize = parentEngine.PropertyListToSerialize; if (propertyListToSerialize != null && propertyListToSerialize.Length > 0) { foreach (string propertyToGet in propertyListToSerialize) { BuildProperty property = this.evaluatedProperties[propertyToGet]; //property can be null if propertyToGet does not exist if (property != null) { propertyGroupForStartedEvent.SetProperty(property); } } } } BuildPropertyGroupProxy propertiesProxy = new BuildPropertyGroupProxy(propertyGroupForStartedEvent); BuildItemGroupProxy itemsProxy = new BuildItemGroupProxy(this.evaluatedItems); ParentEngine.LoggingServices.LogProjectStarted(this.projectId, buildRequest.ParentBuildEventContext, buildEventContext, FullFileName, joinedTargetNamesToBuild, propertiesProxy, itemsProxy); // See comment on DefaultToolsVersion setter. if (treatinghigherToolsVersionsAs40) { ParentEngine.LoggingServices.LogComment(buildEventContext, MessageImportance.High, "TreatingHigherToolsVersionAs40", DefaultToolsVersion); } ParentEngine.LoggingServices.LogComment(buildEventContext, MessageImportance.Low, "ToolsVersionInEffectForBuild", ToolsVersion); } // Incrementing the building count. A single project may be building more than once at a time // because of callbacks by the MSBuild task. this.buildingCount++; // Because we are about to build some targets, we are no longer going to be in the "reset" // state. this.IsReset = false; // This is an ArrayList of strings, where each string is the name of a target that // we need to build. We start out by populating it with the list of targets specified // in the "InitialTargets" attribute of the <Project> node. ArrayList completeListOfTargetNamesToBuild = this.CombinedInitialTargetNames; if (buildRequest.UseResultsCache) { buildRequest.InitialTargets = string.Join(";", (string[])completeListOfTargetNamesToBuild.ToArray(typeof(string))); buildRequest.DefaultTargets = (this.DefaultBuildTargets != null) ? string.Join(";", this.DefaultBuildTargets) : string.Empty; buildRequest.ProjectId = this.projectId; } // If no targets were passed in, use the "defaultTargets" from the // project file. if ((targetNamesToBuild == null) || (targetNamesToBuild.Length == 0)) { string[] defaultTargetsToBuild = this.DefaultBuildTargets; // There wasn't at least one target in the project, then we have // a problem. ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile(defaultTargetsToBuild != null, new BuildEventFileInfo(this.FullFileName), "NoTargetSpecified"); completeListOfTargetNamesToBuild.AddRange(defaultTargetsToBuild); } else { completeListOfTargetNamesToBuild.AddRange(targetNamesToBuild); } // Check if the client requests that the project should be unloaded once it is completed needToUnloadProject = buildRequest.UnloadProjectsOnCompletion || needToUnloadProject; buildContext = new ProjectBuildState(buildRequest, completeListOfTargetNamesToBuild, buildEventContext); exitedDueToError = false; } catch (InvalidProjectFileException e) { // Make sure the Invalid Project error gets logged *before* ProjectFinished. Otherwise, // the log is confusing. this.ParentEngine.LoggingServices.LogInvalidProjectFileError(buildEventContext, e); // Mark the build request as completed and failed. The build context is either not created // or discarded buildRequest.BuildCompleted = true; buildRequest.BuildSucceeded = false; buildContext = null; } finally { if (exitedDueToError) { this.buildingCount--; if (buildRequest.FireProjectStartedFinishedEvents) { ParentEngine.LoggingServices.LogProjectFinished( buildEventContext, FullFileName, false); } } } return buildContext; }