Skip to content

Commit 31ffebd

Browse files
universal build
1 parent befdf77 commit 31ffebd

7 files changed

Lines changed: 318 additions & 67 deletions

File tree

MacUtilGUI/Services/ScriptService.fs

Lines changed: 61 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,13 @@ module ScriptService =
2525
if trimmed.Contains("tty -s") ||
2626
trimmed.Contains("[ -t 0 ]") ||
2727
trimmed.Contains("[[ -t 0 ]]") ||
28-
trimmed.Contains("if tty") then
28+
trimmed.Contains("if tty") ||
29+
trimmed.Contains("test -t 0") ||
30+
trimmed.Contains("[ -t 1 ]") ||
31+
trimmed.Contains("[[ -t 1 ]]") ||
32+
trimmed.Contains("test -t 1") ||
33+
trimmed.Contains("isatty") ||
34+
trimmed.Contains("stdin is not a TTY") then
2935
"# TTY check disabled for .app bundle execution: " + line
3036

3137
// Force non-interactive mode for package managers
@@ -50,21 +56,43 @@ module ScriptService =
5056
elif trimmed.Contains("command -v brew") then
5157
line + " 2>/dev/null"
5258

59+
// Handle common non-interactive mode messages
60+
elif trimmed.Contains("Running in non-interactive mode") then
61+
"# " + line + " # Suppressed for GUI execution"
62+
5363
else
5464
line)
5565

56-
// Add non-interactive environment setup at the beginning
66+
// Add comprehensive non-interactive environment setup at the beginning
5767
let header = """#!/bin/bash
68+
# Force non-interactive mode for GUI execution
5869
export TERM=${TERM:-xterm-256color}
70+
export DEBIAN_FRONTEND=noninteractive
71+
export CI=true
72+
export NONINTERACTIVE=1
73+
export FORCE_NONINTERACTIVE=1
5974
export HOMEBREW_NO_ENV_HINTS=1
6075
export HOMEBREW_NO_INSTALL_CLEANUP=1
6176
export HOMEBREW_NO_AUTO_UPDATE=1
77+
export HOMEBREW_NO_ANALYTICS=1
78+
export HOMEBREW_NO_INSECURE_REDIRECT=1
6279
63-
# Disable TTY-related functions that cause issues
80+
# Override TTY-related functions and commands that cause issues
6481
function tty() {
6582
return 1 # Always return "not a TTY"
6683
}
6784
85+
function isatty() {
86+
return 1 # Always return "not a TTY"
87+
}
88+
89+
# Redirect stdin from /dev/null to ensure non-interactive behavior
90+
exec < /dev/null
91+
92+
# Set bash options for non-interactive execution
93+
set +o posix # Disable POSIX mode which can cause TTY issues
94+
set +m # Disable job control
95+
6896
"""
6997

