From 8a00a8319110ab5d2b991b4d3ecd9762ff0fcb01 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Thu, 27 Sep 2018 15:18:36 -0500 Subject: [PATCH] [Xamarin.Android.Build.Tasks] CopyResource should fail with an error code Context: https://github.com/xamarin/xamarin-android/pull/609 In a recent change, we removed `StubApplication.java`, but downstream in `monodroid` we had MSBuild tasks that still expected the file to exist. We got an error such as: Xamarin.Android.Common.Debugging.targets(319,2): error MSB4018: The "CopyResource" task failed unexpectedly. Xamarin.Android.Common.Debugging.targets(319,2): error MSB4018: System.NullReferenceException: Object reference not set to an instance of an object Xamarin.Android.Common.Debugging.targets(319,2): error MSB4018: at Xamarin.Android.Tasks.CopyResource.Run (System.Reflection.Assembly assm, System.String ResourceName, System.String OutputPath, Microsoft.Build.Utilities.TaskLoggingHelper Log) [0x00058] in <5782345e71104ee895a29d54bde93c43>:0 Xamarin.Android.Common.Debugging.targets(319,2): error MSB4018: at Xamarin.Android.Tasks.CopyResource.Execute () [0x00018] in <5782345e71104ee895a29d54bde93c43>:0 Xamarin.Android.Common.Debugging.targets(319,2): error MSB4018: at Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute () [0x00023] in <528faf194f4946628868b84241d6ad15>:0 Xamarin.Android.Common.Debugging.targets(319,2): error MSB4018: at Microsoft.Build.BackEnd.TaskBuilder+d__26.MoveNext () [0x001f6] in <528faf194f4946628868b84241d6ad15>:0 The `CopyResource` MSBuild task should fail more gracefully: log a coded error, and mention the file name that was missing. In addition to this change: - Added `CopyResourceTests` to verify resources that should be working, and the error code if it fails. We should add to the list if there are other files we want to verify are working. This test is very fast (<1s for entire class), because it doesn't need to build an entire project. - Documented the `XA0116` error code. --- Documentation/guides/messages/xa0116.md | 12 +++ .../Tasks/CopyResource.cs | 6 +- .../Tasks/CopyResourceTests.cs | 73 +++++++++++++++++++ .../Xamarin.Android.Build.Tests.csproj | 1 + 4 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 Documentation/guides/messages/xa0116.md create mode 100644 src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/CopyResourceTests.cs diff --git a/Documentation/guides/messages/xa0116.md b/Documentation/guides/messages/xa0116.md new file mode 100644 index 00000000000..d1e9b60cde8 --- /dev/null +++ b/Documentation/guides/messages/xa0116.md @@ -0,0 +1,12 @@ +# Compiler Error XA0116 + +Xamarin.Android's build process extracts various `EmbeddedResource` +files from its assemblies during a build. These include internal Java +source files that are required for a Xamarin.Android application to +start successfully. A `XA0116` error would only be encountered if one +of these required files is missing. + +Consider submitting a [bug][bug] if you are getting this error under +normal circumstances. + +[bug]: https://github.com/xamarin/xamarin-android/wiki/Submitting-Bugs,-Feature-Requests,-and-Pull-Requests diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CopyResource.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CopyResource.cs index 3ffe0457eff..07211fbaf9d 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CopyResource.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CopyResource.cs @@ -34,7 +34,11 @@ public bool Run (Assembly assm, string ResourceName, string OutputPath, TaskLogg // Copy out one of our embedded resources to a path using (var from = GetManifestResourceStream (ResourceName)) { - + if (from == null) { + Log.LogCodedError ("XA0116", $"Unable to find `EmbeddedResource` of name `{ResourceName}`."); + return false; + } + // If the resource already exists, only overwrite if it's changed if (File.Exists (OutputPath)) { var hash1 = MonoAndroidHelper.HashFile (OutputPath); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/CopyResourceTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/CopyResourceTests.cs new file mode 100644 index 00000000000..418943960e6 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/CopyResourceTests.cs @@ -0,0 +1,73 @@ +using Microsoft.Build.Framework; +using NUnit.Framework; +using System.Collections.Generic; +using System.IO; +using Xamarin.Android.Tasks; + +namespace Xamarin.Android.Build.Tests +{ + [TestFixture] + public class CopyResourceTests + { + string tempFile; + List errors; + List messages; + MockBuildEngine engine; + + [SetUp] + public void Setup () + { + tempFile = Path.GetTempFileName (); + engine = new MockBuildEngine (TestContext.Out, + errors: errors = new List (), + messages: messages = new List ()); + } + + [TearDown] + public void TearDown () + { + File.Delete (tempFile); + } + + // If we remove one of these, this test should fail + static object [] EmbeddedResources = new object [] { + new object[] { "machine.config" }, + new object[] { "MonoRuntimeProvider.Bundled.java" }, + new object[] { "NotifyTimeZoneChanges.java" }, + new object[] { "Seppuku.java" }, + new object[] { "IncrementalClassLoader.java" }, + new object[] { "MultiDexLoader.java" }, + new object[] { "Placeholder.java" }, + }; + + [Test] + [TestCaseSource ("EmbeddedResources")] + public void FilesThatAreExpected (string resourceName) + { + var task = new CopyResource { + BuildEngine = engine, + ResourceName = resourceName, + OutputPath = tempFile, + }; + Assert.IsTrue (task.Execute (), "task should succeed!"); + FileAssert.Exists (tempFile); + Assert.AreNotEqual (0, new FileInfo (tempFile).Length, "file should be non-empty!"); + } + + [Test] + public void FileThatDoesNotExist () + { + var resourceName = "thisdoesnotexist"; + var task = new CopyResource { + BuildEngine = engine, + ResourceName = resourceName, + OutputPath = tempFile, + }; + Assert.IsFalse (task.Execute (), "task should fail!"); + Assert.AreEqual (1, errors.Count); + var error = errors [0]; + Assert.AreEqual ("XA0116", error.Code); + StringAssert.Contains (resourceName, error.Message); + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj index 6d37635338b..8d4b2141bed 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj @@ -82,6 +82,7 @@ +