Code and comments ("EXPLANATION:") on how my nightly builds work (it's close to the release builds). With the discussion you're already having maybe it's enough to gain some insight from this instead of blindly replicating my code. It's been in use for a long time now and can surely be made better. Helper files in subsequent emails. I don't intend for anyone to copy this out, I will supply the VM where all of this is included already - this is to add to the discussion you're already having.
This script is run every X minutes from cron. Triggering a similar script on commit as a CI build would be way better.
#!/bin/bash# pulls latest Hatari sources, builds and copies to known external URL
if [ ! -z "$(/opt/local/bin/pidof automated_build.sh)" ]; then
exit 0
fi
export SDKROOT="/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk"export PATH="$PATH":/opt/local/bin/
cd /Users/troed/dev/hatari
# here to give the network some time to wake up
sleep 5
# if nothing has changed, do nothing
git remote update
git log ..@{u} > ../change.tmp
if [ -s ../change.tmp ]; then
xcodebuild -sdk "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk" -UseModernBuildSystem=NO clean -project Hatari.xcodeproj > ../hatari_nightlies/build.log
# has the project regenerated and lost our build script?
# EXPLANATION: When the Xcode project is re-generated the manually inserted post buildscript is lost. This code re-inserts it. This is a dirty fix that hopefully can be avoided by someone who does this better than me :) This is the script that runs otool and fixes files and paths that are packaged together for a redistributable binary.
found=`cat "Hatari.xcodeproj/project.pbxproj" | grep script2 | wc -l`
if [ ${found} -eq 0 ]; then
a="/* Begin PBXShellScriptBuildPhase section */"
b=$(cat script2)
c='/* Build configuration list for PBXNativeTarget "hatari" */;'
d=" 3B81ADC925A4C8110093582A /* ShellScript */,"
rm temp
while IFS= read -r line; do
input="$line"
if [[ $line = *"$c" ]]; then
echo "$input" >> temp
IFS= read -r line
echo "$line" >> temp
IFS= read -r line
echo "$line" >> temp
IFS= read -r line
echo "$line" >> temp
IFS= read -r line
echo "$line" >> temp
IFS= read -r line
echo "$line" >> temp
echo "$d" >> temp
else
output=${input/$a/"$b"}
echo "$output" >> temp
fi
done < "Hatari.xcodeproj/project.pbxproj"
mv temp Hatari.xcodeproj/project.pbxproj
fi
today=`date '+%Y%m%d_%H%M%S'`
# EXPLANATION: I have local changes made to a few files that I need to keep.
git stash
git checkout master
git pull
git stash pop
ret=$?
cp ../change.tmp ../change.tm2
# add newline to end of change.log if there is none
# EXPLANATION: Nightly builds include a change.log with commit comments
[ -n "$(tail -c1 ../hatari_nightlies/change.log)" ] && echo >> ../hatari_nightlies/change.log
cat ../hatari_nightlies/change.log >> ../change.tm2
cp ../change.tm2 ../hatari_nightlies/change.log
if [ ${ret} -eq 0 ]; then
bsuccess=false
# make sure __DATE__ and __TIME__ are up2date
# EXPLANATION: Doesn't build otherwise
touch src/main.c
xcodebuild -sdk "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk" -UseModernBuildSystem=NO -scheme ALL_BUILD -project Hatari.xcodeproj >> ../hatari_nightlies/build.log
if [ $? -eq 0 ]; then
# final sanity check that our build script indeed has run
# EXPLANATION: Dirty hack, counting whether otool has run and now points to included files instead of dynamically linked from the build system
patched=`otool -L src/Release/Hatari.app/Contents/MacOS/hatari | grep "@executable_path" | wc -l`
if [ ${patched} -eq 5 ]; then
bsuccess=true
fi
fi
if [ "$bsuccess" = true ]; then
# this needs to be hatari in lowercase, CMake generates 'Hatari'
defaults write /Users/troed/dev/hatari/src/Release/Hatari.app/Contents/Info.plist CFBundleExecutable -string "hatari"
# EXPLANATION: Well, otherwise we can't codesign ...
security unlock-keychain -p <password> login.keychain
export CODESIGN_ALLOCATE="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/codesign_allocate"
codesign --force --options=runtime --sign "Developer ID Application: Troed Sangberg (467URBKK99)" src/Release/libFloppy.a >> ../hatari_nightlies/build.log
codesign --force --deep --options=runtime --sign "Developer ID Application: Troed Sangberg (467URBKK99)" --entitlements /Users/troed/dev/hatari/hatari.app.xcent src/Release/hatari.app >> ../hatari_nightlies/build.log
dest=Hatari.$today.dmg
cd /tmp/
/Users/troed/npm-global/lib/node_modules/appdmg/bin/appdmg.js /Users/troed/dev/hataridev.json $dest >> /Users/troed/dev/hatari_nightlies/build.log
# notarize our dmg
uuid=$(/usr/bin/xcrun altool --notarize-app --primary-bundle-id "org.tuxfamily.Hatari" --username "troed@xxxxxxxx" --password <password> --file $dest --output-format "xml" | xmllint --xpath "string(//plist/dict/dict/string)" -)
# need to loop here waiting for notarizing to succeed
count=0
inprogress=true
success=false
while [ "${count}" -lt 20 ] && [ "${inprogress}" == true ]; do
sleep 60
result=$(/usr/bin/xcrun altool --notarization-info "$uuid" --username "troed@xxxxxxxx" --password <password> | grep "Status:") echo ${result} >> /Users/troed/dev/hatari_nightlies/build.log
words=($result)
if [[ "${words[1]}" == "success" ]]; then
inprogress=false
success=true
elif [[ "${words[1]}" == "invalid" ]]; then
inprogress=false
else
((count++))
fi
done
if [ "$success" = true ]; then
/usr/bin/xcrun stapler staple $dest
zip -r $dest.zip $dest
mv $dest.zip '/Users/troed/dev/hatari_macos/'
rm -rf /tmp/$dest*
/Users/troed/dev/notify.sh "Hatari macOS successfully built"
else
# signing failed, zip up the log
dest=Hatari.${today}.build_failed.log
zip -j ${dest}.zip /Users/troed/dev/hatari_nightlies/build.log
mv ${dest}.zip '/Users/troed/dev/hatari_macos/'
/Users/troed/dev/notify.sh "Hatari macOS build failure"
fi
else
# build failed, zip up the log
dest=Hatari.${today}.build_failed.log
zip -j ${dest}.zip /Users/troed/dev/hatari_nightlies/build.log
mv ${dest}.zip '/Users/troed/dev/hatari_macos/'
/Users/troed/dev/notify.sh "Hatari macOS build failure"
fi
else
# pull failed with unresolved changes
touch '/Users/troed/dev/hatari_macos/Hatari.'${today}'.build_failed'
/Users/troed/dev/notify.sh "Hatari macOS merge failure"
fi
fi
# delete all but the 10 latest .zip files
cd "/Users/troed/dev/hatari_macos/"
ls -tp *.zip | grep -v '/$' | tail -n +11 | tr '\n' '\0' | xargs -0 rm --