7098
// Combine header with processed script content
@@ -328,8 +356,28 @@ function tty() {
328356
// Use osascript to run the script with elevated privileges
329357
// Note: osascript doesn't provide real-time output, so we'll get all output at the end
330358

331-
// Create a wrapper script that sets environment and runs the main script
332-
let wrapperScript = sprintf "#!/bin/bash\nexport TERM=xterm-256color\nexport HOMEBREW_NO_ENV_HINTS=1\nexport HOMEBREW_NO_INSTALL_CLEANUP=1\nexport HOMEBREW_NO_AUTO_UPDATE=1\nexec \"%s\"\n" tempFilePath
359+
// Create a wrapper script that sets comprehensive environment and runs the main script
360+
let wrapperScript =
361+
"#!/bin/bash\n" +
362+
"export TERM=xterm-256color\n" +
363+
"export DEBIAN_FRONTEND=noninteractive\n" +
364+
"export CI=true\n" +
365+
"export NONINTERACTIVE=1\n" +
366+
"export FORCE_NONINTERACTIVE=1\n" +
367+
"export HOMEBREW_NO_ENV_HINTS=1\n" +
368+
"export HOMEBREW_NO_INSTALL_CLEANUP=1\n" +
369+
"export HOMEBREW_NO_AUTO_UPDATE=1\n" +
370+
"export HOMEBREW_NO_ANALYTICS=1\n" +
371+
"export HOMEBREW_NO_INSECURE_REDIRECT=1\n" +
372+
"\n" +
373+
"# Override TTY functions for elevated execution\n" +
374+
"function tty() { return 1; }\n" +
375+
"function isatty() { return 1; }\n" +
376+
"\n" +
377+
"# Redirect stdin from /dev/null\n" +
378+
"exec < /dev/null\n" +
379+
"\n" +
380+
sprintf "exec \"%s\"\n" tempFilePath
333381

334382
let wrapperPath = tempFilePath + "_wrapper.sh"
335383
File.WriteAllText(wrapperPath, wrapperScript)
@@ -436,18 +484,18 @@ function tty() {
436484
startInfo.RedirectStandardOutput <- true
437485
startInfo.RedirectStandardError <- true
438486

439-
// Set environment variables to handle non-TTY execution
487+
// Set comprehensive environment variables to handle non-TTY execution
440488
startInfo.EnvironmentVariables.["TERM"] <- "xterm-256color"
441489
startInfo.EnvironmentVariables.["DEBIAN_FRONTEND"] <- "noninteractive"
442490
startInfo.EnvironmentVariables.["CI"] <- "true"
491+
startInfo.EnvironmentVariables.["NONINTERACTIVE"] <- "1"
492+
startInfo.EnvironmentVariables.["FORCE_NONINTERACTIVE"] <- "1"
443493
startInfo.EnvironmentVariables.["HOMEBREW_NO_ENV_HINTS"] <- "1"
444494
startInfo.EnvironmentVariables.["HOMEBREW_NO_INSTALL_CLEANUP"] <- "1"
445495
startInfo.EnvironmentVariables.["HOMEBREW_NO_AUTO_UPDATE"] <- "1"
446-
startInfo.EnvironmentVariables.["NONINTERACTIVE"] <- "1"
496+
startInfo.EnvironmentVariables.["HOMEBREW_NO_ANALYTICS"] <- "1"
497+
startInfo.EnvironmentVariables.["HOMEBREW_NO_INSECURE_REDIRECT"] <- "1"
447498

448-
// Force scripts to run in non-interactive mode
449-
startInfo.EnvironmentVariables.["FORCE_NONINTERACTIVE"] <- "1"
450-
451499
let proc = Process.Start(startInfo)
452500

453501
if proc <> null then
@@ -594,13 +642,15 @@ function tty() {
594642
startInfo.RedirectStandardOutput <- true
595643
startInfo.RedirectStandardError <- true
596644

597-
// Set environment variables to handle non-TTY execution
645+
// Set comprehensive environment variables to handle non-TTY execution
598646
startInfo.EnvironmentVariables.["TERM"] <- "xterm-256color"
599647
startInfo.EnvironmentVariables.["DEBIAN_FRONTEND"] <- "noninteractive"
600648
startInfo.EnvironmentVariables.["CI"] <- "true"
601649
startInfo.EnvironmentVariables.["HOMEBREW_NO_ENV_HINTS"] <- "1"
602650
startInfo.EnvironmentVariables.["HOMEBREW_NO_INSTALL_CLEANUP"] <- "1"
603651
startInfo.EnvironmentVariables.["HOMEBREW_NO_AUTO_UPDATE"] <- "1"
652+
startInfo.EnvironmentVariables.["HOMEBREW_NO_ANALYTICS"] <- "1"
653+
startInfo.EnvironmentVariables.["HOMEBREW_NO_INSECURE_REDIRECT"] <- "1"
604654
startInfo.EnvironmentVariables.["NONINTERACTIVE"] <- "1"
605655

606656
// Force scripts to run in non-interactive mode

MacUtilGUI/build_universal.sh

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
#!/bin/bash
2+
3+
# Quick Universal App Builder for MacUtil GUI
4+
# This script creates only the universal app bundle without individual architecture builds
5+
6+
echo "🚀 Building Universal MacUtil GUI App..."
7+
echo
8+
9+
# Configuration
10+
APP_NAME="MacUtilGUI"
11+
BUNDLE_NAME="MacUtil"
12+
BUNDLE_IDENTIFIER="com.macutil.gui"
13+
VERSION="0.2.0"
14+
COPYRIGHT="Copyright © 2025 CT Tech Group LLC. All rights reserved."
15+
16+
# Colors for output
17+
RED='\033[0;31m'
18+
GREEN='\033[0;32m'
19+
BLUE='\033[0;34m'
20+
YELLOW='\033[1;33m'
21+
NC='\033[0m' # No Color
22+
23+
print_status() {
24+
echo -e "${BLUE}ℹ️ $1${NC}"
25+
}
26+
27+
print_success() {
28+
echo -e "${GREEN}$1${NC}"
29+
}
30+
31+
print_error() {
32+
echo -e "${RED}$1${NC}"
33+
}
34+
35+
# Clean previous builds
36+
print_status "Cleaning previous builds..."
37+
dotnet clean -c Release > /dev/null 2>&1
38+
rm -rf ./bin/Release/net9.0/publish/
39+
rm -rf ./dist/
40+
mkdir -p ./dist/
41+
42+
# Restore packages
43+
print_status "Restoring NuGet packages..."
44+
dotnet restore > /dev/null
45+
46+
# Build for Intel x64
47+
print_status "Building Intel x64 binary..."
48+
dotnet publish -c Release -r osx-x64 -p:UseAppHost=true --self-contained true -o ./bin/Release/net9.0/publish/osx-x64/ > /dev/null 2>&1
49+
if [ $? -ne 0 ]; then
50+
print_error "Intel x64 build failed"
51+
exit 1
52+
fi
53+
54+
# Build for Apple Silicon ARM64
55+
print_status "Building Apple Silicon ARM64 binary..."
56+
dotnet publish -c Release -r osx-arm64 -p:UseAppHost=true --self-contained true -o ./bin/Release/net9.0/publish/osx-arm64/ > /dev/null 2>&1
57+
if [ $? -ne 0 ]; then
58+
print_error "Apple Silicon ARM64 build failed"
59+
exit 1
60+
fi
61+
62+
# Create Universal App Bundle
63+
print_status "Creating Universal App Bundle..."
64+
universal_app="./dist/${BUNDLE_NAME}-Universal.app"
65+
mkdir -p "$universal_app/Contents/MacOS"
66+
mkdir -p "$universal_app/Contents/Resources"
67+
68+
# Create universal binary using lipo
69+
print_status "Merging binaries with lipo..."
70+
lipo -create \
71+
"./bin/Release/net9.0/publish/osx-x64/$APP_NAME" \
72+
"./bin/Release/net9.0/publish/osx-arm64/$APP_NAME" \
73+
-output "$universal_app/Contents/MacOS/$APP_NAME" 2>/dev/null
74+
75+
if [ $? -ne 0 ]; then
76+
print_error "Failed to create universal binary with lipo"
77+
exit 1
78+
fi
79+
80+
# Copy dependencies
81+
rsync -a --exclude="$APP_NAME" "./bin/Release/net9.0/publish/osx-x64/" "$universal_app/Contents/MacOS/" 2>/dev/null
82+
83+
# Create Info.plist
84+
cat > "$universal_app/Contents/Info.plist" << EOF
85+
<?xml version="1.0" encoding="UTF-8"?>
86+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
87+
<plist version="1.0">
88+
<dict>
89+
<key>CFBundleIconFile</key>
90+
<string>MacUtilGUI.icns</string>
91+
<key>CFBundleIdentifier</key>
92+
<string>$BUNDLE_IDENTIFIER</string>
93+
<key>CFBundleName</key>
94+
<string>$BUNDLE_NAME</string>
95+
<key>CFBundleDisplayName</key>
96+
<string>MacUtil GUI</string>
97+
<key>CFBundleVersion</key>
98+
<string>$VERSION</string>
99+
<key>CFBundleShortVersionString</key>
100+
<string>1.0</string>
101+
<key>LSMinimumSystemVersion</key>
102+
<string>10.15</string>
103+
<key>CFBundleExecutable</key>
104+
<string>$APP_NAME</string>
105+
<key>CFBundleInfoDictionaryVersion</key>
106+
<string>6.0</string>
107+
<key>CFBundlePackageType</key>
108+
<string>APPL</string>
109+
<key>CFBundleSignature</key>
110+
<string>????</string>
111+
<key>NSHighResolutionCapable</key>
112+
<true/>
113+
<key>NSPrincipalClass</key>
114+
<string>NSApplication</string>
115+
<key>LSApplicationCategoryType</key>
116+
<string>public.app-category.utilities</string>
117+
<key>NSRequiresAquaSystemAppearance</key>
118+
<false/>
119+
<key>NSHumanReadableCopyright</key>
120+
<string>$COPYRIGHT</string>
121+
</dict>
122+
</plist>
123+
EOF
124+
125+
# Copy icon
126+
if [ -f "MacUtilGUI.icns" ]; then
127+
cp "MacUtilGUI.icns" "$universal_app/Contents/Resources/"
128+
fi
129+
130+
# Make executable
131+
chmod +x "$universal_app/Contents/MacOS/$APP_NAME"
132+
133+
# Show results
134+
universal_size=$(du -sh "$universal_app" | cut -f1)
135+
print_success "Universal app created: $universal_app"
136+
print_status "Bundle size: $universal_size"
137+
138+
# Verify architecture
139+
print_status "Verifying universal binary:"
140+
lipo -info "$universal_app/Contents/MacOS/$APP_NAME"
141+
142+
echo
143+
print_success "🎉 Universal build complete!"
144+
print_status "📱 Your app will run on both Intel and Apple Silicon Macs"

0 commit comments

Comments
 (0)