-
Notifications
You must be signed in to change notification settings - Fork 426
216 lines (185 loc) · 8.91 KB
/
Copy pathframework-validation.yml
File metadata and controls
216 lines (185 loc) · 8.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
name: Framework Structure Validation
on:
pull_request:
branches: [main]
paths:
- 'Sources/FluidAudio/Frameworks/**'
push:
branches: [main]
paths:
- 'Sources/FluidAudio/Frameworks/**'
jobs:
validate-framework-structure:
name: Validate Framework Structure
runs-on: macos-15
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Check ESpeakNG Framework Structure
run: |
set -e
FRAMEWORK_PATH="Sources/FluidAudio/Frameworks/ESpeakNG.xcframework"
echo "🔍 Validating framework structure..."
echo ""
# Function to validate a single framework variant
validate_framework() {
local variant_path="$1"
local variant_name=$(basename "$(dirname "$variant_path")")
local variant_name_lower=$(echo "$variant_name" | tr '[:upper:]' '[:lower:]')
local requires_versioned=false
# Mac Catalyst and macOS variants must be packaged as versioned bundles
if [[ "$variant_name_lower" == *"maccatalyst"* || "$variant_name_lower" == *"macos"* ]]; then
requires_versioned=true
fi
if [ ! -d "$variant_path" ]; then
echo "⚠️ Skipping $variant_name (not found)"
return 0
fi
echo "📦 Validating $variant_name variant..."
# Check if framework uses versioning (macOS / Catalyst) or flat structure (iOS)
if [ -d "$variant_path/Versions" ]; then
echo " ✓ Versioned framework detected"
# Check Versions/Current symlink exists
if [ ! -L "$variant_path/Versions/Current" ]; then
echo " ❌ ERROR: Versions/Current symlink not found"
return 1
fi
echo " ✓ Versions/Current symlink exists"
# Check Versions/Current points to A
local current_target
current_target=$(readlink "$variant_path/Versions/Current")
if [ "$current_target" != "A" ]; then
echo " ❌ ERROR: Versions/Current points to '$current_target' instead of 'A'"
return 1
fi
echo " ✓ Versions/Current → A"
# Check top-level symlinks point to Versions/Current/* (not Versions/A/*)
local symlinks=("ESpeakNG" "Headers" "Modules" "Resources")
for symlink in "${symlinks[@]}"; do
if [ ! -L "$variant_path/$symlink" ]; then
echo " ❌ ERROR: $symlink is not a symlink"
return 1
fi
local target
target=$(readlink "$variant_path/$symlink")
if [[ ! "$target" =~ ^Versions/Current/ ]]; then
echo " ❌ ERROR: $symlink points to '$target' instead of Versions/Current/*"
return 1
fi
done
echo " ✓ Top-level symlinks point to Versions/Current/*"
# Ensure Info.plist is stored within the versioned resources
local info_plist_versioned="$variant_path/Versions/A/Resources/Info.plist"
local info_plist_current="$variant_path/Versions/Current/Resources/Info.plist"
local info_plist_resources="$variant_path/Resources/Info.plist"
if [ ! -f "$info_plist_versioned" ]; then
echo " ❌ ERROR: Info.plist missing at Versions/A/Resources/Info.plist"
return 1
fi
if [ ! -f "$info_plist_current" ]; then
echo " ❌ ERROR: Info.plist missing at Versions/Current/Resources/Info.plist"
return 1
fi
if [ ! -f "$info_plist_resources" ]; then
echo " ❌ ERROR: Info.plist missing via Resources/Info.plist symlink"
return 1
fi
echo " ✓ Info.plist correctly nested inside Resources"
# Check that the actual binary exists and is valid
local binary_path="$variant_path/Versions/A/ESpeakNG"
if [ ! -f "$binary_path" ]; then
echo " ❌ ERROR: Binary not found at $binary_path"
return 1
fi
echo " ✓ Binary file exists: Versions/A/ESpeakNG"
# Verify it's a valid Mach-O binary
local file_type
file_type=$(file "$binary_path" | grep -o "Mach-O\|executable")
if [ -z "$file_type" ]; then
echo " ❌ ERROR: Binary is not a valid Mach-O file"
return 1
fi
echo " ✓ Valid Mach-O binary"
# Try to verify code signature (if signed)
if codesign -v "$binary_path" 2>/dev/null; then
echo " ✓ Code signature valid"
else
echo " ⚠️ Code signature not valid (expected for local builds)"
fi
else
if [ "$requires_versioned" = true ]; then
echo " ❌ ERROR: $variant_name must use a versioned framework layout (missing Versions/ directory)"
return 1
fi
# Flat framework structure (iOS)
echo " ✓ Flat framework structure detected (iOS)"
# Check binary exists directly
local binary_path="$variant_path/ESpeakNG"
if [ ! -f "$binary_path" ]; then
echo " ❌ ERROR: Binary not found at ESpeakNG"
return 1
fi
echo " ✓ Binary file exists: ESpeakNG"
# Verify it's a valid Mach-O binary
local file_type
file_type=$(file "$binary_path" | grep -o "Mach-O\|executable")
if [ -z "$file_type" ]; then
echo " ❌ ERROR: Binary is not a valid Mach-O file"
return 1
fi
echo " ✓ Valid Mach-O binary"
fi
echo ""
return 0
}
# Validate all framework variants
all_valid=true
for variant in "$FRAMEWORK_PATH"/*; do
if [ -d "$variant" ] && [ -d "$variant/ESpeakNG.framework" ]; then
validate_framework "$variant/ESpeakNG.framework" || all_valid=false
fi
done
if [ "$all_valid" = true ]; then
echo "✅ All framework variants are valid!"
exit 0
else
echo "❌ Framework validation failed"
exit 1
fi
- name: Check for Common Framework Issues
run: |
set -e
FRAMEWORK_PATH="Sources/FluidAudio/Frameworks/ESpeakNG.xcframework"
echo "🔎 Checking for common framework structure issues..."
echo ""
echo "🔠 Verifying binary casing inside versioned frameworks..."
found_versioned=false
while IFS= read -r -d '' version_dir; do
found_versioned=true
actual_name=$(python3 -c 'import os, sys; path=sys.argv[1]; target="espeakng"; print(next((n for n in os.listdir(path) if n.lower()==target), ""))' "$version_dir")
if [ -z "$actual_name" ]; then
echo "❌ ERROR: No ESpeakNG binary found inside $version_dir"
exit 1
fi
if [ "$actual_name" != "ESpeakNG" ]; then
echo "❌ ERROR: Binary '$actual_name' found in $version_dir (expected ESpeakNG)"
echo " This would cause dyld errors on case-sensitive filesystems"
exit 1
fi
done < <(find "$FRAMEWORK_PATH" -type d -path "*/ESpeakNG.framework/Versions/A" -print0)
if [ "$found_versioned" = false ]; then
echo " ⚠️ No versioned frameworks found to inspect"
else
echo " ✓ Binary casing validated in versioned slices"
fi
echo ""
echo "🔗 Checking for broken symlinks..."
while IFS= read -r -d '' framework; do
while IFS= read -r -d '' link; do
if [ -L "$link" ] && ! [ -e "$link" ]; then
echo "❌ ERROR: Broken symlink: $(basename "$link")"
exit 1
fi
done < <(find "$framework" -type l -print0)
done < <(find "$FRAMEWORK_PATH" -type d -name "ESpeakNG.framework" -print0)
echo "✅ All symlinks are valid"