diff --git a/src/Microsoft.Android.Build.BaseTasks/Files.cs b/src/Microsoft.Android.Build.BaseTasks/Files.cs index 514448df475..2fcad10a525 100644 --- a/src/Microsoft.Android.Build.BaseTasks/Files.cs +++ b/src/Microsoft.Android.Build.BaseTasks/Files.cs @@ -609,6 +609,15 @@ public static void DeleteFile (string filename, object log) } } + public static void TryDeleteFile (string filename, Action log) + { + try { + File.Delete (filename); + } catch (Exception ex) { + log ($"Could not delete '{filename}': {ex}"); + } + } + const uint ppdb_signature = 0x424a5342; public static bool IsPortablePdb (string filename) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/Aapt2Compile.cs b/src/Xamarin.Android.Build.Tasks/Tasks/Aapt2Compile.cs index be7badb3b86..1217a5cf14a 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/Aapt2Compile.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/Aapt2Compile.cs @@ -13,6 +13,7 @@ using System.Text.RegularExpressions; using System.Collections.Generic; using Xamarin.Android.Tools; +using Xamarin.Tools.Zip; using Microsoft.Android.Build.Tasks; namespace Xamarin.Android.Tasks { @@ -22,6 +23,7 @@ public class Aapt2Compile : Aapt2 { List archives = new List (); List files = new List (); + List temporaryArchives = new List (); public string? ExtraArgs { get; set; } @@ -43,14 +45,21 @@ protected override int GetRequiredDaemonInstances () public async override System.Threading.Tasks.Task RunTaskAsync () { - await this.WhenAllWithLock (ResourcesToCompile ?? ResourceDirectories ?? [], ProcessDirectory); + try { + await this.WhenAllWithLock (ResourcesToCompile ?? ResourceDirectories ?? [], ProcessDirectory); - ProcessOutput (); + ProcessOutput (); - for (int i = archives.Count -1; i > 0; i-- ) { - if (!File.Exists (archives[i].ItemSpec)) { - archives.RemoveAt (i); + for (int i = archives.Count -1; i > 0; i-- ) { + if (!File.Exists (archives[i].ItemSpec)) { + archives.RemoveAt (i); + } } + } finally { + foreach (var archive in temporaryArchives) { + Files.TryDeleteFile (archive, LogDebugMessage); + } + temporaryArchives.Clear (); } } @@ -80,6 +89,16 @@ void ProcessDirectory (ITaskItem item, object lockObject) outputArchive = GetFullPath (targetDir); } Directory.CreateDirectory (outputArchive); + if (isDirectory && OS.IsWindows && !IsPathOnlyASCII (fileOrDirectory)) { + var temporaryArchive = Path.Combine (outputArchive, $"{Path.GetRandomFileName ()}.zip"); + lock (lockObject) + temporaryArchives.Add (temporaryArchive); + using (var zip = new ZipArchiveEx (temporaryArchive, FileMode.CreateNew)) { + zip.AddDirectory (fileOrDirectory, "res"); + } + fileOrDirectory = temporaryArchive; + isArchive = true; + } string expectedOutputFile; if (isDirectory) { if (flatFile.IsNullOrEmpty ()) @@ -89,12 +108,6 @@ void ProcessDirectory (ITaskItem item, object lockObject) filename = $"{filename}.flata"; outputArchive = Path.Combine (outputArchive, filename); expectedOutputFile = outputArchive; - string archive = item.GetMetadata (ResolveLibraryProjectImports.ResourceDirectoryArchive); - if (!archive.IsNullOrEmpty () && File.Exists (archive)) { - LogDebugMessage ($"Found Compressed Resource Archive '{archive}'."); - fileOrDirectory = archive; - isArchive = true; - } } else { if (IsInvalidFilename (fileOrDirectory)) { LogDebugMessage ($"Invalid filename, ignoring: {fileOrDirectory}"); diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CollectNonEmptyDirectories.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CollectNonEmptyDirectories.cs index 2aa7a51aede..ece37a4fe03 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CollectNonEmptyDirectories.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CollectNonEmptyDirectories.cs @@ -109,7 +109,6 @@ public override bool RunTask () } var fileTaskItem = new TaskItem (file, new Dictionary () { { "ResourceDirectory", directory.ItemSpec }, - { ResolveLibraryProjectImports.ResourceDirectoryArchive, directory.GetMetadata (ResolveLibraryProjectImports.ResourceDirectoryArchive) }, { "StampFile", generateArchive ? stampFile : file }, { "FilesCache", filesCache}, { "Hash", stampFile }, diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/ResolveLibraryProjectImports.cs b/src/Xamarin.Android.Build.Tasks/Tasks/ResolveLibraryProjectImports.cs index bb6ceac5dd8..790d853c55b 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/ResolveLibraryProjectImports.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/ResolveLibraryProjectImports.cs @@ -71,8 +71,6 @@ public class ResolveLibraryProjectImports : AndroidTask internal const string OriginalFile = "OriginalFile"; internal const string AndroidSkipResourceProcessing = "AndroidSkipResourceProcessing"; - internal const string ResourceDirectoryArchive = "ResourceDirectoryArchive"; - internal const string NuGetPackageVersion = "NuGetPackageVersion"; internal const string NuGetPackageId = "NuGetPackageId"; @@ -80,7 +78,6 @@ public class ResolveLibraryProjectImports : AndroidTask internal static readonly string [] KnownMetadata = new [] { OriginalFile, AndroidSkipResourceProcessing, - ResourceDirectoryArchive, NuGetPackageId, NuGetPackageVersion, }; @@ -121,12 +118,14 @@ public override bool RunTask () .Select (s => new TaskItem (Path.GetFullPath (Path.Combine (s.ItemSpec, "../..")) + ".stamp")) .ToArray (); - foreach (var directory in ResolvedResourceDirectories) { - Files.SetDirectoryWriteable (directory.ItemSpec); - } + if (OS.IsWindows) { + foreach (var directory in ResolvedResourceDirectories) { + Files.SetDirectoryWriteable (directory.ItemSpec); + } - foreach (var directory in ResolvedAssetDirectories) { - Files.SetDirectoryWriteable (directory.ItemSpec); + foreach (var directory in ResolvedAssetDirectories) { + Files.SetDirectoryWriteable (directory.ItemSpec); + } } if (!CacheFile.IsNullOrEmpty ()) { @@ -204,7 +203,6 @@ void Extract ( string importsDir = Path.Combine (outDirForDll, ImportsDirectory); string nativeimportsDir = Path.Combine (outDirForDll, NativeImportsDirectory); string resDir = Path.Combine (importsDir, "res"); - string resDirArchive = Path.Combine (resDir, "..", "res.zip"); string assetsDir = Path.Combine (importsDir, "assets"); string nuGetPackageId = assemblyItem.GetMetadata (NuGetPackageId) ?? ""; string nuGetPackageVersion = assemblyItem.GetMetadata (NuGetPackageVersion) ?? ""; @@ -229,7 +227,6 @@ void Extract ( if (Directory.Exists (resDir)) { var taskItem = new TaskItem (Path.GetFullPath (resDir), new Dictionary { [OriginalFile] = assemblyPath, - [ResourceDirectoryArchive] = Path.GetFullPath (resDirArchive), [NuGetPackageId] = nuGetPackageId, [NuGetPackageVersion] = nuGetPackageVersion, }); @@ -327,10 +324,8 @@ void Extract ( // which resulted in missing resource issue. // Here we replaced copy with use of '-S' option and made it to work. if (Directory.Exists (resDir)) { - CreateResourceArchive (resDir, resDirArchive); var taskItem = new TaskItem (Path.GetFullPath (resDir), new Dictionary { [OriginalFile] = assemblyPath, - [ResourceDirectoryArchive] = Path.GetFullPath (resDirArchive), [NuGetPackageId] = nuGetPackageId, [NuGetPackageVersion] = nuGetPackageVersion, }); @@ -378,7 +373,6 @@ void Extract ( string outDirForDll = Path.Combine (OutputImportDirectory, aarIdentityName); string importsDir = Path.Combine (outDirForDll, ImportsDirectory); string resDir = Path.Combine (importsDir, "res"); - string resDirArchive = Path.Combine (resDir, "..", "res.zip"); string rTxt = Path.Combine (importsDir, "R.txt"); string assetsDir = Path.Combine (importsDir, "assets"); string proguardFile = Path.Combine (importsDir, "proguard.txt"); @@ -410,7 +404,6 @@ void Extract ( resolvedResourceDirectories.Add (new TaskItem (Path.GetFullPath (resDir), new Dictionary { [OriginalFile] = Path.GetFullPath (aarFile.ItemSpec), [AndroidSkipResourceProcessing] = skipProcessing, - [ResourceDirectoryArchive] = Path.GetFullPath (resDirArchive), [NuGetPackageId] = nuGetPackageId, [NuGetPackageVersion] = nuGetPackageVersion, })); @@ -466,8 +459,6 @@ void Extract ( } } if (Directory.Exists (resDir) || File.Exists (rTxt)) { - if (Directory.Exists (resDir)) - CreateResourceArchive (resDir, resDirArchive); var skipProcessing = aarFile.GetMetadata (AndroidSkipResourceProcessing); if (skipProcessing.IsNullOrEmpty ()) { skipProcessing = "True"; @@ -475,7 +466,6 @@ void Extract ( resolvedResourceDirectories.Add (new TaskItem (Path.GetFullPath (resDir), new Dictionary { [OriginalFile] = aarFullPath, [AndroidSkipResourceProcessing] = skipProcessing, - [ResourceDirectoryArchive] = Path.GetFullPath (resDirArchive), [NuGetPackageId] = nuGetPackageId, [NuGetPackageVersion] = nuGetPackageVersion, })); @@ -496,16 +486,6 @@ void Extract ( } } - void CreateResourceArchive (string resDir, string outputFile) - { - var fileMode = File.Exists (outputFile) ? FileMode.Open : FileMode.CreateNew; - Files.ArchiveZipUpdate (outputFile, f => { - using (var zip = new ZipArchiveEx (f, fileMode)) { - zip.AddDirectory (resDir, "res"); - } - }); - } - static void AddJar (IDictionary jars, string destination, string path, string? originalFile = null, string? nuGetPackageId = null, string? nuGetPackageVersion = null) { var fullPath = Path.GetFullPath (Path.Combine (destination, path)); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/Aapt2Tests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/Aapt2Tests.cs index b9443fd44af..e45704aac2b 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/Aapt2Tests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/Aapt2Tests.cs @@ -185,10 +185,11 @@ public void Aapt2Link ([Values (true, false)] bool compilePerFile) Directory.Delete (Path.Combine (Root, path), recursive: true); } - [Test] - public void Aapt2Compile () + [TestCase ("Aapt2Compile")] + [TestCase ("Aapt2CompileÜmläüt")] + public void Aapt2Compile (string directoryName) { - var path = Path.Combine (Root, "temp", "Aapt2Compile"); + var path = Path.Combine (Root, "temp", directoryName); Directory.CreateDirectory (path); var resPath = Path.Combine (path, "res"); var archivePath = Path.Combine(path, "flata"); @@ -220,6 +221,7 @@ public void Aapt2Compile () using (var apk = ZipHelper.OpenZip (flatArchive)) { Assert.AreEqual (2, apk.EntryCount, $"{flatArchive} should have 2 entries."); } + Assert.AreEqual (0, Directory.GetFiles (path, "*.zip", SearchOption.AllDirectories).Length, "Temporary resource archives should have been deleted."); Directory.Delete (Path.Combine (Root, path), recursive: true); } diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.EmbeddedResource.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.EmbeddedResource.targets index 20a9e832858..3da2c1405da 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.EmbeddedResource.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.EmbeddedResource.targets @@ -67,10 +67,6 @@ This file is used by all project types, including binding projects. - - - Files.DeleteFile (path, "not a TaskLoggingHelper")); } + + [Test] + public void TryDeleteFile_LogsFailure () + { + var path = Path.Combine (tempDir, "directory-instead-of-file-try-delete"); + Directory.CreateDirectory (path); + string message = ""; + + Assert.DoesNotThrow (() => Files.TryDeleteFile (path, value => message = value)); + Assert.That (message, Does.Contain (path)); + } } }