Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions src/BuildPrediction/MsBuildHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -235,16 +235,22 @@ public static bool ShouldCopyToOutputDirectory(this ProjectItemInstance item)
}

/// <summary>
/// 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.
/// </summary>
/// <remarks>
/// See: https://github.com/microsoft/msbuild/blob/master/src/Tasks/AssignTargetPath.cs.
/// </remarks>
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;
Expand Down
16 changes: 16 additions & 0 deletions src/BuildPrediction/Predictors/ContentItemsPredictor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public sealed class ContentItemsPredictor : IProjectPredictor
{
internal const string OutDirPropertyName = "OutDir";
internal const string ContentItemName = "Content";
internal const string ContentWithTargetPathItemName = "ContentWithTargetPath";

/// <inheritdoc/>
public void PredictInputsAndOutputs(
Expand All @@ -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));
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
13 changes: 9 additions & 4 deletions src/BuildPredictionTests/MsBuildHelpersTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
38 changes: 32 additions & 6 deletions src/BuildPredictionTests/Predictors/ContentItemsPredictorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
}
}
Expand Down
Loading