Skip to content

Commit 0bd54f1

Browse files
Copilotrolfbjarne
andcommitted
Fix FilterStaticFrameworks to support custom framework binary names
Co-authored-by: rolfbjarne <[email protected]>
1 parent e9253cb commit 0bd54f1

File tree

2 files changed

+121
-1
lines changed

2 files changed

+121
-1
lines changed

msbuild/Xamarin.MacDev.Tasks/Tasks/FilterStaticFrameworks.cs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,29 @@ public class FilterStaticFrameworks : XamarinTask, ITaskCallback {
2020
[Output]
2121
public ITaskItem []? FrameworkToPublish { get; set; }
2222

23+
static string GetFrameworkExecutablePath (string frameworkPath)
24+
{
25+
if (!frameworkPath.EndsWith (".framework", StringComparison.OrdinalIgnoreCase) || !Directory.Exists (frameworkPath))
26+
return frameworkPath;
27+
28+
// Try to read the CFBundleExecutable from Info.plist
29+
var infoPlistPath = Path.Combine (frameworkPath, "Info.plist");
30+
if (File.Exists (infoPlistPath)) {
31+
try {
32+
var plist = PDictionary.FromFile (infoPlistPath);
33+
var bundleExecutable = plist?.GetCFBundleExecutable ();
34+
if (!string.IsNullOrEmpty (bundleExecutable)) {
35+
return Path.Combine (frameworkPath, bundleExecutable);
36+
}
37+
} catch {
38+
// If reading the plist fails, fall back to the default behavior
39+
}
40+
}
41+
42+
// Fall back to the default assumption: framework name without extension
43+
return Path.Combine (frameworkPath, Path.GetFileNameWithoutExtension (frameworkPath));
44+
}
45+
2346
public override bool Execute ()
2447
{
2548
if (ShouldExecuteRemotely ())
@@ -32,7 +55,7 @@ public override bool Execute ()
3255
var frameworkExecutablePath = PathUtils.ConvertToMacPath (item.ItemSpec);
3356
try {
3457
if (frameworkExecutablePath.EndsWith (".framework", StringComparison.OrdinalIgnoreCase) && Directory.Exists (frameworkExecutablePath)) {
35-
frameworkExecutablePath = Path.Combine (frameworkExecutablePath, Path.GetFileNameWithoutExtension (frameworkExecutablePath));
58+
frameworkExecutablePath = GetFrameworkExecutablePath (frameworkExecutablePath);
3659
}
3760

3861
if (OnlyFilterFrameworks && !Path.GetDirectoryName (frameworkExecutablePath).EndsWith (".framework", StringComparison.OrdinalIgnoreCase)) {
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
using System;
2+
using System.IO;
3+
using Microsoft.Build.Framework;
4+
using Microsoft.Build.Utilities;
5+
using NUnit.Framework;
6+
using Xamarin.MacDev.Tasks;
7+
8+
#nullable enable
9+
10+
namespace Xamarin.MacDev.Tasks.Tests {
11+
12+
[TestFixture]
13+
public class FilterStaticFrameworksTaskTest {
14+
15+
string tempDir = "";
16+
17+
[SetUp]
18+
public void Setup ()
19+
{
20+
tempDir = Path.Combine (Path.GetTempPath (), Guid.NewGuid ().ToString ());
21+
Directory.CreateDirectory (tempDir);
22+
}
23+
24+
[TearDown]
25+
public void TearDown ()
26+
{
27+
if (Directory.Exists (tempDir))
28+
Directory.Delete (tempDir, true);
29+
}
30+
31+
[Test]
32+
public void TestCustomFrameworkExecutablePath ()
33+
{
34+
// Arrange: Create a mock framework with custom CFBundleExecutable
35+
var frameworkDir = Path.Combine (tempDir, "libavcodec.framework");
36+
Directory.CreateDirectory (frameworkDir);
37+
38+
// Create Info.plist with custom CFBundleExecutable
39+
var infoPlistContent = @"<?xml version=""1.0"" encoding=""UTF-8""?>
40+
<!DOCTYPE plist PUBLIC ""-//Apple//DTD PLIST 1.0//EN"" ""http://www.apple.com/DTDs/PropertyList-1.0.dtd"">
41+
<plist version=""1.0"">
42+
<dict>
43+
<key>CFBundleExecutable</key>
44+
<string>libavcodec.dylib</string>
45+
<key>CFBundleIdentifier</key>
46+
<string>com.ffmpeg.libavcodec</string>
47+
</dict>
48+
</plist>";
49+
File.WriteAllText (Path.Combine (frameworkDir, "Info.plist"), infoPlistContent);
50+
51+
// Create the custom executable file
52+
var customExecutablePath = Path.Combine (frameworkDir, "libavcodec.dylib");
53+
File.WriteAllText (customExecutablePath, "mock executable");
54+
55+
// Act: Use reflection to test the helper method
56+
var method = typeof (FilterStaticFrameworks).GetMethod ("GetFrameworkExecutablePath",
57+
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
58+
var result = method?.Invoke (null, new object[] { frameworkDir }) as string;
59+
60+
// Assert: Should return the custom executable path from CFBundleExecutable
61+
Assert.That (result, Is.EqualTo (customExecutablePath), "Should use CFBundleExecutable from Info.plist");
62+
}
63+
64+
[Test]
65+
public void TestDefaultFrameworkExecutablePath ()
66+
{
67+
// Arrange: Create a framework without Info.plist (or with default CFBundleExecutable)
68+
var frameworkDir = Path.Combine (tempDir, "TestFramework.framework");
69+
Directory.CreateDirectory (frameworkDir);
70+
71+
var expectedPath = Path.Combine (frameworkDir, "TestFramework");
72+
73+
// Act: Use reflection to test the helper method
74+
var method = typeof (FilterStaticFrameworks).GetMethod ("GetFrameworkExecutablePath",
75+
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
76+
var result = method?.Invoke (null, new object[] { frameworkDir }) as string;
77+
78+
// Assert: Should return the default framework executable path
79+
Assert.That (result, Is.EqualTo (expectedPath), "Should use default framework executable path");
80+
}
81+
82+
[Test]
83+
public void TestNonFrameworkPath ()
84+
{
85+
// Arrange: Use a non-framework path
86+
var nonFrameworkPath = Path.Combine (tempDir, "regular_file.dylib");
87+
88+
// Act: Use reflection to test the helper method
89+
var method = typeof (FilterStaticFrameworks).GetMethod ("GetFrameworkExecutablePath",
90+
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
91+
var result = method?.Invoke (null, new object[] { nonFrameworkPath }) as string;
92+
93+
// Assert: Should return the path unchanged
94+
Assert.That (result, Is.EqualTo (nonFrameworkPath), "Should return non-framework paths unchanged");
95+
}
96+
}
97+
}

0 commit comments

Comments
 (0)