Skip to content

Commit

Permalink
[Xamarin.Android.Build.Tasks] build.props can cause ConvertResourceCa…
Browse files Browse the repository at this point in the history
…ses to skip (#1943)

Fixes: #1933

There have been various reports of a scenario such as:
- Open a project in VS 2017, that uses uppercase letters when
  referencing a resource, such as `@drawable/IMALLCAPS`
- A Design-Time Build occurs
- Some future build later, a *regular* build fails with an `APT0000`
  error

    Resources\layout\test.axml(3,0): error APT0000: No resource found that matches the given name (at 'src' with value '@drawable/IMALLCAPS')

Once you are in this state, you are basically hosed until you
`Rebuild` or delete `obj`...

After a lot of digging, I was able to reproduce the issue by
invalidating `build.props`. This happens in a lot of common
situations:
- `$(DesignTimeBuild)` changes, such as a DTB or a regular build
- `$(AdbTarget)` changes, such as when you change the device or
  emulator you are deploying to

I created a `BuildPropsBreaksConvertResourcesCases` test that
reproduces this issue by modifying the timestamp on `build.props`.

If `build.props` was invalidated, this was happening:

    Target Name=_UpdateAndroidResgen Project=UnnamedProject.csproj
    ...
        Target Name=_GenerateAndroidResourceDir Project=UnnamedProject.csproj
            Building target "_GenerateAndroidResourceDir" completely.
            Input file "obj\Debug\build.props" is newer than output file "obj\Debug\res.flag".
            ...
                CopyIfChanged Task
                  ...
                  ModifiedFiles:
                    C:\Users\myuser\Desktop\Git\xamarin-android\bin\TestDebug\temp\BuildPropsBreaksConvertResourcesCases\obj\Debug\res\layout\main.xml
                    C:\Users\myuser\Desktop\Git\xamarin-android\bin\TestDebug\temp\BuildPropsBreaksConvertResourcesCases\obj\Debug\res\layout\test.xml
                    C:\Users\myuser\Desktop\Git\xamarin-android\bin\TestDebug\temp\BuildPropsBreaksConvertResourcesCases\obj\Debug\res\values\strings.xml

The `CopyIfChanged` task is overwriting my `test.xml` layout file with
the original file contents--which has `IMALLCAPS` in uppercase.

This would normally be OK, except `ConvertResourcesCases` skipped
processing this file!

    ConvertResourcesCases
        Parameters
            ResourceDirectories = obj\Debug\res\
            AcwMapFile = obj\Debug\acw-map.txt
            AndroidConversionFlagFile = obj\Debug\R.cs.flag
        ConvertResourcesCases Task
          ResourceDirectories: obj\Debug\res\
          AcwMapFile: obj\Debug\acw-map.txt
          AndroidConversionFlagFile: obj\Debug\R.cs.flag
          AndroidConversionFlagFile modified: 7/9/2018 7:57:56 PM
          Skipping: obj\Debug\res\layout\main.xml  7/9/2018 7:57:53 PM <= 7/9/2018 7:57:56 PM
          Skipping: obj\Debug\res\layout\test.xml  7/9/2018 7:57:53 PM <= 7/9/2018 7:57:56 PM
          Skipping: obj\Debug\res\values\strings.xml  7/9/2018 7:57:53 PM <= 7/9/2018 7:57:56 PM

Since `obj\Debug\R.cs.flag` is newer than these files, `IMALLCAPS` is
not converted to lower case!

It appears that the `CopyIfChanged` MSBuild task was not setting the
timestamps of files it copies...

After fixing this, `CopyIfChanged` does not ovewrite `test.xml` in the
first place:

    CopyIfChanged Task
      ...
      Skipping Resources\drawable-hdpi\Icon.png its up to date
      Skipping Resources\drawable-mdpi\Icon.png its up to date
      Skipping Resources\drawable-xhdpi\Icon.png its up to date
      Skipping Resources\drawable-xxhdpi\Icon.png its up to date
      Skipping Resources\drawable-xxxhdpi\Icon.png its up to date
      Skipping Resources\drawable\IMALLCAPS.png its up to date
      Skipping Resources\layout\Main.axml its up to date
      Skipping Resources\layout\test.axml its up to date
      Skipping Resources\values\Strings.xml its up to date
    ModifiedFiles:

Note that `ModifiedFiles` is blank, and my unit test now passes.
  • Loading branch information
jonathanpeppers authored Jul 9, 2018
1 parent fa4fe91 commit 7f6750f
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/Xamarin.Android.Build.Tasks/Tasks/CopyIfChanged.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ public override bool Execute ()
modifiedFiles.Add (new TaskItem (dest));
if (KeepDestinationDates)
MonoAndroidHelper.SetLastAccessAndWriteTimeUtc (dest, dstmodifiedDate, Log);
else
MonoAndroidHelper.SetLastAccessAndWriteTimeUtc (dest, DateTime.UtcNow, Log);
}

ModifiedFiles = modifiedFiles.ToArray ();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,31 @@ public void FooMethod () {
}
}

[Test]
public void BuildPropsBreaksConvertResourcesCases ()
{
var proj = new XamarinAndroidApplicationProject () {
AndroidResources = {
new AndroidItem.AndroidResource (() => "Resources\\drawable\\IMALLCAPS.png") {
BinaryContent = () => XamarinAndroidApplicationProject.icon_binary_mdpi,
},
new AndroidItem.AndroidResource ("Resources\\layout\\test.axml") {
TextContent = () => {
return "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ImageView xmlns:android=\"http://schemas.android.com/apk/res/android\" android:src=\"@drawable/IMALLCAPS\" />";
}
}
}
};
using (var b = CreateApkBuilder (Path.Combine ("temp", TestName))) {
Assert.IsTrue (b.Build (proj), "first build should have succeeded.");
//Invalidate build.props with newer timestamp, you could also modify anything in @(_PropertyCacheItems)
var props = b.Output.GetIntermediaryPath("build.props");
File.SetLastWriteTimeUtc(props, DateTime.UtcNow);
File.SetLastAccessTimeUtc(props, DateTime.UtcNow);
Assert.IsTrue (b.Build (proj), "second build should have succeeded.");
}
}

[Test]
public void CheckTimestamps ()
{
Expand Down

0 comments on commit 7f6750f

Please sign in to comment.