Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into dev/rolf/bot-diagnost…
Browse files Browse the repository at this point in the history
…ics-and-preparation
  • Loading branch information
rolfbjarne committed Oct 1, 2024
2 parents f2858ee + 15c1e75 commit d66ed0a
Show file tree
Hide file tree
Showing 39 changed files with 336 additions and 411 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/update-single-platform-branches.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
set -ex
git config user.email "[email protected]"
git config user.name "GitHub Actions Single Platform Branch Updater"
for platform in dotnet-iOS dotnet-tvOS dotnet-MacCatalyst dotnet-macOS dotnet; do
for platform in dotnet-iOS dotnet-tvOS dotnet-MacCatalyst dotnet-macOS; do
git checkout -b release-test/only-$platform origin/release-test/only-$platform
git merge origin/main
git push
Expand Down
2 changes: 1 addition & 1 deletion msbuild/ILMerge.targets
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<MergeSystemAssemblies Condition="'$(MergeSystemAssemblies)' == ''">true</MergeSystemAssemblies>
<MergeSystemAssemblies Condition="'$(MergeSystemAssemblies)' == ''">false</MergeSystemAssemblies>
</PropertyGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion msbuild/Xamarin.MacDev.Tasks/Tasks/ComputeCodesignItems.cs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ public override bool Execute ()
for (var i = 1; i < all.Length; i++) {
var nextMetadata = all [i].CloneCustomMetadataToDictionary ();
if (nextMetadata.Count != firstMetadata.Count) {
Log.LogWarning (MSBStrings.W7095, /* Code signing has been requested multiple times for '{0}', with different metadata. The metadata for one are: '{1}', while the metadata for the other are: '{2}' */ group.Key, string.Join (", ", firstMetadata.Keys), string.Join (", ", nextMetadata.Keys));
Log.LogWarning (MSBStrings.W7095, /* Code signing has been requested multiple times for '{0}', with different metadata. The metadata for one are: '{1}', while the metadata for the other are: '{2}' */ group.Key, string.Join (", ", firstMetadata.Keys.OrderBy (v => v)), string.Join (", ", nextMetadata.Keys.OrderBy (v => v)));
} else {
foreach (var kvp in firstMetadata) {
if (!nextMetadata.TryGetValue (kvp.Key, out var nextValue)) {
Expand Down
153 changes: 75 additions & 78 deletions msbuild/Xamarin.MacDev.Tasks/Tasks/UnpackLibraryResources.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using System.Text;
using System.Collections.Generic;

Expand All @@ -15,7 +17,6 @@

namespace Xamarin.MacDev.Tasks {
public class UnpackLibraryResources : XamarinTask, ITaskCallback, ICancelableTask {
MetadataLoadContext? universe;
List<ITaskItem> unpackedResources = new List<ITaskItem> ();

#region Inputs
Expand All @@ -26,9 +27,6 @@ public class UnpackLibraryResources : XamarinTask, ITaskCallback, ICancelableTas
[Required]
public string IntermediateOutputPath { get; set; } = string.Empty;

[Required]
public ITaskItem [] ReferenceAssemblies { get; set; } = Array.Empty<ITaskItem> ();

[Required]
public ITaskItem [] ReferencedLibraries { get; set; } = Array.Empty<ITaskItem> ();

Expand All @@ -52,15 +50,6 @@ public class UnpackLibraryResources : XamarinTask, ITaskCallback, ICancelableTas
#endregion

public override bool Execute ()
{
try {
return ExecuteImpl ();
} finally {
universe?.Dispose ();
}
}

bool ExecuteImpl ()
{
if (ShouldExecuteRemotely ()) {
var result = new TaskRunner (SessionId, BuildEngine4).RunAsync (this).Result;
Expand All @@ -87,7 +76,7 @@ bool ExecuteImpl ()
Log.LogMessage (MessageImportance.Low, MSBStrings.M0168, asm.ItemSpec);
} else {
var perAssemblyOutputPath = Path.Combine (IntermediateOutputPath, "unpack", asm.GetMetadata ("Filename"));
var extracted = ExtractContentAssembly (asm.ItemSpec, perAssemblyOutputPath).ToArray ();
var extracted = ExtractContentAssembly (asm.ItemSpec, perAssemblyOutputPath);

results.AddRange (extracted);

Expand All @@ -113,58 +102,88 @@ bool IsFrameworkAssembly (ITaskItem asm)
return false;
}

IEnumerable<ITaskItem> ExtractContentAssembly (string assembly, string intermediatePath)
List<ITaskItem> ExtractContentAssembly (string assembly, string intermediatePath)
{
var rv = new List<ITaskItem> ();

if (!File.Exists (assembly)) {
Log.LogMessage (MessageImportance.Low, $"Not inspecting assembly because it doesn't exist: {assembly}");
yield break;
return rv;
}

var asmWriteTime = File.GetLastWriteTimeUtc (assembly);
var manifestResources = GetAssemblyManifestResources (assembly).ToArray ();
if (!manifestResources.Any ())
yield break;

Log.LogMessage (MessageImportance.Low, $"Inspecting assembly with {manifestResources.Length} resources: {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 {
continue;
}

var path = Path.Combine (intermediatePath, rpath);
var file = new FileInfo (path);

var item = new TaskItem (path);
item.SetMetadata ("LogicalName", rpath);
item.SetMetadata ("Optimize", "false");

if (file.Exists && file.LastWriteTimeUtc >= asmWriteTime) {
Log.LogMessage (" Up to date: {0}", rpath);
} else {
Log.LogMessage (" Unpacking: {0}", rpath);

Directory.CreateDirectory (Path.GetDirectoryName (path));
try {
var asmWriteTime = File.GetLastWriteTimeUtc (assembly);
using var peStream = File.OpenRead (assembly);
using var peReader = new PEReader (peStream);
var metadataReader = PEReaderExtensions.GetMetadataReader (peReader);
Log.LogMessage (MessageImportance.Low, $"Inspecting resources in assembly {assembly}");
foreach (var manifestResourceHandle in metadataReader.ManifestResources) {
var manifestResource = metadataReader.GetManifestResource (manifestResourceHandle);
if (!manifestResource.Implementation.IsNil)
continue; // embedded resources have Implementation.IsNil = true, and those are the ones we care about

var name = metadataReader.GetString (manifestResource.Name);
if (string.IsNullOrEmpty (name))
continue;

string rpath;

if (name.StartsWith ("__" + Prefix + "_content_", StringComparison.Ordinal)) {
var mangled = name.Substring (("__" + Prefix + "_content_").Length);
rpath = UnmangleResource (mangled);
} else if (name.StartsWith ("__" + Prefix + "_page_", StringComparison.Ordinal)) {
var mangled = name.Substring (("__" + Prefix + "_page_").Length);
rpath = UnmangleResource (mangled);
} else {
continue;
}

using (var stream = File.Open (path, FileMode.Create)) {
using (var resource = embedded.Open ())
resource.CopyTo (stream);
var path = Path.Combine (intermediatePath, rpath);
var file = new FileInfo (path);

var item = new TaskItem (path);
item.SetMetadata ("LogicalName", rpath);
item.SetMetadata ("Optimize", "false");

if (file.Exists && file.LastWriteTimeUtc >= asmWriteTime) {
Log.LogMessage (" Up to date: {0}", rpath);
} else {
Log.LogMessage (" Unpacking: {0}", rpath);

Directory.CreateDirectory (Path.GetDirectoryName (path));

var resourceDirectory = peReader.GetSectionData (peReader.PEHeaders.CorHeader!.ResourcesDirectory.RelativeVirtualAddress);
var reader = resourceDirectory.GetReader ((int) manifestResource.Offset, resourceDirectory.Length - (int) manifestResource.Offset);
var length = reader.ReadUInt32 ();
if (length > reader.RemainingBytes)
throw new BadImageFormatException ();
#if NET
using var fs = new FileStream (path, FileMode.Create, FileAccess.Write, FileShare.Read);
unsafe {
var span = new ReadOnlySpan<byte> (reader.CurrentPointer, (int) length);
fs.Write (span);
}
#else
var buffer = new byte [4096];
using var fs = new FileStream (path, FileMode.Create, FileAccess.Write, FileShare.Read, buffer.Length);
var left = (int) length;
while (left > 0) {
var read = Math.Min (left, buffer.Length);
reader.ReadBytes (read, buffer, 0);
fs.Write (buffer, 0, read);
left -= read;
}
#endif
unpackedResources.Add (item);
}

unpackedResources.Add (item);
rv.Add (item);
}

yield return item;
} catch (Exception e) {
Log.LogMessage (MessageImportance.Low, $"Unable to load the resources from the assembly '{assembly}': {e}");
return new List<ITaskItem> ();
}

yield break;
return rv;
}

static string UnmangleResource (string mangled)
Expand Down Expand Up @@ -237,27 +256,5 @@ public bool ShouldCopyToBuildServer (ITaskItem item)

public IEnumerable<ITaskItem> GetAdditionalItemsToBeCopied () => ItemsFiles;

IEnumerable<ManifestResource> GetAssemblyManifestResources (string fileName)
{
if (universe is null)
universe = new MetadataLoadContext (new PathAssemblyResolver (ReferenceAssemblies.Select (v => v.ItemSpec)));

Assembly assembly;
try {
assembly = universe.LoadFromAssemblyPath (fileName);
} catch (Exception e) {
Log.LogMessage (MessageImportance.Low, $"Unable to load the assembly '{fileName}: {e}");
yield break;
}

foreach (var resourceName in assembly.GetManifestResourceNames ()) {
if (string.IsNullOrEmpty (resourceName))
continue;
var info = assembly.GetManifestResourceInfo (resourceName);
if (!info.ResourceLocation.HasFlag (ResourceLocation.Embedded))
continue;
yield return new ManifestResource (resourceName, () => assembly.GetManifestResourceStream (resourceName));
}
}
}
}
6 changes: 3 additions & 3 deletions msbuild/Xamarin.Shared/Xamarin.Shared.targets
Original file line number Diff line number Diff line change
Expand Up @@ -1933,7 +1933,9 @@ Copyright (C) 2018 Microsoft. All rights reserved.
<_StampDirectory>$(DeviceSpecificIntermediateOutputPath)resourcestamps\</_StampDirectory>
</PropertyGroup>
<ItemGroup>
<_UnpackLibraryResourceItems Include="@(ReferencePath);@(ReferenceDependencyPaths)">
<_UnpackLibraryResourceItems Include="@(ReferencePath)" Condition="'%(ReferencePath.FrameworkReferenceName)' != 'Microsoft.NETCore.App' And '%(ReferencePath.FrameworkReferenceName)' != 'Microsoft.$(_PlatformName)'" />
<_UnpackLibraryResourceItems Include="@(ReferenceDependencyPaths)" Condition="'%(ReferenceDependencyPaths.FrameworkReferenceName)' != 'Microsoft.NETCore.App' And '%(ReferenceDependencyPaths.FrameworkReferenceName)' != 'Microsoft.$(_PlatformName)'" />
<_UnpackLibraryResourceItems>
<StampFile>$(_StampDirectory)%(FileName).stamp</StampFile>
<ItemsFile>$(_StampDirectory)%(FileName).items</ItemsFile>
</_UnpackLibraryResourceItems>
Expand Down Expand Up @@ -1982,14 +1984,12 @@ Copyright (C) 2018 Microsoft. All rights reserved.
<MakeDir Directories="$(_StampDirectory)" />

<!-- This task may be executed locally on Windows (for Hot Restart) -->
<!-- Note that ReferenceAssemblies must always be passed all referenced assemblies, even for incremental builds when we're not necessarily unpacking from all assemblies -->
<UnpackLibraryResources
Condition="'$(IsMacEnabled)' == 'true' Or '$(IsHotRestartBuild)' == 'true'"
SessionId="$(BuildSessionId)"
Prefix="$(_EmbeddedResourcePrefix)"
IntermediateOutputPath="$(DeviceSpecificIntermediateOutputPath)"
TargetFrameworkDirectory="$(TargetFrameworkDirectory)"
ReferenceAssemblies="@(ReferencePath);@(ReferenceDependencyPaths)"
ReferencedLibraries="@(_UnpackLibraryResourceItems)"
>
<Output TaskParameter="BundleResourcesWithLogicalNames" ItemName="_BundleResourceWithLogicalName" />
Expand Down
1 change: 1 addition & 0 deletions src/Foundation/DictionaryContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,7 @@ static public NativeHandle GetHandle (this DictionaryContainer? self)

// helper to avoid the (common pattern)
// var p = x is null ? null : x.Dictionary;
[return: NotNullIfNotNull (nameof (self))]
static public NSDictionary? GetDictionary (this DictionaryContainer? self)
{
return self is null ? null : self.Dictionary;
Expand Down
Loading

0 comments on commit d66ed0a

Please sign in to comment.