Context: https://github.com/xamarin/xamarin-android/pull/8706/files#r1538222261
dotnet@dd1f25b
("initial" commit) had code within the `<BindingsGenerator/>` task
to parse the `generator`-emitted `.projitems` file, to read out the
`@(Compile)` group:
List<ITaskItem> files = new List<ITaskItem> ();
var doc = XDocument.Load (GeneratedFileListFile);
var compileItems = doc.XPathSelectElements ("//Project/ItemGroup/Compile");
foreach (var item in compileItems) {
var file = item.Attribute ("Include");
if (file != null && File.Exists (file.Value)) {
files.Add (new TaskItem (file.Value));
}
}
GeneratedFiles = files.ToArray ();
There were two fundamental problems with this code:
1. No XML namespaces
2. The `File.Exists()` check.
`GeneratedFileListFile` would be the `.projitems` file,
which is a normal MSBuild file with a default xmlns:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<DefineConstants>$(DefineConstants);ANDROID_1;ANDROID_2;ANDROID_3;ANDROID_4;ANDROID_5;ANDROID_6;ANDROID_7;ANDROID_8;ANDROID_9;ANDROID_10;ANDROID_11;ANDROID_12;ANDROID_13;ANDROID_14;ANDROID_15;ANDROID_16;ANDROID_17;ANDROID_18;ANDROID_19;ANDROID_20;ANDROID_21;ANDROID_22;ANDROID_23;ANDROID_24;ANDROID_25;ANDROID_26;ANDROID_27;ANDROID_28;ANDROID_29;ANDROID_30;ANDROID_31;ANDROID_32;ANDROID_33;ANDROID_34</DefineConstants>
</PropertyGroup>
<!-- Classes -->
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)E.Example.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Java.Interop.__TypeRegistrations.cs" />
<Compile Include="$(MSBuildThisFileDirectory)__NamespaceMapping__.cs" />
</ItemGroup>
<!-- Enums -->
<ItemGroup />
</Project>
The original `doc.XPathSelectElements()` expression didn't have any
XML namespaces present, so `compileItems` would always be *empty*.
This can be fixed by using an `XmlNamespaceManager`:
List<ITaskItem> files = new List<ITaskItem> ();
Log.LogDebugMessage ($"# jonp: SHOULD process {GeneratedFileListFile}");
var doc = XDocument.Load (GeneratedFileListFile);
var nsmgr = new XmlNamespaceManager(new NameTable());
nsmgr.AddNamespace ("msb", "http://schemas.microsoft.com/developer/msbuild/2003");
var compileItems = doc.XPathSelectElements ("//msb:Project/msb:ItemGroup/msb:Compile", nsmgr);
foreach (var item in compileItems) {
var file = item.Attribute ("Include");
if (file != null && File.Exists (file.Value)) {
Log.LogDebugMessage ($"# jonp: found //Compile/@include value: {file.Value}");
files.Add (new TaskItem (file.Value));
}
}
GeneratedFiles = files.ToArray ();
Now `compileItems` has elements!
Then we encounter the `File.Exists()` problem: *we* are parsing the
`.projitems` file, ***not MSBuild***, so if (when) the file contains
MSBuild-isms such as `$(MSBuildThisFileDirectory)`, those pass through
unchanged! For example, `compileItems.ElementAt(0)` would be:
<Compile Include="$(MSBuildThisFileDirectory)E.Example.cs" />
`item.Attribute("Include").Value` would be:
$(MSBuildThisFileDirectory)E.Example.cs
which means we're trying to *literally* do:
File.Exists("$(MSBuildThisFileDirectory)E.Example.cs")
No expansion is occurring.
This has (approximately) ***no*** chance of working.
At minimum we'd have to `string.Replace()` the sub-string
`$(MSBuildThisFileDirectory)` with `OutputDirectory`.
However, the fact that all the unit tests pass means one of two things:
1. We need more unit tests ;-), or
2. We don't actually need to parse the `.projitems` file.
Assume that (2) is the case: update `<BindingsGenerator/>` et al to
*remove* the processing of `.projitems`.
Does It Work™?