diff --git a/dotnet/targets/Xamarin.Shared.Sdk.targets b/dotnet/targets/Xamarin.Shared.Sdk.targets index ddae59a13225..e749aa34a3c6 100644 --- a/dotnet/targets/Xamarin.Shared.Sdk.targets +++ b/dotnet/targets/Xamarin.Shared.Sdk.targets @@ -226,6 +226,7 @@ _ErrorRuntimeIdentifiersClash; + BuildOnlySettings; _CollectBundleResources; _RunRidSpecificBuild; _DetectAppManifest; diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/CollectBundleResources.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/CollectBundleResources.cs index 29a43f17e7f3..5edbf00000be 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/CollectBundleResources.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/CollectBundleResources.cs @@ -1,6 +1,8 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Collections.Generic; +using System.Linq; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; @@ -31,6 +33,8 @@ public class CollectBundleResources : XamarinTask, ICancelableTask { [Output] public ITaskItem [] BundleResourcesWithLogicalNames { get; set; } = Array.Empty (); + public ITaskItem [] UnpackedResources { get; set; } = Array.Empty (); + #endregion static bool CanOptimize (string path) @@ -68,37 +72,8 @@ bool ExecuteImpl () var bundleResources = new List (); foreach (var item in BundleResources) { - // Skip anything with the PublishFolderType metadata, these are copied directly to the ResolvedFileToPublish item group instead. - var publishFolderType = item.GetMetadata ("PublishFolderType"); - if (!string.IsNullOrEmpty (publishFolderType)) - continue; - - var logicalName = BundleResource.GetLogicalName (ProjectDir, prefixes, item, !string.IsNullOrEmpty (SessionId)); - // We need a physical path here, ignore the Link element - var path = item.GetMetadata ("FullPath"); - - if (!File.Exists (path)) { - Log.LogError (MSBStrings.E0099, logicalName, path); - continue; - } - - if (logicalName.StartsWith (".." + Path.DirectorySeparatorChar, StringComparison.Ordinal)) { - Log.LogError (null, null, null, item.ItemSpec, 0, 0, 0, 0, MSBStrings.E0100, logicalName); - continue; - } - - if (logicalName == "Info.plist") { - Log.LogWarning (null, null, null, item.ItemSpec, 0, 0, 0, 0, MSBStrings.E0101); + if (!TryCreateItemWithLogicalName (this, item, ProjectDir, prefixes, SessionId, out var bundleResource)) continue; - } - - if (BundleResource.IsIllegalName (logicalName, out var illegal)) { - Log.LogError (null, null, null, item.ItemSpec, 0, 0, 0, 0, MSBStrings.E0102, illegal); - continue; - } - - var bundleResource = new TaskItem (item); - bundleResource.SetMetadata ("LogicalName", logicalName); bool optimize = false; @@ -122,11 +97,51 @@ bool ExecuteImpl () bundleResources.Add (bundleResource); } + bundleResources.AddRange (UnpackedResources); + BundleResourcesWithLogicalNames = bundleResources.ToArray (); return !Log.HasLoggedErrors; } + public static bool TryCreateItemWithLogicalName (Task task, ITaskItem item, string projectDir, IList prefixes, string sessionId, [NotNullWhen (true)] out TaskItem? itemWithLogicalName) + { + itemWithLogicalName = null; + + // Skip anything with the PublishFolderType metadata, these are copied directly to the ResolvedFileToPublish item group instead. + var publishFolderType = item.GetMetadata ("PublishFolderType"); + if (!string.IsNullOrEmpty (publishFolderType)) + return false; + + var logicalName = BundleResource.GetLogicalName (projectDir, prefixes, item, !string.IsNullOrEmpty (sessionId)); + // We need a physical path here, ignore the Link element + var path = item.GetMetadata ("FullPath"); + + if (!File.Exists (path)) { + task.Log.LogError (MSBStrings.E0099, logicalName, path); + return false; + } + + if (logicalName.StartsWith (".." + Path.DirectorySeparatorChar, StringComparison.Ordinal)) { + task.Log.LogError (null, null, null, item.ItemSpec, 0, 0, 0, 0, MSBStrings.E0100, logicalName); + return false; + } + + if (logicalName == "Info.plist") { + task.Log.LogWarning (null, null, null, item.ItemSpec, 0, 0, 0, 0, MSBStrings.E0101); + return false; + } + + if (BundleResource.IsIllegalName (logicalName, out var illegal)) { + task.Log.LogError (null, null, null, item.ItemSpec, 0, 0, 0, 0, MSBStrings.E0102, illegal); + return false; + } + + itemWithLogicalName = new TaskItem (item); + itemWithLogicalName.SetMetadata ("LogicalName", logicalName); + return true; + } + public void Cancel () { if (ShouldExecuteRemotely ()) diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/CollectPackLibraryResources.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/CollectPackLibraryResources.cs new file mode 100644 index 000000000000..aca64d8a7907 --- /dev/null +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/CollectPackLibraryResources.cs @@ -0,0 +1,86 @@ +using System; +using System.IO; +using System.Collections.Generic; + +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using Xamarin.Localization.MSBuild; +using Xamarin.Messaging.Build.Client; + +namespace Xamarin.MacDev.Tasks { + // This task will collect several item groups with various types of assets/resources, + // add/compute the LogicalName value for each of them, and then add them to the + // ItemsWithLogicalNames item group. The items in this item group will have the + // 'OriginalItemGroup' metadata set indicating where they came from. + public class CollectPackLibraryResources : XamarinTask { + #region Inputs + + public ITaskItem [] AtlasTextures { get; set; } = Array.Empty (); + + public ITaskItem [] BundleResources { get; set; } = Array.Empty (); + + public ITaskItem [] ImageAssets { get; set; } = Array.Empty (); + + public ITaskItem [] InterfaceDefinitions { get; set; } = Array.Empty (); + + public ITaskItem [] ColladaAssets { get; set; } = Array.Empty (); + + public ITaskItem [] CoreMLModels { get; set; } = Array.Empty (); + + public ITaskItem [] PartialAppManifests { get; set; } = Array.Empty (); + + public ITaskItem [] SceneKitAssets { get; set; } = Array.Empty (); + + [Required] + public string ProjectDir { get; set; } = string.Empty; + + [Required] + public string ResourcePrefix { get; set; } = string.Empty; + + #endregion + + #region Outputs + + // These items will have the following metadata set: + // * LogicalName + // * OriginalItemGroup: the name of the originating item group + [Output] + public ITaskItem [] ItemsWithLogicalNames { get; set; } = Array.Empty (); + + #endregion + + public override bool Execute () + { + var prefixes = BundleResource.SplitResourcePrefixes (ResourcePrefix); + var rv = new List (); + + var resources = new [] { + new { Name = "AtlasTexture", Items = AtlasTextures }, + new { Name = "BundleResource", Items = BundleResources }, + new { Name = "Collada", Items = ColladaAssets }, + new { Name = "CoreMLModel", Items = CoreMLModels }, + new { Name = "ImageAsset", Items = ImageAssets }, + new { Name = "InterfaceDefinition", Items = InterfaceDefinitions }, + new { Name = "PartialAppManifest", Items = PartialAppManifests }, + new { Name = "SceneKitAsset", Items = SceneKitAssets }, + }; + + foreach (var kvp in resources) { + var itemName = kvp.Name; + var items = kvp.Items; + + foreach (var item in items) { + if (!CollectBundleResources.TryCreateItemWithLogicalName (this, item, ProjectDir, prefixes, SessionId, out var itemWithLogicalName)) + continue; + + itemWithLogicalName.SetMetadata ("OriginalItemGroup", itemName); + rv.Add (itemWithLogicalName); + } + } + + ItemsWithLogicalNames = rv.ToArray (); + + return !Log.HasLoggedErrors; + } + } +} diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/CompileSceneKitAssets.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/CompileSceneKitAssets.cs index f7209f6a5a0a..afb0f4b6d253 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/CompileSceneKitAssets.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/CompileSceneKitAssets.cs @@ -118,6 +118,14 @@ Task CopySceneKitAssets (string scnassets, string output, string intermediate) return ExecuteAsync (GetFullPathToTool (), args, sdkDevPath: SdkDevPath, environment: environment, showErrorIfFailure: true); } + static bool TryGetScnAssetsPath (string file, out string scnassets) + { + scnassets = file; + while (scnassets.Length > 0 && Path.GetExtension (scnassets).ToLowerInvariant () != ".scnassets") + scnassets = Path.GetDirectoryName (scnassets); + return scnassets.Length > 0; + } + public override bool Execute () { if (ShouldExecuteRemotely ()) { @@ -141,15 +149,9 @@ public override bool Execute () continue; // get the .scnassets directory path - var scnassets = Path.GetDirectoryName (asset.ItemSpec); - while (scnassets.Length > 0 && Path.GetExtension (scnassets).ToLowerInvariant () != ".scnassets") - scnassets = Path.GetDirectoryName (scnassets); - - if (scnassets.Length == 0) + if (!TryGetScnAssetsPath (asset.ItemSpec, out var scnassets)) continue; - asset.RemoveMetadata ("LogicalName"); - var bundleName = BundleResource.GetLogicalName (ProjectDir, prefixes, asset, !string.IsNullOrEmpty (SessionId)); var output = new TaskItem (Path.Combine (intermediate, bundleName)); @@ -160,6 +162,13 @@ public override bool Execute () // .. but we really want it to be for @scnassets, so set ItemSpec accordingly scnassetsItem.ItemSpec = scnassets; + // .. and set LogicalName, the original one is for @asset + if (!TryGetScnAssetsPath (bundleName, out var logicalScnAssetsPath)) { + Log.LogError (null, null, null, asset.ItemSpec, $"Unable to compute the path of the *.scnassets path from the item's LogicalName '{bundleName}'"); + continue; + } + scnassetsItem.SetMetadata ("LogicalName", logicalScnAssetsPath); + // .. and remove the @OriginalItemSpec which is for @asset scnassetsItem.RemoveMetadata ("OriginalItemSpec"); diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/CoreMLCompiler.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/CoreMLCompiler.cs index 24295c4fe955..d76266548d29 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/CoreMLCompiler.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/CoreMLCompiler.cs @@ -167,6 +167,9 @@ public override bool Execute () var bundleResources = new List (); var partialPlists = new List (); + // Log.LogWarning ($"IntermediateOutputPath: {IntermediateOutputPath}"); + // Log.LogWarning ($"CoreML output dir: {coremlcOutputDir}"); + if (Models.Length > 0) { Directory.CreateDirectory (coremlcOutputDir); diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/CreateEmbeddedResources.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/CreateEmbeddedResources.cs index 2a17ff59e898..c1da950e5fb7 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/CreateEmbeddedResources.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/CreateEmbeddedResources.cs @@ -17,35 +17,8 @@ public class CreateEmbeddedResources : XamarinTask { [Output] public ITaskItem [] EmbeddedResources { get; set; } = Array.Empty (); - static string EscapeMangledResource (string name) - { - var mangled = new StringBuilder (); - - for (int i = 0; i < name.Length; i++) { - switch (name [i]) { - case '\\': mangled.Append ("_b"); break; - case '/': mangled.Append ("_f"); break; - case '_': mangled.Append ("__"); break; - default: mangled.Append (name [i]); break; - } - } - - return mangled.ToString (); - } - public override bool Execute () { - if (ShouldExecuteRemotely ()) { - foreach (var bundleResource in this.BundleResources) { - var logicalName = bundleResource.GetMetadata ("LogicalName"); - - if (!string.IsNullOrEmpty (logicalName)) { - logicalName = logicalName.Replace ("\\", "/"); - bundleResource.SetMetadata ("LogicalName", logicalName); - } - } - } - EmbeddedResources = new ITaskItem [BundleResources.Length]; for (int i = 0; i < BundleResources.Length; i++) { @@ -56,7 +29,7 @@ public override bool Execute () bundleResource.CopyMetadataTo (embeddedResource); // mangle the resource name - var logicalName = "__" + Prefix + "_content_" + EscapeMangledResource (bundleResource.GetMetadata ("LogicalName")); + var logicalName = "__" + Prefix + "_content_" + PackLibraryResources.EscapeMangledResource (bundleResource.GetMetadata ("LogicalName")); embeddedResource.SetMetadata ("LogicalName", logicalName); // add it to the output connection diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/PackLibraryResources.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/PackLibraryResources.cs index fad793f7a11a..ccb7e0320110 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/PackLibraryResources.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/PackLibraryResources.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using System.Collections.Generic; @@ -17,6 +18,8 @@ public class PackLibraryResources : XamarinTask, ITaskCallback, ICancelableTask public ITaskItem [] BundleResourcesWithLogicalNames { get; set; } = Array.Empty (); + public ITaskItem [] BundleOriginalResourcesWithLogicalNames { get; set; } = Array.Empty (); + #endregion #region Outputs @@ -26,14 +29,14 @@ public class PackLibraryResources : XamarinTask, ITaskCallback, ICancelableTask #endregion - static string EscapeMangledResource (string name) + public static string EscapeMangledResource (string name) { var mangled = new StringBuilder (); for (int i = 0; i < name.Length; i++) { switch (name [i]) { - case '\\': mangled.Append ("_b"); break; - case '/': mangled.Append ("_f"); break; + case '\\': + case '/': mangled.Append ("_s"); break; case '_': mangled.Append ("__"); break; default: mangled.Append (name [i]); break; } @@ -42,43 +45,8 @@ static string EscapeMangledResource (string name) return mangled.ToString (); } - bool ExecuteRemotely () - { - // Fix LogicalName path for the Mac - foreach (var resource in BundleResourcesWithLogicalNames) { - var logicalName = resource.GetMetadata ("LogicalName"); - - if (!string.IsNullOrEmpty (logicalName)) { - resource.SetMetadata ("LogicalName", logicalName.Replace ("\\", "/")); - } - } - - var runner = new TaskRunner (SessionId, BuildEngine4); - - try { - var result = runner.RunAsync (this).Result; - - if (result && EmbeddedResources is not null) { - // We must get the "real" file that will be embedded in the - // compiled assembly in Windows - foreach (var embeddedResource in EmbeddedResources.Where (x => runner.ShouldCopyItemAsync (task: this, item: x).Result)) { - runner.GetFileAsync (this, embeddedResource.ItemSpec).Wait (); - } - } - - return result; - } catch (Exception ex) { - Log.LogErrorFromException (ex); - - return false; - } - } - public override bool Execute () { - if (ShouldExecuteRemotely ()) - return ExecuteRemotely (); - var results = new List (); foreach (var item in BundleResourcesWithLogicalNames) { @@ -96,11 +64,32 @@ public override bool Execute () results.Add (embedded); } + foreach (var item in BundleOriginalResourcesWithLogicalNames) { + var originalItemGroup = item.GetMetadata ("OriginalItemGroup"); + if (!TryGetMangledLogicalName (item, originalItemGroup, out var mangledLogicalName)) + continue; + var embedded = new TaskItem (item); + embedded.SetMetadata ("LogicalName", mangledLogicalName); + results.Add (embedded); + } + EmbeddedResources = results.ToArray (); return !Log.HasLoggedErrors; } + bool TryGetMangledLogicalName (ITaskItem item, string itemName, [NotNullWhen (true)] out string? mangled) + { + var logicalName = item.GetMetadata ("LogicalName"); + if (string.IsNullOrEmpty (logicalName)) { + Log.LogError (null, null, null, item.ItemSpec, 0, 0, 0, 0, MSBStrings.E0161); + mangled = null; + return false; + } + mangled = "__" + Prefix + "_item_" + itemName + "_" + EscapeMangledResource (logicalName); + return true; + } + public void Cancel () { if (ShouldExecuteRemotely ()) diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/TextureAtlas.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/TextureAtlas.cs index e4fff3152ea6..118fd642adec 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/TextureAtlas.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/TextureAtlas.cs @@ -8,16 +8,13 @@ using Xamarin.MacDev; using Xamarin.Messaging.Build.Client; -// Disable until we get around to enable + fix any issues. -#nullable disable - namespace Xamarin.MacDev.Tasks { public class TextureAtlas : XcodeToolTaskBase, ICancelableTask { - readonly Dictionary> atlases = new Dictionary> (); + readonly Dictionary Items)> atlases = new (); #region Inputs - public ITaskItem [] AtlasTextures { get; set; } + public ITaskItem [] AtlasTextures { get; set; } = Array.Empty (); #endregion @@ -31,6 +28,7 @@ protected override string ToolName { protected override void AppendCommandLineArguments (IDictionary environment, CommandLineBuilder args, ITaskItem input, ITaskItem output) { + Log.LogWarning ($"AppendCommandLineArguments ({input.ItemSpec}, {output.ItemSpec}) => {input.GetMetadata ("FullPath")} {output.GetMetadata ("FullPath")}"); args.AppendFileNameIfNotNull (input.GetMetadata ("FullPath")); args.AppendFileNameIfNotNull (Path.GetDirectoryName (output.GetMetadata ("FullPath"))); } @@ -38,7 +36,9 @@ protected override void AppendCommandLineArguments (IDictionary protected override string GetBundleRelativeOutputPath (IList prefixes, ITaskItem input) { // Note: if the relative input dir is "relative/texture.atlas", then the relative output path will be "relative/texture.atlasc" - return Path.ChangeExtension (base.GetBundleRelativeOutputPath (prefixes, input), ".atlasc"); + var rv = Path.ChangeExtension (base.GetBundleRelativeOutputPath (prefixes, input), ".atlasc"); + Log.LogWarning ($"GetBundleRelativeOutputPath ({input.ItemSpec}) => {rv}"); + return rv; } protected override IEnumerable GetCompiledBundleResources (ITaskItem input, ITaskItem output) @@ -58,6 +58,8 @@ protected override IEnumerable GetCompiledBundleResources (ITaskItem item.SetMetadata ("LogicalName", logical); item.SetMetadata ("Optimize", "false"); + Log.LogWarning ($"GetCompiledBundleResources ({input.ItemSpec}, {output.ItemSpec}) => {item.ItemSpec} LogicalName={logical}"); + yield return item; } @@ -71,7 +73,7 @@ protected override bool NeedsBuilding (ITaskItem input, ITaskItem output) if (!File.Exists (plist)) return true; - var items = atlases [input.ItemSpec]; + var items = atlases [input.ItemSpec].Items; foreach (var item in items) { if (File.GetLastWriteTimeUtc (item.ItemSpec) > File.GetLastWriteTimeUtc (plist)) @@ -87,20 +89,28 @@ protected override IEnumerable EnumerateInputs () yield break; // group the atlas textures by their parent .atlas directories + var prefixes = BundleResource.SplitResourcePrefixes (ResourcePrefix); foreach (var item in AtlasTextures) { var atlas = Path.GetDirectoryName (BundleResource.GetVirtualProjectPath (ProjectDir, item, !string.IsNullOrEmpty (SessionId))); - List items; - if (!atlases.TryGetValue (atlas, out items)) { - items = new List (); - atlases.Add (atlas, items); + if (!atlases.TryGetValue (atlas, out var tuple)) { + tuple.Items = new List (); + var itemLogicalName = BundleResource.GetLogicalName (ProjectDir, prefixes, item, !string.IsNullOrEmpty (SessionId)); + tuple.LogicalName = Path.GetDirectoryName (itemLogicalName); + atlases.Add (atlas, tuple); } + var items = tuple.Items; items.Add (item); } - foreach (var atlas in atlases.Keys) - yield return new TaskItem (atlas); + foreach (var kvp in atlases) { + var atlas = kvp.Key; + var logicalName = kvp.Value.LogicalName; + var rv = new TaskItem (atlas); + rv.SetMetadata ("LogicalName", logicalName); + yield return rv; + } yield break; } diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/UnpackLibraryResources.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/UnpackLibraryResources.cs index a82dff8a8e43..f01c342e92f0 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/UnpackLibraryResources.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/UnpackLibraryResources.cs @@ -49,8 +49,40 @@ public class UnpackLibraryResources : XamarinTask, ITaskCallback, ICancelableTas [Output] public ITaskItem [] UnpackedResources { get; set; } = Array.Empty (); + [Output] + public ITaskItem [] AtlasTextures { get; set; } = Array.Empty (); + + [Output] + public ITaskItem [] ColladaAssets { get; set; } = Array.Empty (); + + [Output] + public ITaskItem [] CoreMLModels { get; set; } = Array.Empty (); + + [Output] + public ITaskItem [] ImageAssets { get; set; } = Array.Empty (); + + [Output] + public ITaskItem [] InterfaceDefinitions { get; set; } = Array.Empty (); + + [Output] + public ITaskItem [] PartialAppManifests { get; set; } = Array.Empty (); + + [Output] + public ITaskItem [] SceneKitAssets { get; set; } = Array.Empty (); + #endregion + enum ResourceType { + AtlasTexture, + BundleResource, + ColladaAsset, + CoreMLModel, + ImageAsset, + InterfaceDefinition, + PartialAppManifest, + SceneKitAsset, + } + public override bool Execute () { try { @@ -78,7 +110,14 @@ bool ExecuteImpl () return result; } - var results = new List (); + var bundleResources = new List (); + var atlasTextures = new List (); + var colladaAssets = new List (); + var coreMLModels = new List (); + var imageAssets = new List (); + var interfaceDefinitions = new List (); + var partialAppManifests = new List (); + var sceneKitAssets = new List (); foreach (var asm in ReferencedLibraries) { // mscorlib.dll was not coming out with ResolvedFrom == {TargetFrameworkDirectory} @@ -89,15 +128,50 @@ bool ExecuteImpl () var perAssemblyOutputPath = Path.Combine (IntermediateOutputPath, "unpack", asm.GetMetadata ("Filename")); var extracted = ExtractContentAssembly (asm.ItemSpec, perAssemblyOutputPath).ToArray (); - results.AddRange (extracted); - - var itemsFile = asm.GetMetadata ("ItemsFile"); - itemsFile = itemsFile.Replace ('\\', Path.DirectorySeparatorChar); - WriteItemsToFile.Write (this, itemsFile, extracted, "_BundleResourceWithLogicalName", true, true); + foreach (var tuple in extracted) { + var resourceType = tuple.Type; + var item = tuple.Item; + switch (resourceType) { + case ResourceType.AtlasTexture: + atlasTextures.Add (item); + break; + case ResourceType.BundleResource: + bundleResources.Add (item); + break; + case ResourceType.ColladaAsset: + colladaAssets.Add (item); + break; + case ResourceType.CoreMLModel: + coreMLModels.Add (item); + break; + case ResourceType.ImageAsset: + imageAssets.Add (item); + break; + case ResourceType.InterfaceDefinition: + interfaceDefinitions.Add (item); + break; + case ResourceType.PartialAppManifest: + partialAppManifests.Add (item); + break; + case ResourceType.SceneKitAsset: + sceneKitAssets.Add (item); + break; + default: + Log.LogError ($"Unknown resource type: {resourceType}"); // FIXME: better error. + break; + } + } } } - BundleResourcesWithLogicalNames = results.ToArray (); + BundleResourcesWithLogicalNames = bundleResources.ToArray (); + AtlasTextures = atlasTextures.ToArray (); + ColladaAssets = colladaAssets.ToArray (); + CoreMLModels = coreMLModels.ToArray (); + ImageAssets = imageAssets.ToArray (); + InterfaceDefinitions = interfaceDefinitions.ToArray (); + PartialAppManifests = partialAppManifests.ToArray (); + SceneKitAssets = sceneKitAssets.ToArray (); UnpackedResources = unpackedResources.ToArray (); return !Log.HasLoggedErrors; @@ -113,7 +187,7 @@ bool IsFrameworkAssembly (ITaskItem asm) return false; } - IEnumerable ExtractContentAssembly (string assembly, string intermediatePath) + IEnumerable<(ResourceType Type, ITaskItem Item)> ExtractContentAssembly (string assembly, string intermediatePath) { if (!File.Exists (assembly)) { Log.LogMessage (MessageImportance.Low, $"Not inspecting assembly because it doesn't exist: {assembly}"); @@ -122,20 +196,78 @@ IEnumerable ExtractContentAssembly (string assembly, string intermedi var asmWriteTime = File.GetLastWriteTimeUtc (assembly); var manifestResources = GetAssemblyManifestResources (assembly).ToArray (); - if (!manifestResources.Any ()) + // Log.LogMessage (MessageImportance.Low, $"Inspecting assembly with {manifestResources.Length} resources: {assembly}"); + if (!manifestResources.Any ()) { + Log.LogMessage (MessageImportance.Low, $" No resources found in: {assembly}"); yield break; + } - Log.LogMessage (MessageImportance.Low, $"Inspecting assembly with {manifestResources.Length} resources: {assembly}"); + // Log.LogMessage (MessageImportance.Low, " Searching resources in assembly: {0}", assembly); foreach (var embedded in manifestResources) { string rpath; - if (embedded.Name.StartsWith ("__" + Prefix + "_content_", StringComparison.Ordinal)) { - var mangled = embedded.Name.Substring (("__" + Prefix + "_content_").Length); - rpath = UnmangleResource (mangled); - } else if (embedded.Name.StartsWith ("__" + Prefix + "_page_", StringComparison.Ordinal)) { - var mangled = embedded.Name.Substring (("__" + Prefix + "_page_").Length); - rpath = UnmangleResource (mangled); - } else { + var resourceName = embedded.Name; + var startsWith = "__" + Prefix + "_"; + if (!resourceName.StartsWith (startsWith, StringComparison.Ordinal)) { + Log.LogMessage (MessageImportance.Low, $" Not applicable resource (does not match prefix): {resourceName}"); + continue; + } + + var underscoreIndex = resourceName.IndexOf ('_', startsWith.Length); + if (underscoreIndex == -1) { + Log.LogMessage (MessageImportance.Low, $" Not applicable resource (no content type found): {resourceName}"); + continue; + } + var contentType = resourceName.Substring (startsWith.Length, underscoreIndex - startsWith.Length); + var contentValue = resourceName.Substring (underscoreIndex + 1); + ResourceType resourceType; + switch (contentType) { + case "content": + case "page": + rpath = UnmangleResource (contentValue); + resourceType = ResourceType.BundleResource; + break; + case "item": + var itemUnderscoreIndex = contentValue.IndexOf ('_'); + if (itemUnderscoreIndex == -1) { + Log.LogMessage (MessageImportance.Low, $" Not applicable resource (no item type in '{contentValue}'): {resourceName}"); + continue; + } + var itemType = contentValue.Substring (0, itemUnderscoreIndex); + var itemValue = contentValue.Substring (itemUnderscoreIndex + 1); + rpath = UnmangleResource (itemValue); + switch (itemType) { + case "AtlasTexture": + resourceType = ResourceType.AtlasTexture; + break; + case "BundleResource": + resourceType = ResourceType.BundleResource; + break; + case "Collada": + resourceType = ResourceType.ColladaAsset; + break; + case "CoreMLModel": + resourceType = ResourceType.CoreMLModel; + break; + case "ImageAsset": + resourceType = ResourceType.ImageAsset; + break; + case "InterfaceDefinition": + resourceType = ResourceType.InterfaceDefinition; + break; + case "PartialAppManifest": + resourceType = ResourceType.PartialAppManifest; + break; + case "SceneKitAsset": + resourceType = ResourceType.SceneKitAsset; + break; + default: + Log.LogMessage (MessageImportance.Low, $" Not applicable resource (unknown item type in '{itemType}'): {resourceName}"); + continue; + } + break; + default: + Log.LogMessage (MessageImportance.Low, $" Not applicable resource (unknown content type '{contentType}'): {resourceName}"); continue; } @@ -145,11 +277,12 @@ IEnumerable ExtractContentAssembly (string assembly, string intermedi var item = new TaskItem (path); item.SetMetadata ("LogicalName", rpath); item.SetMetadata ("Optimize", "false"); + item.SetMetadata ("BundledInAssembly", assembly); if (file.Exists && file.LastWriteTimeUtc >= asmWriteTime) { - Log.LogMessage (" Up to date: {0}", rpath); + Log.LogMessage ($" Up to date (contentType: {contentType} resourceType: {resourceType}: {path}"); } else { - Log.LogMessage (" Unpacking: {0}", rpath); + Log.LogMessage ($" Unpacking (contentType: {contentType} resourceType: {resourceType}: {path}"); Directory.CreateDirectory (Path.GetDirectoryName (path)); @@ -161,7 +294,7 @@ IEnumerable ExtractContentAssembly (string assembly, string intermedi unpackedResources.Add (item); } - yield return item; + yield return (resourceType, item); } yield break; @@ -182,6 +315,7 @@ static string UnmangleResource (string mangled) if (escaped) { switch (c) { + case 's': c = Path.DirectorySeparatorChar; break; case 'b': c = '\\'; break; case 'f': c = '/'; break; case '_': c = '_'; break; diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/XcodeCompilerToolTask.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/XcodeCompilerToolTask.cs index 662a63d1cafa..580d71452f21 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/XcodeCompilerToolTask.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/XcodeCompilerToolTask.cs @@ -256,6 +256,18 @@ protected int Compile (ITaskItem [] items, string output, ITaskItem manifest) File.Delete (manifest.ItemSpec); } + + Log.LogWarning ($"Tried to compile {items.Length} items:"); + foreach (var item in items) { + Log.LogWarning ($" {item.ItemSpec} {(File.Exists (item.ItemSpec) ? new FileInfo (item.ItemSpec).Length : -1)}"); + } + foreach (var item in items) { + if (!File.Exists (item.ItemSpec)) + continue; + Log.LogWarning ($"{item.ItemSpec}:"); + Log.LogWarning (File.ReadAllText (item.ItemSpec)); + } + } return exitCode; diff --git a/msbuild/Xamarin.Shared/Xamarin.Shared.ObjCBinding.targets b/msbuild/Xamarin.Shared/Xamarin.Shared.ObjCBinding.targets index 21f7e6ff0ccd..7bfe2bb657ee 100644 --- a/msbuild/Xamarin.Shared/Xamarin.Shared.ObjCBinding.targets +++ b/msbuild/Xamarin.Shared/Xamarin.Shared.ObjCBinding.targets @@ -103,7 +103,6 @@ Copyright (C) 2020 Microsoft. All rights reserved. diff --git a/msbuild/Xamarin.Shared/Xamarin.Shared.props b/msbuild/Xamarin.Shared/Xamarin.Shared.props index 5cc684fbbd1e..a81f34b4ba06 100644 --- a/msbuild/Xamarin.Shared/Xamarin.Shared.props +++ b/msbuild/Xamarin.Shared/Xamarin.Shared.props @@ -308,6 +308,12 @@ Copyright (C) 2020 Microsoft. All rights reserved. all <_AppBundleName>$(AssemblyName) + + + true + + + <_BundleOriginalResources Condition="'$(OutputType)' == 'Library' And '$(IsAppExtension)' != 'true' And '$(BundleOriginalResources)' == 'true'">true diff --git a/msbuild/Xamarin.Shared/Xamarin.Shared.targets b/msbuild/Xamarin.Shared/Xamarin.Shared.targets index 0487153b9bda..fc3175083e21 100644 --- a/msbuild/Xamarin.Shared/Xamarin.Shared.targets +++ b/msbuild/Xamarin.Shared/Xamarin.Shared.targets @@ -45,6 +45,7 @@ Copyright (C) 2018 Microsoft. All rights reserved. + @@ -444,6 +445,7 @@ Copyright (C) 2018 Microsoft. All rights reserved. $(CollectBundleResourcesDependsOn); + _UnpackLibraryResources; _CompileImageAssets; _CompileInterfaceDefinitions; _CompileSceneKitAssets; @@ -471,13 +473,14 @@ Copyright (C) 2018 Microsoft. All rights reserved. @@ -497,6 +500,25 @@ Copyright (C) 2018 Microsoft. All rights reserved. + + + + + + + + @@ -597,7 +620,7 @@ Copyright (C) 2018 Microsoft. All rights reserved. - + - + - + + + + + + + + + + + + + + + + + + + diff --git a/tests/dotnet/LibraryWithResources/iOS/Makefile b/tests/dotnet/LibraryWithResources/iOS/Makefile new file mode 100644 index 000000000000..110d078f4577 --- /dev/null +++ b/tests/dotnet/LibraryWithResources/iOS/Makefile @@ -0,0 +1 @@ +include ../shared.mk diff --git a/tests/dotnet/LibraryWithResources/iOS/Resources/A.ttc b/tests/dotnet/LibraryWithResources/iOS/Resources/A.ttc new file mode 100644 index 000000000000..61fd4366efd1 --- /dev/null +++ b/tests/dotnet/LibraryWithResources/iOS/Resources/A.ttc @@ -0,0 +1 @@ +I am a font! diff --git a/tests/dotnet/LibraryWithResources/iOS/Resources/B.otf b/tests/dotnet/LibraryWithResources/iOS/Resources/B.otf new file mode 100644 index 000000000000..2054ef0e7d50 --- /dev/null +++ b/tests/dotnet/LibraryWithResources/iOS/Resources/B.otf @@ -0,0 +1 @@ +I am a font too! diff --git a/tests/dotnet/LibraryWithResources/iOS/Resources/C.ttf b/tests/dotnet/LibraryWithResources/iOS/Resources/C.ttf new file mode 100644 index 000000000000..2ca44e510977 --- /dev/null +++ b/tests/dotnet/LibraryWithResources/iOS/Resources/C.ttf @@ -0,0 +1 @@ +Even I am a font! diff --git a/tests/dotnet/LibraryWithResources/iOS/Resources/Images.xcassets/Contents.json b/tests/dotnet/LibraryWithResources/iOS/Resources/Images.xcassets/Contents.json new file mode 100644 index 000000000000..73c00596a7fc --- /dev/null +++ b/tests/dotnet/LibraryWithResources/iOS/Resources/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/tests/dotnet/LibraryWithResources/iOS/Resources/Images.xcassets/Image.imageset/Contents.json b/tests/dotnet/LibraryWithResources/iOS/Resources/Images.xcassets/Image.imageset/Contents.json new file mode 100644 index 000000000000..4449069d93ca --- /dev/null +++ b/tests/dotnet/LibraryWithResources/iOS/Resources/Images.xcassets/Image.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Icon16.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Icon32.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Icon64.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/tests/dotnet/LibraryWithResources/iOS/Resources/Images.xcassets/Image.imageset/Icon16.png b/tests/dotnet/LibraryWithResources/iOS/Resources/Images.xcassets/Image.imageset/Icon16.png new file mode 100644 index 000000000000..35c074e65fce Binary files /dev/null and b/tests/dotnet/LibraryWithResources/iOS/Resources/Images.xcassets/Image.imageset/Icon16.png differ diff --git a/tests/dotnet/LibraryWithResources/iOS/Resources/Images.xcassets/Image.imageset/Icon32.png b/tests/dotnet/LibraryWithResources/iOS/Resources/Images.xcassets/Image.imageset/Icon32.png new file mode 100644 index 000000000000..a488140938ed Binary files /dev/null and b/tests/dotnet/LibraryWithResources/iOS/Resources/Images.xcassets/Image.imageset/Icon32.png differ diff --git a/tests/dotnet/LibraryWithResources/iOS/Resources/Images.xcassets/Image.imageset/Icon64.png b/tests/dotnet/LibraryWithResources/iOS/Resources/Images.xcassets/Image.imageset/Icon64.png new file mode 100644 index 000000000000..4027b6bf9ada Binary files /dev/null and b/tests/dotnet/LibraryWithResources/iOS/Resources/Images.xcassets/Image.imageset/Icon64.png differ diff --git a/tests/dotnet/LibraryWithResources/macOS/LibraryWithResources.csproj b/tests/dotnet/LibraryWithResources/macOS/LibraryWithResources.csproj new file mode 100644 index 000000000000..a77287b9ba00 --- /dev/null +++ b/tests/dotnet/LibraryWithResources/macOS/LibraryWithResources.csproj @@ -0,0 +1,7 @@ + + + + net$(BundledNETCoreAppTargetFrameworkVersion)-macos + + + diff --git a/tests/dotnet/LibraryWithResources/macOS/Main.storyboard b/tests/dotnet/LibraryWithResources/macOS/Main.storyboard new file mode 100644 index 000000000000..2c81cc6cab30 --- /dev/null +++ b/tests/dotnet/LibraryWithResources/macOS/Main.storyboard @@ -0,0 +1,717 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/dotnet/LibraryWithResources/macOS/Makefile b/tests/dotnet/LibraryWithResources/macOS/Makefile new file mode 100644 index 000000000000..110d078f4577 --- /dev/null +++ b/tests/dotnet/LibraryWithResources/macOS/Makefile @@ -0,0 +1 @@ +include ../shared.mk diff --git a/tests/dotnet/LibraryWithResources/macOS/Resources/A.ttc b/tests/dotnet/LibraryWithResources/macOS/Resources/A.ttc new file mode 100644 index 000000000000..61fd4366efd1 --- /dev/null +++ b/tests/dotnet/LibraryWithResources/macOS/Resources/A.ttc @@ -0,0 +1 @@ +I am a font! diff --git a/tests/dotnet/LibraryWithResources/macOS/Resources/B.otf b/tests/dotnet/LibraryWithResources/macOS/Resources/B.otf new file mode 100644 index 000000000000..2054ef0e7d50 --- /dev/null +++ b/tests/dotnet/LibraryWithResources/macOS/Resources/B.otf @@ -0,0 +1 @@ +I am a font too! diff --git a/tests/dotnet/LibraryWithResources/macOS/Resources/C.ttf b/tests/dotnet/LibraryWithResources/macOS/Resources/C.ttf new file mode 100644 index 000000000000..2ca44e510977 --- /dev/null +++ b/tests/dotnet/LibraryWithResources/macOS/Resources/C.ttf @@ -0,0 +1 @@ +Even I am a font! diff --git a/tests/dotnet/LibraryWithResources/macOS/Resources/Images.xcassets/Contents.json b/tests/dotnet/LibraryWithResources/macOS/Resources/Images.xcassets/Contents.json new file mode 100644 index 000000000000..73c00596a7fc --- /dev/null +++ b/tests/dotnet/LibraryWithResources/macOS/Resources/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/tests/dotnet/LibraryWithResources/macOS/Resources/Images.xcassets/Image.imageset/Contents.json b/tests/dotnet/LibraryWithResources/macOS/Resources/Images.xcassets/Image.imageset/Contents.json new file mode 100644 index 000000000000..4449069d93ca --- /dev/null +++ b/tests/dotnet/LibraryWithResources/macOS/Resources/Images.xcassets/Image.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Icon16.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Icon32.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Icon64.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/tests/dotnet/LibraryWithResources/macOS/Resources/Images.xcassets/Image.imageset/Icon16.png b/tests/dotnet/LibraryWithResources/macOS/Resources/Images.xcassets/Image.imageset/Icon16.png new file mode 100644 index 000000000000..35c074e65fce Binary files /dev/null and b/tests/dotnet/LibraryWithResources/macOS/Resources/Images.xcassets/Image.imageset/Icon16.png differ diff --git a/tests/dotnet/LibraryWithResources/macOS/Resources/Images.xcassets/Image.imageset/Icon32.png b/tests/dotnet/LibraryWithResources/macOS/Resources/Images.xcassets/Image.imageset/Icon32.png new file mode 100644 index 000000000000..a488140938ed Binary files /dev/null and b/tests/dotnet/LibraryWithResources/macOS/Resources/Images.xcassets/Image.imageset/Icon32.png differ diff --git a/tests/dotnet/LibraryWithResources/macOS/Resources/Images.xcassets/Image.imageset/Icon64.png b/tests/dotnet/LibraryWithResources/macOS/Resources/Images.xcassets/Image.imageset/Icon64.png new file mode 100644 index 000000000000..4027b6bf9ada Binary files /dev/null and b/tests/dotnet/LibraryWithResources/macOS/Resources/Images.xcassets/Image.imageset/Icon64.png differ diff --git a/tests/dotnet/LibraryWithResources/scene.dae b/tests/dotnet/LibraryWithResources/scene.dae new file mode 100644 index 000000000000..d0235f58160b --- /dev/null +++ b/tests/dotnet/LibraryWithResources/scene.dae @@ -0,0 +1,37 @@ + + + + + SceneKit Collada Exporter v1.0 + + 2021-09-23T09:36:40Z + 2021-09-23T09:36:40Z + + Y_UP + + + + + + + 45 + 0.111134 + 27.7834 + + + + + + + + + 0.9999999 0 0 0 0 1 0 0.3 0 0 0.9999999 2.5 0 0 0 1 + + + + + + + + + diff --git a/tests/dotnet/LibraryWithResources/shared.csproj b/tests/dotnet/LibraryWithResources/shared.csproj new file mode 100644 index 000000000000..159d97db62fa --- /dev/null +++ b/tests/dotnet/LibraryWithResources/shared.csproj @@ -0,0 +1,27 @@ + + + + true + true + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/dotnet/LibraryWithResources/shared.mk b/tests/dotnet/LibraryWithResources/shared.mk new file mode 100644 index 000000000000..f555cad4e805 --- /dev/null +++ b/tests/dotnet/LibraryWithResources/shared.mk @@ -0,0 +1,2 @@ +TOP=../../../.. +include $(TOP)/tests/common/shared-dotnet.mk diff --git a/tests/dotnet/LibraryWithResources/shared.plist b/tests/dotnet/LibraryWithResources/shared.plist new file mode 100644 index 000000000000..ffd2dd8dead5 --- /dev/null +++ b/tests/dotnet/LibraryWithResources/shared.plist @@ -0,0 +1,8 @@ + + + + + LibraryWithResources + Here I am + + diff --git a/tests/dotnet/LibraryWithResources/tvOS/LibraryWithResources.csproj b/tests/dotnet/LibraryWithResources/tvOS/LibraryWithResources.csproj new file mode 100644 index 000000000000..bd487ddcd88d --- /dev/null +++ b/tests/dotnet/LibraryWithResources/tvOS/LibraryWithResources.csproj @@ -0,0 +1,7 @@ + + + + net$(BundledNETCoreAppTargetFrameworkVersion)-tvos + + + diff --git a/tests/dotnet/LibraryWithResources/tvOS/Main.storyboard b/tests/dotnet/LibraryWithResources/tvOS/Main.storyboard new file mode 100644 index 000000000000..6a96318d776e --- /dev/null +++ b/tests/dotnet/LibraryWithResources/tvOS/Main.storyboard @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/dotnet/LibraryWithResources/tvOS/Makefile b/tests/dotnet/LibraryWithResources/tvOS/Makefile new file mode 100644 index 000000000000..110d078f4577 --- /dev/null +++ b/tests/dotnet/LibraryWithResources/tvOS/Makefile @@ -0,0 +1 @@ +include ../shared.mk diff --git a/tests/dotnet/LibraryWithResources/tvOS/Resources/A.ttc b/tests/dotnet/LibraryWithResources/tvOS/Resources/A.ttc new file mode 100644 index 000000000000..61fd4366efd1 --- /dev/null +++ b/tests/dotnet/LibraryWithResources/tvOS/Resources/A.ttc @@ -0,0 +1 @@ +I am a font! diff --git a/tests/dotnet/LibraryWithResources/tvOS/Resources/B.otf b/tests/dotnet/LibraryWithResources/tvOS/Resources/B.otf new file mode 100644 index 000000000000..2054ef0e7d50 --- /dev/null +++ b/tests/dotnet/LibraryWithResources/tvOS/Resources/B.otf @@ -0,0 +1 @@ +I am a font too! diff --git a/tests/dotnet/LibraryWithResources/tvOS/Resources/C.ttf b/tests/dotnet/LibraryWithResources/tvOS/Resources/C.ttf new file mode 100644 index 000000000000..2ca44e510977 --- /dev/null +++ b/tests/dotnet/LibraryWithResources/tvOS/Resources/C.ttf @@ -0,0 +1 @@ +Even I am a font! diff --git a/tests/dotnet/LibraryWithResources/tvOS/Resources/Images.xcassets/Contents.json b/tests/dotnet/LibraryWithResources/tvOS/Resources/Images.xcassets/Contents.json new file mode 100644 index 000000000000..73c00596a7fc --- /dev/null +++ b/tests/dotnet/LibraryWithResources/tvOS/Resources/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/tests/dotnet/LibraryWithResources/tvOS/Resources/Images.xcassets/Image.imageset/Contents.json b/tests/dotnet/LibraryWithResources/tvOS/Resources/Images.xcassets/Image.imageset/Contents.json new file mode 100644 index 000000000000..4449069d93ca --- /dev/null +++ b/tests/dotnet/LibraryWithResources/tvOS/Resources/Images.xcassets/Image.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Icon16.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Icon32.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Icon64.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/tests/dotnet/LibraryWithResources/tvOS/Resources/Images.xcassets/Image.imageset/Icon16.png b/tests/dotnet/LibraryWithResources/tvOS/Resources/Images.xcassets/Image.imageset/Icon16.png new file mode 100644 index 000000000000..35c074e65fce Binary files /dev/null and b/tests/dotnet/LibraryWithResources/tvOS/Resources/Images.xcassets/Image.imageset/Icon16.png differ diff --git a/tests/dotnet/LibraryWithResources/tvOS/Resources/Images.xcassets/Image.imageset/Icon32.png b/tests/dotnet/LibraryWithResources/tvOS/Resources/Images.xcassets/Image.imageset/Icon32.png new file mode 100644 index 000000000000..a488140938ed Binary files /dev/null and b/tests/dotnet/LibraryWithResources/tvOS/Resources/Images.xcassets/Image.imageset/Icon32.png differ diff --git a/tests/dotnet/LibraryWithResources/tvOS/Resources/Images.xcassets/Image.imageset/Icon64.png b/tests/dotnet/LibraryWithResources/tvOS/Resources/Images.xcassets/Image.imageset/Icon64.png new file mode 100644 index 000000000000..4027b6bf9ada Binary files /dev/null and b/tests/dotnet/LibraryWithResources/tvOS/Resources/Images.xcassets/Image.imageset/Icon64.png differ diff --git a/tests/dotnet/UnitTests/ProjectTest.cs b/tests/dotnet/UnitTests/ProjectTest.cs index 917d7e136f6b..069514ac620c 100644 --- a/tests/dotnet/UnitTests/ProjectTest.cs +++ b/tests/dotnet/UnitTests/ProjectTest.cs @@ -780,6 +780,261 @@ public void AppWithResources (ApplePlatform platform, string runtimeIdentifiers) Assert.AreEqual (runtimeIdentifiers.Split (';').Any (v => v.EndsWith ("-x64")), File.Exists (x64txt), "x64.txt"); } + [Category ("Windows")] + [TestCase (ApplePlatform.iOS, true)] + [TestCase (ApplePlatform.TVOS, true)] + [TestCase (ApplePlatform.MacCatalyst, true)] + [TestCase (ApplePlatform.MacOSX, true)] + public void LibraryWithResourcesOnWindows (ApplePlatform platform, bool? bundleOriginalResources) + { + Configuration.IgnoreIfNotOnWindows (); + + // This should all execute locally on Windows when BundleOriginalResources=true + LibraryWithResources (platform, bundleOriginalResources); + } + + [TestCase (ApplePlatform.iOS, true)] + [TestCase (ApplePlatform.iOS, false)] + [TestCase (ApplePlatform.iOS, null)] + [TestCase (ApplePlatform.TVOS, true)] + [TestCase (ApplePlatform.TVOS, false)] + [TestCase (ApplePlatform.TVOS, null)] + [TestCase (ApplePlatform.MacCatalyst, true)] + [TestCase (ApplePlatform.MacCatalyst, false)] + [TestCase (ApplePlatform.MacCatalyst, null)] + [TestCase (ApplePlatform.MacOSX, true)] + [TestCase (ApplePlatform.MacOSX, false)] + [TestCase (ApplePlatform.MacOSX, null)] + public void LibraryWithResources (ApplePlatform platform, bool? bundleOriginalResources) + { + var project = "LibraryWithResources"; + Configuration.IgnoreIfIgnoredPlatform (platform); + + var actualBundleOriginalResources = bundleOriginalResources ?? Version.Parse (Configuration.DotNetTfm.Replace ("net", "")).Major >= 9; + var project_path = GetProjectPath (project, platform: platform); + Clean (project_path); + + var properties = GetDefaultProperties (); + if (bundleOriginalResources.HasValue) + properties ["BundleOriginalResources"] = bundleOriginalResources.Value ? "true" : "false"; + + var rv = DotNet.AssertBuild (project_path, properties); + + var allTargets = BinLog.GetAllTargets (rv.BinLogPath).Where (v => !v.Skipped).Select (v => v.TargetName); + // https://github.com/xamarin/xamarin-macios/issues/15031 + if (actualBundleOriginalResources) { + Assert.That (allTargets, Does.Not.Contain ("_CompileAppManifest"), "Didn't execute '_CompileAppManifest'"); + Assert.That (allTargets, Does.Not.Contain ("_DetectSdkLocations"), "Didn't execute '_DetectSdkLocations'"); + } else { + Assert.That (allTargets, Does.Contain ("_CompileAppManifest"), "Did execute '_CompileAppManifest'"); + Assert.That (allTargets, Does.Contain ("_DetectSdkLocations"), "Did execute '_DetectSdkLocations'"); + } + + var lines = BinLog.PrintToLines (rv.BinLogPath); + // Find the resulting binding assembly from the build log + var assemblies = FilterToAssembly (lines, project); + Assert.That (assemblies, Is.Not.Empty, "Assemblies"); + // Make sure there's no other assembly confusing our logic + Assert.That (assemblies.Distinct ().Count (), Is.EqualTo (1), "Unique assemblies"); + var asm = assemblies.First (); + Assert.That (asm, Does.Exist, "Assembly existence"); + + var ad = AssemblyDefinition.ReadAssembly (asm, new ReaderParameters { ReadingMode = ReadingMode.Deferred }); + var actualResources = ad.MainModule.Resources.Select (v => v.Name).OrderBy (v => v).ToArray (); + + string [] expectedResources; + + var platformPrefix = (platform == ApplePlatform.MacOSX) ? "xammac" : "monotouch"; + if (actualBundleOriginalResources) { + expectedResources = new string [] { + $"__{platformPrefix}_content_A.ttc", + $"__{platformPrefix}_content_B.otf", + $"__{platformPrefix}_content_C.ttf", + $"__{platformPrefix}_item_AtlasTexture_Archer__Attack.atlas_sarcher__attack__0001.png", + $"__{platformPrefix}_item_AtlasTexture_Archer__Attack.atlas_sarcher__attack__0002.png", + $"__{platformPrefix}_item_AtlasTexture_Archer__Attack.atlas_sarcher__attack__0003.png", + $"__{platformPrefix}_item_AtlasTexture_Archer__Attack.atlas_sarcher__attack__0004.png", + $"__{platformPrefix}_item_AtlasTexture_Archer__Attack.atlas_sarcher__attack__0005.png", + $"__{platformPrefix}_item_AtlasTexture_Archer__Attack.atlas_sarcher__attack__0006.png", + $"__{platformPrefix}_item_AtlasTexture_Archer__Attack.atlas_sarcher__attack__0007.png", + $"__{platformPrefix}_item_AtlasTexture_Archer__Attack.atlas_sarcher__attack__0008.png", + $"__{platformPrefix}_item_AtlasTexture_Archer__Attack.atlas_sarcher__attack__0009.png", + $"__{platformPrefix}_item_AtlasTexture_Archer__Attack.atlas_sarcher__attack__0010.png", + $"__{platformPrefix}_item_BundleResource_A.ttc", + $"__{platformPrefix}_item_BundleResource_B.otf", + $"__{platformPrefix}_item_BundleResource_C.ttf", + $"__{platformPrefix}_item_Collada_scene.dae", + $"__{platformPrefix}_item_CoreMLModel_SqueezeNet.mlmodel", + $"__{platformPrefix}_item_ImageAsset_Images.xcassets_sContents.json", + $"__{platformPrefix}_item_ImageAsset_Images.xcassets_sImage.imageset_sContents.json", + $"__{platformPrefix}_item_ImageAsset_Images.xcassets_sImage.imageset_sIcon16.png", + $"__{platformPrefix}_item_ImageAsset_Images.xcassets_sImage.imageset_sIcon32.png", + $"__{platformPrefix}_item_ImageAsset_Images.xcassets_sImage.imageset_sIcon64.png", + $"__{platformPrefix}_item_InterfaceDefinition_Main.storyboard", + $"__{platformPrefix}_item_PartialAppManifest_shared.plist", + $"__{platformPrefix}_item_SceneKitAsset_art.scnassets_sscene.scn", + $"__{platformPrefix}_item_SceneKitAsset_art.scnassets_stexture.png", + $"__{platformPrefix}_item_SceneKitAsset_DirWithResources_slinkedArt.scnassets_sscene.scn", + $"__{platformPrefix}_item_SceneKitAsset_DirWithResources_slinkedArt.scnassets_stexture.png", + }; + } else { + var expectedList = new List (); + expectedList.Add ($"__{platformPrefix}_content_A.ttc"); + expectedList.Add ($"__{platformPrefix}_content_Archer__Attack.atlasc_sArcher__Attack.plist"); + expectedList.Add ($"__{platformPrefix}_content_art.scnassets_sscene.scn"); + expectedList.Add ($"__{platformPrefix}_content_art.scnassets_stexture.png"); + expectedList.Add ($"__{platformPrefix}_content_Assets.car"); + expectedList.Add ($"__{platformPrefix}_content_B.otf"); + expectedList.Add ($"__{platformPrefix}_content_C.ttf"); + expectedList.Add ($"__{platformPrefix}_content_DirWithResources_slinkedArt.scnassets_sscene.scn"); + expectedList.Add ($"__{platformPrefix}_content_DirWithResources_slinkedArt.scnassets_stexture.png"); + expectedList.Add ($"__{platformPrefix}_content_scene.dae"); + switch (platform) { + case ApplePlatform.iOS: + expectedList.Add ($"__{platformPrefix}_content_Main.storyboardc_sBYZ-38-t0r-view-8bC-Xf-vdC.nib"); + expectedList.Add ($"__{platformPrefix}_content_Main.storyboardc_sInfo.plist"); + expectedList.Add ($"__{platformPrefix}_content_Main.storyboardc_sUIViewController-BYZ-38-t0r.nib"); + break; + case ApplePlatform.TVOS: + expectedList.Add ($"__{platformPrefix}_content_Main.storyboardc_s1-view-2.nib"); + expectedList.Add ($"__{platformPrefix}_content_Main.storyboardc_sInfo.plist"); + expectedList.Add ($"__{platformPrefix}_content_Main.storyboardc_sUIViewController-1.nib"); + break; + case ApplePlatform.MacCatalyst: + expectedList.Add ($"__{platformPrefix}_content_Main.storyboardc_s1-view-2.nib"); + expectedList.Add ($"__{platformPrefix}_content_Main.storyboardc_sInfo.plist"); + expectedList.Add ($"__{platformPrefix}_content_Main.storyboardc_sUIViewController-1.nib"); + break; + case ApplePlatform.MacOSX: + expectedList.Add ($"__{platformPrefix}_content_Main.storyboardc_sInfo.plist"); + expectedList.Add ($"__{platformPrefix}_content_Main.storyboardc_sMainMenu.nib"); + expectedList.Add ($"__{platformPrefix}_content_Main.storyboardc_sNSWindowController-B8D-0N-5wS.nib"); + expectedList.Add ($"__{platformPrefix}_content_Main.storyboardc_sXfG-lQ-9wD-view-m2S-Jp-Qdl.nib"); + break; + } + expectedList.Add ($"__{platformPrefix}_content_SqueezeNet.mlmodelc_sanalytics_scoremldata.bin"); + expectedList.Add ($"__{platformPrefix}_content_SqueezeNet.mlmodelc_scoremldata.bin"); + expectedList.Add ($"__{platformPrefix}_content_SqueezeNet.mlmodelc_smetadata.json"); + expectedList.Add ($"__{platformPrefix}_content_SqueezeNet.mlmodelc_smodel.espresso.net"); + expectedList.Add ($"__{platformPrefix}_content_SqueezeNet.mlmodelc_smodel.espresso.shape"); + expectedList.Add ($"__{platformPrefix}_content_SqueezeNet.mlmodelc_smodel.espresso.weights"); + expectedList.Add ($"__{platformPrefix}_content_SqueezeNet.mlmodelc_smodel_scoremldata.bin"); + expectedList.Add ($"__{platformPrefix}_content_SqueezeNet.mlmodelc_sneural__network__optionals_scoremldata.bin"); + expectedResources = expectedList.ToArray (); + } + CollectionAssert.AreEquivalent (expectedResources, actualResources, "Resources"); + } + + [TestCase (ApplePlatform.iOS, "ios-arm64", false)] + [TestCase (ApplePlatform.iOS, "ios-arm64", true)] + [TestCase (ApplePlatform.TVOS, "tvossimulator-arm64", false)] + [TestCase (ApplePlatform.TVOS, "tvossimulator-arm64", true)] + [TestCase (ApplePlatform.MacCatalyst, "maccatalyst-x64", false)] + [TestCase (ApplePlatform.MacCatalyst, "maccatalyst-arm64;maccatalyst-x64", true)] + [TestCase (ApplePlatform.MacOSX, "osx-x64", true)] + [TestCase (ApplePlatform.MacOSX, "osx-arm64;osx-x64", false)] + public void AppWithLibraryWithResourcesReference (ApplePlatform platform, string runtimeIdentifiers, bool bundleOriginalResources) + { + AppWithLibraryWithResourcesReferenceImpl (platform, runtimeIdentifiers, bundleOriginalResources, false); + } + + + [Category ("RemoteWindows")] + [TestCase (ApplePlatform.iOS, "ios-arm64", false)] + [TestCase (ApplePlatform.iOS, "ios-arm64", true)] + public void AppWithLibraryWithResourcesReferenceOnWindows (ApplePlatform platform, string runtimeIdentifiers, bool bundleOriginalResources) + { + Configuration.IgnoreIfNotOnWindows (); + + AppWithLibraryWithResourcesReferenceImpl (platform, runtimeIdentifiers, bundleOriginalResources, false); + } + + void AppWithLibraryWithResourcesReferenceImpl (ApplePlatform platform, string runtimeIdentifiers, bool bundleOriginalResources, bool remoteWindows) + { + var project = "AppWithLibraryWithResourcesReference"; + var config = bundleOriginalResources ? "DebugOriginal" : "DebugCompiled"; + + Configuration.IgnoreIfIgnoredPlatform (platform); + Configuration.AssertRuntimeIdentifiersAvailable (platform, runtimeIdentifiers); + + var library_project = GetProjectPath ("LibraryWithResources", platform: platform); + Clean (library_project); + var project_path = GetProjectPath (project, runtimeIdentifiers: runtimeIdentifiers, platform: platform, out var appPath, configuration: config); + Clean (project_path); + + var properties = GetDefaultProperties (runtimeIdentifiers); + properties ["Configuration"] = config; + properties ["BundleOriginalResources"] = bundleOriginalResources ? "true" : "false"; + if (remoteWindows) { + // Copy the app bundle to Windows so that we can inspect the results. + properties ["CopyAppBundleToWindows"] = "true"; + } + + var rv = DotNet.AssertBuild (project_path, properties); + + var appExecutable = GetNativeExecutable (platform, appPath); + ExecuteWithMagicWordAndAssert (platform, runtimeIdentifiers, appExecutable); + + var appBundleInfo = new AppBundleInfo (platform, appPath, remoteWindows, runtimeIdentifiers, config); + var appBundleContents = appBundleInfo.GetAppBundleFiles ().ToHashSet (); + + Console.WriteLine ($"App bundle contents:"); + foreach (var abc in appBundleContents.OrderBy (v => v)) + Console.WriteLine ($" {abc}"); + + Assert.Multiple (() => { + var resourcesDirectory = GetResourcesDirectory (platform, ""); + + var fontDirectory = resourcesDirectory; + var fontAFile = Path.Combine (fontDirectory, "A.ttc"); + var fontBFile = Path.Combine (fontDirectory, "B.otf"); + var fontCFile = Path.Combine (fontDirectory, "C.ttf"); + + Assert.That (appBundleContents, Does.Contain (fontAFile), "A.ttc existence"); + Assert.That (appBundleContents, Does.Contain (fontBFile), "B.otf existence"); + Assert.That (appBundleContents, Does.Contain (fontCFile), "C.ttf existence"); + + var atlasTexture = Path.Combine (resourcesDirectory, "Archer_Attack.atlasc", "Archer_Attack.plist"); + Assert.That (appBundleContents, Does.Contain (atlasTexture), "AtlasTexture - Archer_Attack"); + + var scnAssetsDir = Path.Combine (resourcesDirectory, "art.scnassets"); + Assert.That (appBundleContents, Does.Contain (Path.Combine (scnAssetsDir, "scene.scn")), "scene.scn"); + Assert.That (appBundleContents, Does.Contain (Path.Combine (scnAssetsDir, "texture.png")), "texture.png"); + + Assert.That (appBundleContents, Does.Contain (Path.Combine (resourcesDirectory, "Assets.car")), "Assets.car"); + + Assert.That (appBundleContents, Does.Contain (Path.Combine (resourcesDirectory, "DirWithResources", "linkedArt.scnassets", "scene.scn")), "DirWithResources/linkedArt.scnassets/scene.scn"); + Assert.That (appBundleContents, Does.Contain (Path.Combine (resourcesDirectory, "DirWithResources", "linkedArt.scnassets", "texture.png")), "DirWithResources/linkedArt.scnassets/texture.png"); + + var mainStoryboard = Path.Combine (resourcesDirectory, "Main.storyboardc"); + Assert.That (appBundleContents, Does.Contain (mainStoryboard), "Main.storyboardc"); + Assert.That (appBundleContents, Does.Contain (Path.Combine (mainStoryboard, "Info.plist")), "Main.storyboardc/Info.plist"); + + var colladaScene = Path.Combine (resourcesDirectory, "scene.dae"); + Assert.That (appBundleContents, Does.Contain (colladaScene), "Collada - scene.dae"); + + var mlModel = Path.Combine (resourcesDirectory, "SqueezeNet.mlmodelc"); + Assert.That (appBundleContents, Does.Contain (mlModel), "CoreMLModel"); + Assert.That (appBundleContents, Does.Contain (Path.Combine (mlModel, "analytics")), "CoreMLModel/analytics"); + Assert.That (appBundleContents, Does.Contain (Path.Combine (mlModel, "analytics", "coremldata.bin")), "CoreMLModel/analytics/coremldata.bin"); + Assert.That (appBundleContents, Does.Contain (Path.Combine (mlModel, "coremldata.bin")), "CoreMLModel/coremldata.bin"); + Assert.That (appBundleContents, Does.Contain (Path.Combine (mlModel, "metadata.json")), "CoreMLModel/metadata.json"); + Assert.That (appBundleContents, Does.Contain (Path.Combine (mlModel, "model")), "CoreMLModel/model"); + Assert.That (appBundleContents, Does.Contain (Path.Combine (mlModel, "model.espresso.net")), "CoreMLModel/model.espresso.net"); + Assert.That (appBundleContents, Does.Contain (Path.Combine (mlModel, "model.espresso.shape")), "CoreMLModel/model.espresso.shape"); + Assert.That (appBundleContents, Does.Contain (Path.Combine (mlModel, "model.espresso.weights")), "CoreMLModel/model.espresso.weights"); + Assert.That (appBundleContents, Does.Contain (Path.Combine (mlModel, "model", "coremldata.bin")), "CoreMLModel/model/coremldata.bin"); + Assert.That (appBundleContents, Does.Contain (Path.Combine (mlModel, "neural_network_optionals")), "CoreMLModel/neural_network_optionals"); + Assert.That (appBundleContents, Does.Contain (Path.Combine (mlModel, "neural_network_optionals", "coremldata.bin")), "CoreMLModel/neural_network_optionals/coremldata.bin"); + + if (bundleOriginalResources) { + var infoPlist = appBundleInfo.GetFile (GetInfoPListPath (platform, "")); + var appManifest = PDictionary.FromByteArray (infoPlist, out var _)!; + Assert.AreEqual ("Here I am", appManifest.GetString ("LibraryWithResources").Value, "Partial plist entry"); + } + }); + } + [TestCase (ApplePlatform.iOS, "iossimulator-x64")] [TestCase (ApplePlatform.iOS, "ios-arm64;ios-arm")] [TestCase (ApplePlatform.TVOS, "tvossimulator-x64")] @@ -1012,13 +1267,13 @@ IEnumerable FilterToAssembly (IEnumerable lines, string assembly Where (v => { if (v.Length < 10) return false; - if (v [0] != '/') + if (v [0] != '/' && !(char.IsAsciiLetter (v [0]) && v [1] == ':')) return false; if (!v.EndsWith ($"{assemblyName}.dll", StringComparison.Ordinal)) return false; - if (!v.Contains ("/bin/", StringComparison.Ordinal)) + if (!(v.Contains ("/bin/", StringComparison.Ordinal) || v.Contains ("\\bin\\", StringComparison.Ordinal))) return false; - if (v.Contains ("/ref/", StringComparison.Ordinal)) + if (v.Contains ("/ref/", StringComparison.Ordinal) || v.Contains ("\\ref\\", StringComparison.Ordinal)) return false; // Skip reference assemblies return true; }); diff --git a/tests/dotnet/UnitTests/TestBaseClass.cs b/tests/dotnet/UnitTests/TestBaseClass.cs index b432e0fb4309..5223a6438ee7 100644 --- a/tests/dotnet/UnitTests/TestBaseClass.cs +++ b/tests/dotnet/UnitTests/TestBaseClass.cs @@ -20,9 +20,20 @@ protected Dictionary GetDefaultProperties (string? runtimeIdenti var rv = new Dictionary (verbosity); if (!string.IsNullOrEmpty (runtimeIdentifiers)) SetRuntimeIdentifiers (rv, runtimeIdentifiers); + if (Configuration.IsBuildingRemotely) + AddRemoteProperties (rv); return rv; } + protected void AddRemoteProperties (Dictionary properties) + { + properties ["ServerAddress"] = Environment.GetEnvironmentVariable ("MAC_AGENT_IP") ?? string.Empty; + properties ["ServerUser"] = Environment.GetEnvironmentVariable ("MAC_AGENT_USER") ?? string.Empty; + properties ["ServerPassword"] = Environment.GetEnvironmentVariable ("XMA_PASSWORD") ?? string.Empty; + if (!string.IsNullOrEmpty (properties ["ServerUser"])) + properties ["EnsureRemoteConnection"] = "true"; + } + protected void SetRuntimeIdentifiers (Dictionary properties, string runtimeIdentifiers) { var multiRid = runtimeIdentifiers.IndexOf (';') >= 0 ? "RuntimeIdentifiers" : "RuntimeIdentifier"; @@ -51,12 +62,12 @@ protected string GetBinDir (string projectPath, ApplePlatform platform, string r return GetBinOrObjDir ("bin", projectPath, platform, runtimeIdentifiers, configuration); } - protected string GetObjDir (string projectPath, ApplePlatform platform, string runtimeIdentifiers, string configuration = "Debug") + internal static protected string GetObjDir (string projectPath, ApplePlatform platform, string runtimeIdentifiers, string configuration = "Debug") { return GetBinOrObjDir ("obj", projectPath, platform, runtimeIdentifiers, configuration); } - protected string GetBinOrObjDir (string binOrObj, string projectPath, ApplePlatform platform, string runtimeIdentifiers, string configuration = "Debug") + internal static protected string GetBinOrObjDir (string binOrObj, string projectPath, ApplePlatform platform, string runtimeIdentifiers, string configuration = "Debug") { var appPathRuntimeIdentifier = runtimeIdentifiers.IndexOf (';') >= 0 ? "" : runtimeIdentifiers; return Path.Combine (Path.GetDirectoryName (projectPath)!, binOrObj, configuration, platform.ToFramework (), appPathRuntimeIdentifier); diff --git a/tests/dotnet/UnitTests/WindowsTest.cs b/tests/dotnet/UnitTests/WindowsTest.cs index 878deff51dda..028a7e683681 100644 --- a/tests/dotnet/UnitTests/WindowsTest.cs +++ b/tests/dotnet/UnitTests/WindowsTest.cs @@ -363,15 +363,62 @@ public void RemoteTest (ApplePlatform platform, string runtimeIdentifiers) Assert.AreEqual ("3.14", infoPlist.GetString ("CFBundleVersion").Value, "CFBundleVersion"); Assert.AreEqual ("3.14", infoPlist.GetString ("CFBundleShortVersionString").Value, "CFBundleShortVersionString"); } + } + + public class AppBundleInfo { + public readonly bool IsRemoteBuild; + public readonly string AppPath; + public readonly ApplePlatform Platform; + public readonly string Configuration; + public readonly string RuntimeIdentifiers; + + string? zippedAppBundlePath; + string ZippedAppBundlePath { + get { + if (zippedAppBundlePath is null) { + if (!IsRemoteBuild) + throw new InvalidOperationException ($"Can't get the zipped app bundle path unless it's for a remote build."); + var objDir = TestBaseClass.GetObjDir (AppPath, Platform, RuntimeIdentifiers, Configuration); + zippedAppBundlePath = Path.Combine (objDir, "AppBundle.zip"); + Assert.That (zippedAppBundlePath, Does.Exist, "AppBundle.zip"); + } + return zippedAppBundlePath; + } + } + + public AppBundleInfo (ApplePlatform platform, string appPath, bool isRemoteBuild, string runtimeIdentifiers, string configuration) + { + Platform = platform; + AppPath = appPath; + IsRemoteBuild = isRemoteBuild; + Configuration = configuration; + RuntimeIdentifiers = runtimeIdentifiers; + } - protected void AddRemoteProperties (Dictionary properties) + public byte [] GetFile (string appBundleRelativePath) { - properties ["ServerAddress"] = Environment.GetEnvironmentVariable ("MAC_AGENT_IP") ?? string.Empty; - properties ["ServerUser"] = Environment.GetEnvironmentVariable ("MAC_AGENT_USER") ?? string.Empty; - properties ["ServerPassword"] = Environment.GetEnvironmentVariable ("XMA_PASSWORD") ?? string.Empty; + Assert.That (GetAppBundleFiles (), Does.Contain (appBundleRelativePath), "File does not exist in app bundle"); + if (IsRemoteBuild) { + using var zip = ZipFile.OpenRead (ZippedAppBundlePath); + var entry = zip.GetEntry (appBundleRelativePath.Replace (Path.DirectorySeparatorChar, '/'))!; + using var stream = entry.Open (); + using var memoryStream = new MemoryStream ((int) stream.Length); + stream.CopyTo (memoryStream); + return memoryStream.ToArray (); + } else { + return File.ReadAllBytes (Path.Combine (AppPath, appBundleRelativePath)); + } + } - if (!string.IsNullOrEmpty (properties ["ServerUser"])) - properties ["EnsureRemoteConnection"] = "true"; + public IEnumerable GetAppBundleFiles () + { + if (IsRemoteBuild) { + return ZipHelpers.List (ZippedAppBundlePath); + } else { + return Directory + .GetFileSystemEntries (AppPath, "*", SearchOption.AllDirectories) + .Select (v => v.Substring (AppPath.Length + 1)); + } } } } diff --git a/tests/msbuild/Xamarin.MacDev.Tests/TargetTests/TargetTests.cs b/tests/msbuild/Xamarin.MacDev.Tests/TargetTests/TargetTests.cs index 6cf38341ca61..aed1fa38d413 100644 --- a/tests/msbuild/Xamarin.MacDev.Tests/TargetTests/TargetTests.cs +++ b/tests/msbuild/Xamarin.MacDev.Tests/TargetTests/TargetTests.cs @@ -100,17 +100,17 @@ static string [] ExpectedLibraryEmbeddedResources { return new [] { "MyLibrary.MyLibraryFolder.LibraryLinkedEmbeddedResource.txt", "MyLibrary.MyLibraryFolder.LibraryEmbeddedResource.txt", - "__monotouch_content_MyLibraryFolder_fLibraryLinkedBundleResource.txt", - "__monotouch_content_MyLibraryFolder_fLibraryBundleResource.txt", - "__monotouch_content_MyLibraryFolder_fLibraryLinkedContent.txt", - "__monotouch_content_MyLibraryFolder_fLibraryContent.txt", - "__monotouch_content_LibraryStoryboard.storyboardc_f1-view-2.nib", - "__monotouch_content_LibraryStoryboard.storyboardc_fInfo.plist", - "__monotouch_content_LibraryStoryboard.storyboardc_fUIViewController-1.nib", - "__monotouch_content_LibrarySecondStoryboard.storyboardc_f43-view-49.nib", - "__monotouch_content_LibrarySecondStoryboard.storyboardc_f45-view-53.nib", - "__monotouch_content_LibrarySecondStoryboard.storyboardc_fInfo.plist", - "__monotouch_content_LibrarySecondStoryboard.storyboardc_fUITabBarController-41.nib" + "__monotouch_content_MyLibraryFolder_sLibraryLinkedBundleResource.txt", + "__monotouch_content_MyLibraryFolder_sLibraryBundleResource.txt", + "__monotouch_content_MyLibraryFolder_sLibraryLinkedContent.txt", + "__monotouch_content_MyLibraryFolder_sLibraryContent.txt", + "__monotouch_content_LibraryStoryboard.storyboardc_s1-view-2.nib", + "__monotouch_content_LibraryStoryboard.storyboardc_sInfo.plist", + "__monotouch_content_LibraryStoryboard.storyboardc_sUIViewController-1.nib", + "__monotouch_content_LibrarySecondStoryboard.storyboardc_s43-view-49.nib", + "__monotouch_content_LibrarySecondStoryboard.storyboardc_s45-view-53.nib", + "__monotouch_content_LibrarySecondStoryboard.storyboardc_sInfo.plist", + "__monotouch_content_LibrarySecondStoryboard.storyboardc_sUITabBarController-41.nib" }; } } diff --git a/tools/devops/automation/templates/windows/build.yml b/tools/devops/automation/templates/windows/build.yml index e398db56fd6e..27f609585b84 100644 --- a/tools/devops/automation/templates/windows/build.yml +++ b/tools/devops/automation/templates/windows/build.yml @@ -234,6 +234,7 @@ steps: - pwsh: | $Env:PATH = "$(Build.SourcesDirectory)\xamarin-macios\tests\dotnet\Windows\bin\dotnet;$env:PATH" $Env:DOTNET = "$(Build.SourcesDirectory)\xamarin-macios\tests\dotnet\Windows\bin\dotnet\dotnet.exe" + $Env:MAC_AGENT_IP = "" & $(Build.SourcesDirectory)\xamarin-macios\tests\dotnet\Windows\bin\dotnet\dotnet.exe ` test ` "$(Build.SourcesDirectory)/xamarin-macios/tests/dotnet/UnitTests/DotNetUnitTests.csproj" `