.. item.
If we have a project, that sets some properties or items at runtime,
like in a target:
```
<Target Name="Build">
<PropertyGroup>
<Bar>Bar01</Bar>
</PropertyGroup>
```
.. such a property can be accessed as `$(Bar)` subsequently.
Then at later point, a target tries to update metadata on an item group
with existing items, like:
```
<ItemGroup>
<FooItem Include="xyz" />
</ItemGroup>
<Target Name="Foo">
<ItemGroup>
<FooItem>
<SomeMetadata>MetadataValue</SomeMetadata>
</FooItem>
</ItemGroup>
```
.. then it is seen that the value for the earlier created `$(Bar)` disappears!
So, if we try to print the value of `$(Bar)` right after that item
group, it would appear as `''`!
The issue is that the metadata update in target `Foo` caused the project
to get re-evaluated, which meant that items/properites created after the
project load were lost! We should not be reevaluating the project when
setting metadata on the basis of dynamic items, like in the target
`Foo`.
These dynamic item groups in a target are represented as
`BuildItemTask`, and these create BuildItems which have their
`IsDynamic` property set. And this is used to avoid re-evaluating the
project in `BuildItem.SetMetadata`.
But when updating metadata (`BuildItem.UpdateMetadata`), we need to
update metadata on the *existing* items, which might not have been
created from such dynamic item groups! So, their `IsDynamic==false`.
Hence, trying to `SetMetadata` on such items would cause the project to
be reevaluated, and thus properties/items like `$(Bar)` would be lost!
Fixes: https://bugzilla.xamarin.com/show_bug.cgi?id=45137
In this particular case, `Bar` was the `DesignTimeBuild` property, which
was losing it's value when `ProjectReference`'s `AdditionalProperties`
metadata was set in:
```
<Target Name="BclBuildAddProjectReferenceProperties"
<ItemGroup>
<ProjectReference>
<AdditionalProperties>$(_BclBuildProjectReferenceProperties);%(ProjectReference.AdditionalProperties)</AdditionalProperties>
</ProjectReference>
</ItemGroup>
```
public void SetMetadata (string metadataName,
string metadataValue,
bool treatMetadataValueAsLiteral)
public void SetMetadata (string metadataName,
string metadataValue,
bool treatMetadataValueAsLiteral)
+ {
+ SetMetadata (metadataName, metadataValue, treatMetadataValueAsLiteral, false);
+ }
+
+ void SetMetadata (string metadataName,
+ string metadataValue,
+ bool treatMetadataValueAsLiteral,
+ bool fromDynamicItem)
{
if (metadataName == null)
throw new ArgumentNullException ("metadataName");
{
if (metadataName == null)
throw new ArgumentNullException ("metadataName");
} else if (HasParentItem) {
if (parent_item.child_items.Count > 1)
SplitParentItem ();
} else if (HasParentItem) {
if (parent_item.child_items.Count > 1)
SplitParentItem ();
- parent_item.SetMetadata (metadataName, metadataValue, treatMetadataValueAsLiteral);
+ parent_item.SetMetadata (metadataName, metadataValue, treatMetadataValueAsLiteral, fromDynamicItem);
- if (FromXml || HasParentItem) {
+
+ // We don't want to reevalute the project for dynamic items
+ if (!fromDynamicItem && !IsDynamic && (FromXml || HasParentItem)) {
parent_item_group.ParentProject.MarkProjectAsDirty ();
parent_item_group.ParentProject.NeedToReevaluate ();
}
parent_item_group.ParentProject.MarkProjectAsDirty ();
parent_item_group.ParentProject.NeedToReevaluate ();
}
continue;
foreach (string name in evaluatedMetadata.Keys) {
continue;
foreach (string name in evaluatedMetadata.Keys) {
- item.SetMetadata (name, (string)evaluatedMetadata [name]);
+ item.SetMetadata (name, (string)evaluatedMetadata [name], false, IsDynamic);
}
AddAndRemoveMetadata (project, item);
}
AddAndRemoveMetadata (project, item);
+ [Test]
+ public void ItemGroupInsideTarget_UpdateMetadata ()
+ {
+ ItemGroupInsideTarget (
+ @"<Project ToolsVersion=""4.0"" xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
+ <ItemGroup>
+ <ProjectReference Include='xyz'/>
+ </ItemGroup>
+
+ <Target Name='Main' DependsOnTargets='CreateBar'>
+ <Message Text='Before: $(Bar)'/>
+ <ItemGroup>
+ <ProjectReference>
+ <AdditionalProperties>A=b</AdditionalProperties>
+ </ProjectReference>
+ </ItemGroup>
+ <Message Text='After: $(Bar)'/>
+ </Target>
+
+ <Target Name='CreateBar'>
+ <PropertyGroup>
+ <Bar>Bar01</Bar>
+ </PropertyGroup>
+ </Target>
+ </Project>", 2, "Before: Bar01", "After: Bar01");
+ }
+
[Test]
public void ItemGroupInsideTarget_Batching ()
{
[Test]
public void ItemGroupInsideTarget_Batching ()
{