diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs index 63a575f42a2..acb3f9c1713 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs @@ -2300,6 +2300,79 @@ public void CheckLintResourceFileReferencesAreFixed ([Values (AndroidRuntime.Cor } } + [Test] + public void BuildDoesNotModifyNuGetPackageCache () + { + var proj = new XamarinAndroidApplicationProject { + IsRelease = true, + GlobalPackagesFolder = Path.Combine (Root, TestName, "packages"), + Imports = { + new Import (() => "EnableMarshalMethodsForPostLink.targets") { + TextContent = () => +""" + + + + + <_AndroidUseMarshalMethods>true + + + +""" + }, + }, + PackageReferences = { + new Package { Id = "Humanizer.Core", Version = "2.14.1" }, + new Package { Id = "Humanizer.Core.es", Version = "2.14.1" }, + }, + }; + proj.SetRuntime (AndroidRuntime.CoreCLR); + proj.SetProperty ("AndroidTypeMapImplementation", "llvm-ir"); + proj.SetProperty (KnownProperties.PublishTrimmed, true.ToString ()); + proj.MainActivity = proj.DefaultMainActivity + .Replace ("//${USINGS}", "using Humanizer;") + .Replace ("//${AFTER_ONCREATE}", "System.Console.WriteLine (System.DateTime.UtcNow.Humanize ());"); + + using var builder = CreateApkBuilder (); + var buildParameters = new [] { $"RestorePackagesPath={proj.GlobalPackagesFolder}" }; + Assert.IsTrue (builder.Restore (proj, parameters: buildParameters), "Package restore should have succeeded."); + Assert.IsTrue (builder.Build (proj, doNotCleanupOnUpdate: true, saveProject: false, parameters: buildParameters), + "Initial build should have succeeded."); + + var satelliteAssemblies = Directory.GetFiles (proj.GlobalPackagesFolder, "*.resources.dll", SearchOption.AllDirectories); + Assert.IsNotEmpty (satelliteAssemblies, "The NuGet package should contain satellite assemblies."); + + var originalWriteTimes = new Dictionary (); + foreach (string assembly in satelliteAssemblies) { + File.SetLastWriteTimeUtc (assembly, new DateTime (2000, 1, 1, 0, 0, 0, DateTimeKind.Utc)); + originalWriteTimes.Add (assembly, File.GetLastWriteTimeUtc (assembly)); + } + + var postLinkStamp = Path.Combine (Root, builder.ProjectDirectory, proj.IntermediateOutputPath, "stamp", "_AdditionalPostLinkerSteps.stamp"); + FileAssert.Exists (postLinkStamp); + File.Delete (postLinkStamp); + + // A package cache is immutable: deny write sharing and verify timestamps remain unchanged. + var packageLocks = satelliteAssemblies + .Select (assembly => File.Open (assembly, FileMode.Open, FileAccess.Read, FileShare.Read)) + .ToList (); + try { + var postLinkParameters = buildParameters.Append ("TestEnableMarshalMethodsForPostLink=true").ToArray (); + Assert.IsTrue (builder.RunTarget (proj, "_PrepareAssemblies", doNotCleanupOnUpdate: true, saveProject: false, parameters: postLinkParameters), + "Preparing assemblies should have succeeded."); + FileAssert.Exists (postLinkStamp); + foreach (string assembly in satelliteAssemblies) { + Assert.AreEqual (originalWriteTimes [assembly], File.GetLastWriteTimeUtc (assembly), $"Build should not modify '{assembly}'."); + } + } finally { + foreach (var packageLock in packageLocks) { + packageLock.Dispose (); + } + } + } + [Test] [TestCase (true, AndroidRuntime.CoreCLR)] [TestCase (false, AndroidRuntime.CoreCLR)] diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 57fa1a57afc..82c799eed84 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -1472,8 +1472,10 @@ because xbuild doesn't support framework reference assemblies. Outputs="$(_AdditionalPostLinkerStepsFlag)"> - <_AfterILLinkDestFiles Condition=" '$(_AndroidUseMarshalMethods)' != 'True' " Include="@(ResolvedAssemblies->'$(_AfterILLinkOutputDir)%(DestinationSubPath)')" /> - <_AfterILLinkDestFiles Condition=" '$(_AndroidUseMarshalMethods)' == 'True' " Include="@(ResolvedAssemblies)" /> + <_AfterILLinkSourceFiles Include="@(ResolvedAssemblies)" + Condition=" '$(_AndroidUseMarshalMethods)' != 'True' or !$([System.String]::Copy('%(ResolvedAssemblies.Filename)').ToLowerInvariant().EndsWith('.resources')) " /> + <_AfterILLinkDestFiles Condition=" '$(_AndroidUseMarshalMethods)' != 'True' " Include="@(_AfterILLinkSourceFiles->'$(_AfterILLinkOutputDir)%(DestinationSubPath)')" /> + <_AfterILLinkDestFiles Condition=" '$(_AndroidUseMarshalMethods)' == 'True' " Include="@(_AfterILLinkSourceFiles)" /> + <_AfterILLinkSourceFiles Remove="@(_AfterILLinkSourceFiles)" /> <_AfterILLinkDestFiles Remove="@(_AfterILLinkDestFiles)" />