From c5115703f5d83b8d9efbe26a03598f072cee75a9 Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Thu, 14 Sep 2017 12:05:53 +0100 Subject: [PATCH] [Xamarin.Android.Build.Tasks] Fix Removal of Non Duplicate elements Fixes https://bugzilla.xamarin.com/show_bug.cgi?id=59473 Commit d079a42e went a bit too far when removing duplicates. It removed ANY duplicate entry that appeared anywhere in the document. What we really wanted to remove full duplicates that exist at the same level as the current element in the document. For example ```xml ``` `bar2` should NOT be removed but one of the `dupe` values should. So this commit reworks the RemoveDuplicates code to handle the correct logic. It also adds a unit test for this exact senario. --- .../ManifestTest.cs | 58 +++++++++++++++++++ .../Utilities/ManifestDocument.cs | 13 ++++- 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/ManifestTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/ManifestTest.cs index 027ee60b051..74d7c81e46f 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/ManifestTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/ManifestTest.cs @@ -544,7 +544,56 @@ public void MergeLibraryManifest () References = { new BuildItem.ProjectReference ("..\\Binding1\\Binding1.csproj", lib.ProjectGuid) }, + Packages = { + KnownPackages.SupportMediaCompat_25_4_0_1, + KnownPackages.SupportFragment_25_4_0_1, + KnownPackages.SupportCoreUtils_25_4_0_1, + KnownPackages.SupportCoreUI_25_4_0_1, + KnownPackages.SupportCompat_25_4_0_1, + KnownPackages.AndroidSupportV4_25_4_0_1, + KnownPackages.SupportV7AppCompat_25_4_0_1, + }, }; + proj.Sources.Add (new BuildItem.Source ("TestActivity1.cs") { + TextContent = () => @"using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using Android.App; +using Android.Content; +using Android.OS; +using Android.Runtime; +using Android.Views; +using Android.Widget; +using Android.Support.V4.App; +using Android.Util; +[Activity (Label = ""TestActivity1"")] +[IntentFilter (new[]{Intent.ActionMain}, Categories = new[]{ ""com.xamarin.sample"" })] +public class TestActivity1 : FragmentActivity { +} + ", + }); + proj.Sources.Add (new BuildItem.Source ("TestActivity2.cs") { + TextContent = () => @"using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using Android.App; +using Android.Content; +using Android.OS; +using Android.Runtime; +using Android.Views; +using Android.Widget; +using Android.Support.V4.App; +using Android.Util; +[Activity (Label = ""TestActivity2"")] +[IntentFilter (new[]{Intent.ActionMain}, Categories = new[]{ ""com.xamarin.sample"" })] +public class TestActivity2 : FragmentActivity { +} + ", + }); using (var libbuilder = CreateDllBuilder (Path.Combine (path, "Binding1"))) { Assert.IsTrue (libbuilder.Build (lib), "Build should have succeeded."); using (var builder = CreateApkBuilder (Path.Combine (path, "App1"))) { @@ -558,6 +607,15 @@ public void MergeLibraryManifest () ".internal.FacebookInitProvider was not replaced with com.xamarin.test.internal.FacebookInitProvider"); Assert.AreEqual (manifest.IndexOf ("meta-data", StringComparison.OrdinalIgnoreCase), manifest.LastIndexOf ("meta-data", StringComparison.OrdinalIgnoreCase), "There should be only one meta-data element"); + + var doc = XDocument.Parse (manifest); + var ns = XNamespace.Get ("http://schemas.android.com/apk/res/android"); + + var activities = doc.Element ("manifest")?.Element ("application")?.Elements ("activity"); + var e = activities.FirstOrDefault (x => x.Attribute (ns.GetName ("label"))?.Value == "TestActivity2"); + Assert.IsNotNull (e, "Manifest should contain an activity for TestActivity2"); + Assert.IsNotNull (e.Element ("intent-filter"), "TestActivity2 should have an intent-filter"); + Assert.IsNotNull (e.Element ("intent-filter").Element ("action"), "TestActivity2 should have an intent-filter/action"); } } } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs index fedbec144ab..5e48d52badb 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs @@ -402,11 +402,18 @@ void MergeLibraryManifest (string mergedManifest) } } + public IEnumerable ResolveDuplicates (IEnumerable elements) + { + foreach (var e in elements) + foreach (var d in ResolveDuplicates (e.Elements ())) + yield return d; + foreach (var d in elements.GroupBy (x => x.ToFullString ()).SelectMany (x => x.Skip (1))) + yield return d; + } + void RemoveDuplicateElements () { - var duplicates = doc.Descendants () - .GroupBy (x => x.ToFullString ()) - .SelectMany (x => x.Skip (1)); + var duplicates = ResolveDuplicates (doc.Elements ()); foreach (var duplicate in duplicates) duplicate.Remove ();