diff --git a/src/BuildPrediction/MsBuildHelpers.cs b/src/BuildPrediction/MsBuildHelpers.cs
index f5f9c0a..b8ee2ae 100644
--- a/src/BuildPrediction/MsBuildHelpers.cs
+++ b/src/BuildPrediction/MsBuildHelpers.cs
@@ -235,16 +235,22 @@ public static bool ShouldCopyToOutputDirectory(this ProjectItemInstance item)
}
///
- /// Determins what the TargetPath metadata would be set to after calling the AssignTargetPath task.
+ /// Determines what the TargetPath metadata would be set to after calling the AssignTargetPath task.
///
///
/// See: https://github.com/microsoft/msbuild/blob/master/src/Tasks/AssignTargetPath.cs.
///
public static string GetTargetPath(this ProjectItemInstance item)
{
- string link = item.GetMetadataValue("Link");
+ // If TargetPath is already set, it takes priority.
+ string targetPath = item.GetMetadataValue("TargetPath");
+ if (!string.IsNullOrEmpty(targetPath))
+ {
+ return targetPath;
+ }
// If file has a link, use that.
+ string link = item.GetMetadataValue("Link");
if (!string.IsNullOrEmpty(link))
{
return link;
diff --git a/src/BuildPrediction/Predictors/ContentItemsPredictor.cs b/src/BuildPrediction/Predictors/ContentItemsPredictor.cs
index 9198e4c..fe4b610 100644
--- a/src/BuildPrediction/Predictors/ContentItemsPredictor.cs
+++ b/src/BuildPrediction/Predictors/ContentItemsPredictor.cs
@@ -13,6 +13,7 @@ public sealed class ContentItemsPredictor : IProjectPredictor
{
internal const string OutDirPropertyName = "OutDir";
internal const string ContentItemName = "Content";
+ internal const string ContentWithTargetPathItemName = "ContentWithTargetPath";
///
public void PredictInputsAndOutputs(
@@ -34,6 +35,21 @@ public void PredictInputsAndOutputs(
}
}
}
+
+ foreach (ProjectItemInstance item in projectInstance.GetItems(ContentWithTargetPathItemName))
+ {
+ predictionReporter.ReportInputFile(item.EvaluatedInclude);
+
+ if (!string.IsNullOrEmpty(outDir) && item.ShouldCopyToOutputDirectory())
+ {
+ // Note: Using TargetPath directly instead of GetTargetPath since ContentWithTargetPath items don't have AssignTargetPath called on them.
+ string targetPath = item.GetMetadataValue("TargetPath");
+ if (!string.IsNullOrEmpty(targetPath))
+ {
+ predictionReporter.ReportOutputFile(Path.Combine(outDir, targetPath));
+ }
+ }
+ }
}
}
}
\ No newline at end of file
diff --git a/src/BuildPrediction/Predictors/GetCopyToOutputDirectoryItemsGraphPredictor.cs b/src/BuildPrediction/Predictors/GetCopyToOutputDirectoryItemsGraphPredictor.cs
index e9176f5..a2a7b27 100644
--- a/src/BuildPrediction/Predictors/GetCopyToOutputDirectoryItemsGraphPredictor.cs
+++ b/src/BuildPrediction/Predictors/GetCopyToOutputDirectoryItemsGraphPredictor.cs
@@ -57,6 +57,7 @@ private static void PredictInputsAndOutputs(
// Process each item type considered in GetCopyToOutputDirectoryItems. Yes, Compile is considered.
ReportCopyToOutputDirectoryItemsAsInputs(dependency.ProjectInstance, ContentItemsPredictor.ContentItemName, outDir, predictionReporter);
+ ReportCopyToOutputDirectoryItemsAsInputs(dependency.ProjectInstance, ContentItemsPredictor.ContentWithTargetPathItemName, outDir, predictionReporter);
ReportCopyToOutputDirectoryItemsAsInputs(dependency.ProjectInstance, EmbeddedResourceItemsPredictor.EmbeddedResourceItemName, outDir, predictionReporter);
ReportCopyToOutputDirectoryItemsAsInputs(dependency.ProjectInstance, CompileItemsPredictor.CompileItemName, outDir, predictionReporter);
ReportCopyToOutputDirectoryItemsAsInputs(dependency.ProjectInstance, NoneItemsPredictor.NoneItemName, outDir, predictionReporter);
diff --git a/src/BuildPrediction/Predictors/GetCopyToPublishDirectoryItemsGraphPredictor.cs b/src/BuildPrediction/Predictors/GetCopyToPublishDirectoryItemsGraphPredictor.cs
index a3b390d..946cdbd 100644
--- a/src/BuildPrediction/Predictors/GetCopyToPublishDirectoryItemsGraphPredictor.cs
+++ b/src/BuildPrediction/Predictors/GetCopyToPublishDirectoryItemsGraphPredictor.cs
@@ -76,6 +76,7 @@ private static void ReportCopyToPublishDirectoryItems(
{
// Process each item type considered in GetCopyToPublishDirectoryItems. Yes, Compile is considered.
ReportCopyToPublishDirectoryItems(projectInstance, ContentItemsPredictor.ContentItemName, publishDir, predictionReporter);
+ ReportCopyToPublishDirectoryItems(projectInstance, ContentItemsPredictor.ContentWithTargetPathItemName, publishDir, predictionReporter);
ReportCopyToPublishDirectoryItems(projectInstance, EmbeddedResourceItemsPredictor.EmbeddedResourceItemName, publishDir, predictionReporter);
ReportCopyToPublishDirectoryItems(projectInstance, CompileItemsPredictor.CompileItemName, publishDir, predictionReporter);
ReportCopyToPublishDirectoryItems(projectInstance, NoneItemsPredictor.NoneItemName, publishDir, predictionReporter);
diff --git a/src/BuildPredictionTests/MsBuildHelpersTests.cs b/src/BuildPredictionTests/MsBuildHelpersTests.cs
index 6967508..9e4d500 100644
--- a/src/BuildPredictionTests/MsBuildHelpersTests.cs
+++ b/src/BuildPredictionTests/MsBuildHelpersTests.cs
@@ -34,21 +34,26 @@ public void ShouldCopyToOutputDirectory(string copyToOutputDirectoryValue, bool
[Theory]
[InlineData("Foo.xml", null, "Foo.xml")]
- [InlineData("Foo.xml", @"Bar\Baz.xml", @"Bar\Baz.xml")]
+ [InlineData("Foo.xml", @"Link=Bar\Baz.xml", @"Bar\Baz.xml")]
+ [InlineData("Foo.xml", @"TargetPath=Bar\Baz.xml;Link=ShouldNotBeUsed.xml", @"Bar\Baz.xml")]
[InlineData(@".\.\.\X\.\.\.\.\Foo.xml", null, @"X\Foo.xml")]
[InlineData(@"{ProjectDir}\X\Foo.xml", null, @"X\Foo.xml")]
[InlineData(@"{ProjectDir}\.\.\.\.\X\.\.\.\Foo.xml", null, @"X\Foo.xml")]
[InlineData(@"{ProjectDir}\..\..\..\X\Y\Z\Foo.xml", null, @"Foo.xml")]
- public void GetTargetPath(string itemIdentity, string linkValue, string expectedResult)
+ public void GetTargetPath(string itemIdentity, string properties, string expectedResult)
{
ProjectRootElement projectRootElement = ProjectRootElement.Create();
itemIdentity = itemIdentity.Replace("{ProjectDir}", projectRootElement.DirectoryPath, StringComparison.Ordinal);
ProjectItemElement item = projectRootElement.AddItem("Foo", itemIdentity);
- if (!string.IsNullOrEmpty(linkValue))
+ if (properties is not null)
{
- item.AddMetadata("Link", linkValue);
+ foreach (string property in properties.Split(';'))
+ {
+ string[] propertyParts = property.Split(['='], 2);
+ item.AddMetadata(propertyParts[0], propertyParts[1]);
+ }
}
ProjectInstance projectInstance = TestHelpers.CreateProjectInstanceFromRootElement(projectRootElement);
diff --git a/src/BuildPredictionTests/Predictors/ContentItemsPredictorTests.cs b/src/BuildPredictionTests/Predictors/ContentItemsPredictorTests.cs
index 77cc1cd..3c367b8 100644
--- a/src/BuildPredictionTests/Predictors/ContentItemsPredictorTests.cs
+++ b/src/BuildPredictionTests/Predictors/ContentItemsPredictorTests.cs
@@ -15,15 +15,25 @@ public void NoCopy()
{
ProjectRootElement projectRootElement = ProjectRootElement.Create();
projectRootElement.AddProperty(ContentItemsPredictor.OutDirPropertyName, @"bin\");
- projectRootElement.AddItem(ContentItemsPredictor.ContentItemName, "Foo.xml");
+
+ ProjectItemElement item1 = projectRootElement.AddItem(ContentItemsPredictor.ContentItemName, "Foo.xml");
+
+ ProjectItemElement item2 = projectRootElement.AddItem(ContentItemsPredictor.ContentWithTargetPathItemName, "Bar.xml");
+ item2.AddMetadata("TargetPath", @"bin\Bar.xml");
ProjectInstance projectInstance = TestHelpers.CreateProjectInstanceFromRootElement(projectRootElement);
+ PredictedItem[] expectedInputFiles =
+ [
+ new PredictedItem("Foo.xml", nameof(ContentItemsPredictor)),
+ new PredictedItem("Bar.xml", nameof(ContentItemsPredictor)),
+ ];
+
new ContentItemsPredictor()
.GetProjectPredictions(projectInstance)
.AssertPredictions(
projectInstance,
- new[] { new PredictedItem("Foo.xml", nameof(ContentItemsPredictor)) },
+ expectedInputFiles,
null,
null,
null);
@@ -35,18 +45,34 @@ public void WithCopy()
ProjectRootElement projectRootElement = ProjectRootElement.Create();
projectRootElement.AddProperty(ContentItemsPredictor.OutDirPropertyName, @"bin\");
- ProjectItemElement item = projectRootElement.AddItem(ContentItemsPredictor.ContentItemName, "Foo.xml");
- item.AddMetadata("CopyToOutputDirectory", "PreserveNewest");
+ ProjectItemElement item1 = projectRootElement.AddItem(ContentItemsPredictor.ContentItemName, "Foo.xml");
+ item1.AddMetadata("CopyToOutputDirectory", "PreserveNewest");
+
+ ProjectItemElement item2 = projectRootElement.AddItem(ContentItemsPredictor.ContentWithTargetPathItemName, "Bar.xml");
+ item2.AddMetadata("CopyToOutputDirectory", "PreserveNewest");
+ item2.AddMetadata("TargetPath", @"Bar\Bar.xml");
ProjectInstance projectInstance = TestHelpers.CreateProjectInstanceFromRootElement(projectRootElement);
+ PredictedItem[] expectedInputFiles =
+ [
+ new PredictedItem("Foo.xml", nameof(ContentItemsPredictor)),
+ new PredictedItem("Bar.xml", nameof(ContentItemsPredictor)),
+ ];
+
+ PredictedItem[] expectedOutputFiles =
+ [
+ new PredictedItem(@"bin\Foo.xml", nameof(ContentItemsPredictor)),
+ new PredictedItem(@"bin\Bar\Bar.xml", nameof(ContentItemsPredictor)),
+ ];
+
new ContentItemsPredictor()
.GetProjectPredictions(projectInstance)
.AssertPredictions(
projectInstance,
- new[] { new PredictedItem("Foo.xml", nameof(ContentItemsPredictor)) },
+ expectedInputFiles,
null,
- new[] { new PredictedItem(@"bin\Foo.xml", nameof(ContentItemsPredictor)) },
+ expectedOutputFiles,
null);
}
}