# Dali Clock for MacOS X, Copyright © 2005-2022 Jamie Zawinski.

XCODE_APP = /Applications/Xcode.app

# To build savers that will run on MacOS 10.6 and 10.7, Xcode 5.0.2 must
# be used (as that's the latest version of Xcode that ships with a version
# of clang that implements "-fobjc-gc").  However, Xcode 5.0.2 will not
# launch on MacOS 10.11 or later.
#
# XCODE_APP = /Applications/Xcode-5.0.2.app

TARGETS    = -target DaliClock \
	     -target DaliClockStore \
	     -target DaliClockSaver \
	     -target DaliClockWidget
#ARCH      = -arch i386 -arch x86_64 ONLY_ACTIVE_ARCH=NO
XCODEBUILD = $(XCODE_APP)/Contents/Developer/usr/bin/xcodebuild
SETFILE    = $(XCODE_APP)/Contents/Developer/Tools/SetFile
SETICON    = ./seticon.pl

# Using $(MAKE) directly means the shell executes things even with "make -n"
MAKE2 = $(MAKE)


default: release
all: debug release

clean:
	-rm -rf build
#	$(XCODEBUILD) $(TARGETS) clean

distclean:
	-rm -f config.status config.cache config.log \
	  *.bak *.rej TAGS *~ "#"*
	-rm -rf autom4te*.cache
	-rm -rf build
#	-rm -rf Sparkle.framework

distdepend:: Sparkle.framework
distdepend:: update_plist_version
distdepend:: update_bindist_version

debug: distdepend
	$(XCODEBUILD) $(ARCH) $(TARGETS) -configuration Debug   build

release:: distdepend
	$(XCODEBUILD) $(ARCH) $(TARGETS) -configuration Release build
	spctl --assess --type execute build/Release/*.app

release:: check_versions

Sparkle.framework:
	rm -rf bin sparkle-bin
	tar -vxjf ../archive/Sparkle-1.27.0.tar.xz \
	  --exclude CHANGELOG \
	  --exclude LICENSE \
	  --exclude SampleAppcast.xml \
	  --exclude Sparkle.framework.dSYM \
	  --exclude Sparkle\ Test\ App\*
	mv bin sparkle-bin


check_versions:
	@\
  U=../version.h ;							\
  V=`sed -n 's/[^0-9]*\([0-9]\.[0-9][^. ;]*\).*/\1/p' < $$U` ;		\
  DIR=build/Release ;							\
  RESULT=0 ;								\
  for P in `find $$DIR -name Info.plist |				\
	    grep -v Sparkle.framework` ; do				\
     V2=`perl -0000 -n -e						\
	'm@<key>CFBundleVersion</key>\s*<string>(.*?)</string>@si 	\
	 && print $$1' < $$P` ;						\
     if [ "$$V2" != "$$V" ] ; then					\
       echo "Wrong version: $$P ($$V2)" ;				\
       RESULT=1 ;							\
     fi ;								\
  done ;								\
  if [ "$$RESULT" = 0 ]; then echo "Versions match ($$V2)" ; fi ;	\
  exit $$RESULT


echo_tarfiles:
	@echo `find . \
	  \( \( -name '.??*' -o -name build -o -name CVS -o -name '*~*' \
	     -o -name 'jwz.*' -o -name '*.widgetplugin' \
	     -o -name '*.psd' -o -name '*.ai'  -o -name sparkle-bin \) \
	     -prune \) \
	  -o \( -type f -o -type l \) -print \
	| sed 's@^\./@@' \
	| sort`

update_plist_version:
	@								      \
  SS="AppInfo.plist SaverInfo.plist PluginInfo.plist iPhoneInfo.plist *.wdgt/Info.plist" ;   \
  SRC=../version.h ;							      \
  V=`sed -n 's/[^0-9]*\([0-9]\.[0-9][^. ]*\).*/\1/p' $$SRC` ;		      \
  Y=`date +%Y` ;							      \
  T=/tmp/xs.$$$$ ;							      \
  for S in $$SS ; do							      \
    /bin/echo -n "Updating version number in $$S to \"$$V\"... " ;	      \
    KEYS1="CFBundleVersion|CFBundleShortVersionString" ;		      \
    KEYS2="NSHumanReadableCopyright|CFBundleLongVersionString|CFBundleGetInfoString" ; \
    perl -0777 -pne							      \
      "s@(<key>($$KEYS1)</key>\s*<string>)[^<>]+(</string>)@\$${1}$$V\$${3}@g; \
       s@(<key>($$KEYS2)</key>\s*<string>[^\d]+)[\d.]+(.*?</string>)@\$${1}$$V\$${3}@gs; \
       s@(<key>($$KEYS2)</key>\s*<string>.*?1991-)\d\d\d\d(.*?</string>)@\$${1}$$Y\$${3}@gs" \
    < $$S > $$T ;							    \
   if cmp -s $$S $$T ; then						    \
     echo "unchanged." ;						    \
   else									    \
    cat $$T > $$S ;							    \
    echo "done." ;							    \
   fi ;									    \
   rm $$T ;								    \
  done


update_bindist_version:
	@								    \
  SS="bindist.rtf Credits.html" ;					    \
  U=../version.h ;							    \
  V=`sed -n 's/[^0-9]*\([0-9]\.[0-9][^. ;]*\).*/\1/p' < $$U` ;		    \
  D=`date '+%d-%b-%Y'` ;						    \
  Y=`date '+%Y'` ;							    \
  for S in $$SS ; do							    \
   T=/tmp/xs.$$$$ ;							    \
   sed -e "s/\(.*version \)[0-9][0-9]*\.[0-9]*[ab]*[0-9]*\(.*\)/\1$$V\2/"   \
       -e "s/\(1991-\)[0-9][0-9][0-9][0-9]/\1$$Y/"			    \
       -e "s/\([0-9][0-9]-[A-Z][a-z][a-z]-[0-9][0-9][0-9]*\)/$$D/"	    \
      < $$S > $$T ;							    \
   if cmp -s $$S $$T ; then						    \
    true ;								    \
   else									    \
    cat $$T > $$S ;							    \
    echo "updated $$S to $$V $$D" ;					    \
   fi ;									    \
  done ;								    \
  rm $$T


updates.xml::
	./updates.pl DaliClock ../README ../archive ~/www/xdaliclock
	@$(MAKE2) test_sig

test_sig::
	@								    \
  U=../version.h ;							    \
  V=`sed -n 's/[^0-9]*\([0-9]\.[0-9][^. ;]*\).*/\1/p' < $$U` ;		    \
  V2="$$V" ;								      \
  V=`echo $$V | sed 's/\.//g'` ;					    \
  ZIP="../archive/DaliClock-$$V.dmg" ;					    \
  OV=`sed -n 's/^.*<title>Version \([^<>]*\).*/\1/p' updates.xml | head -1`;\
  if [ "x$$V2" != "x$$OV" ] ; then					    \
    echo "updates.xml: file version is $$OV instead of $$V2" 2>&2 ;	    \
    exit 1 ; 								    \
  fi ;									    \
  SIG1=`sed -n 's/^.*dsaSignature="\(.*\)".*/\1/p' updates.xml` ;	    \
  SIG2=`sed -n  's/^.*edSignature="\(.*\)".*/\1/p' updates.xml` ;	    \
  PUB1="sparkle_dsa_pub.pem" ;						    \
  NN="t.$$$$" ;								    \
  SIGB=/tmp/$$NN.sig ;							    \
  HASH=/tmp/$$NN.hash ;							    \
  rm -f "$$SIGB" "$$HASH" ;						    \
  if ( echo "$$SIG1" | grep -qi ERROR ); then				    \
    echo "No DSA signature in updates.xml" >&2 ; exit 1 ;		    \
  fi ;									    \
  if ( echo "$$SIG2" | grep -qi ERROR ); then				    \
    echo "No ED signature in updates.xml" >&2 ; exit 1 ;		    \
  fi ;									    \
									    \
  set -e ;								    \
  echo "$$SIG1 " | base64 -D  > "$$SIGB" ;				    \
  for OPENSSL in /usr/bin/openssl /opt/local/bin/openssl ; do		    \
    $$OPENSSL dgst -sha1 -binary  < "$$DMG"  > "$$HASH" ;		    \
    /bin/echo -n "DSA $$OPENSSL    	`$$OPENSSL version`:	" ;	    \
    $$OPENSSL dgst -sha1 -verify "$$PUB1" -signature "$$SIGB" "$$HASH" ;    \
  done ;								    \
  echo "Warning: not verifying edSignature because I don't know how..." ;   \
									    \
  rm -f "$$SIGB" "$$HASH" ;						    \


# Can no longer do: ${TARGET_BUILD_DIR}/DaliClock.wdgt
# It causes code-signing to fail with "a sealed resource is missing or
# invalid", and if we set the icon before signing (with a build phase on
# DaliClockWidget) then signing fails with "resource fork, Finder
# information, or similar detritus not allowed".


dmg:: distdepend check_versions _dmg notarize staple

_dmg::
	@								      \
  set -e ;								      \
  SRC=../version.h ;							      \
  V=`sed -n 's/[^0-9]*\([0-9]\.[0-9][^. ;]*\).*/\1/p' $$SRC` ;		      \
  V2="$$V" ;								      \
  V=`echo $$V | sed 's/\.//g'` ;					      \
  TMPDIR="build" ;							      \
  SRC="build/Release" ;							      \
  BASE="DaliClock-$$V" ;						      \
  OUTDIR="../archive" ;							      \
  DMG="$$OUTDIR/$$BASE.dmg" ;						      \
  TMPDMG="$$TMPDIR/tmp.dmg" ;						      \
  VOLNAME="DaliClock $$V2" ;						      \
  STAGE="$$TMPDIR/dmg_stage" ;						      \
  rm -f "$$DMG" ;							      \
  rm -rf "$$STAGE" ;							      \
  echo + mkdir "$$STAGE" ;						      \
         mkdir "$$STAGE" ;						      \
  FILES="$$SRC/*.app $$SRC/*.saver $$SRC/*.wdgt" ;			      \
  echo + cp -pR $$FILES "$$STAGE" ;					      \
         cp -pR $$FILES "$$STAGE" ;					      \
  set -x ;								      \
  cp -p bindist.rtf "$$STAGE/ READ ME.rtf" ;				      \
  cp -p bindist-DS_Store "$$STAGE/.DS_Store" ;				      \
  cp -p bindist.webloc "$$STAGE/DaliClock for iOS.webloc" ;		      \
  cp -p bindist2.webloc "$$STAGE/DaliClock for Android.webloc" ;	      \
  ${SETFILE} -a E "$$STAGE/ READ ME.rtf" ;				      \
  ${SETFILE} -a e $$STAGE/*.saver ;					      \
  ${SETFILE} -a e $$STAGE/*.wdgt ;					      \
  ${SETFILE} -a E $$STAGE/*.webloc ;					      \
  $(SETICON) -d daliclockSaver.icns $$STAGE/*.saver ;			      \
  $(SETICON) -d weblociOS.icns $$STAGE/*iOS*.webloc ;			      \
  $(SETICON) -d weblocAndroid.icns $$STAGE/*Android*.webloc ;		      \
									      \
  set +x ;								      \
									      \
  echo "Chowning..." ;							      \
  sudo chown -R root:wheel "$$STAGE/"* ;				      \
									      \
  echo "Checking signatures..." ;					      \
  if false; then							      \
    spctl --assess --type execute "$$STAGE/"*.app ;			      \
    spctl --assess --type install "$$STAGE/"*.{saver,wdgt} ;		      \
  else									      \
    true codesign -vv --deep --strict "$$DST/"*.app ;			      \
    true codesign -vv --deep --strict "$$DST/"*.saver ;			      \
  fi ;									      \
									      \
  set -x ;								      \
									      \
  hdiutil makehybrid -quiet -ov -hfs -hfs-volume-name "$$VOLNAME"	      \
    -hfs-openfolder "$$STAGE" "$$STAGE" -o "$$TMPDMG" ;			      \
  echo "Deleting..." ;							      \
  sudo rm -rf "$$STAGE" ;						      \
									      \
  hdiutil convert -quiet -ov -format UDBZ -imagekey zlib-level=9	      \
    "$$TMPDMG" -o "$$DMG" ;						      \
  xattr -w com.apple.quarantine "0000;00000000;;" "$$DMG" ;		      \
  rm -f "$$TMPDMG" ;							      \
									      \
  codesign --sign $(CERT2) "$$DMG" ;					      \
  if false; then							      \
    spctl --assess --type install "$$DMG" ;				      \
  else									      \
    codesign -vvv --deep --strict "$$DMG" ;				      \
  fi ;									      \
									      \
  ls -ldhgF "$$DMG" ;							      \


# To set up notarization:
#  - Log in on https://appleid.apple.com/
#  - Generate App-Specific Password, "altool-notarizer"
#  - Keychain Access / New
#  - Name: "altool-notarizer", Account: "jwz@jwz.org",
#    Pass: the one you just generated.
#
# As of Xcode 13, "altool" is obsolete because of course it is.
# The new way is "notarytool".
#
# "make notarize" will upload the DMG (slow).
#
# Note that if Sparkle.framework/.../Autoupdate.app is not independently
# signed, it won't pass. I had to add a build phase for that.
#
# - xcrun notarytool store-credentials --apple-id jwz@jwz.org
#   - Profile name: altool-notarizer
#   - App-specific password: [the above]
#   - Developer Team ID: 4627ATJELP
# - Credentials saved to Keychain.
#   To use them, specify `--keychain-profile "altool-notarizer"
#
#NOTARGS=-u "jwz@jwz.org" -p "@keychain:altool-notarizer"


# Send a notarization request, and then wait for the result.
#
notarize::
	@								      \
  set -e ;								      \
  SRC=../version.h ;							      \
  V=`sed -n 's/[^0-9]*\([0-9]\.[0-9][^. ;]*\).*/\1/p' $$SRC` ;		      \
  V=`echo $$V | sed 's/\.//g'` ;					      \
  BASE="DaliClock-$$V" ;						      \
  OUTDIR="../archive" ;							      \
  DMG="$$OUTDIR/$$BASE.dmg" ;						      \
  CMD="xcrun notarytool submit $$DMG" ;					      \
  CMD="$$CMD --keychain-profile altool-notarizer" ;			      \
  CMD="$$CMD --apple-id jwz@jwz.org --team-id 4627ATJELP --wait" ;	      \
  echo "+ $$CMD" ;  							      \
  echo "" ;								      \
  RET=`$$CMD` ;  							      \
  echo "$$RET";  							      \
  echo "" ;								      \
  ID=`echo "$$RET" | sed -n 's/.*id: *\([^ ]*\).*/\1/p' | head -1` ;	      \
  STATUS=`echo "$$RET" | sed -n 's/.*status: *\([^ .]*\).*/\1/p' | head -1` ; \
  if [ "x$$ID" = "x" ]; then						      \
    echo "unparsable ID" ;						      \
    exit 1 ;								      \
  fi ;									      \
  if [ x"$$STATUS" != "xAccepted" ]; then				      \
    echo "ERROR: Bad status: $$STATUS" ;				      \
    echo "" ;								      \
    CMD="xcrun notarytool log $$ID --keychain-profile altool-notarizer" ;     \
    echo "+ $$CMD" ;  							      \
    $$CMD ;								      \
    exit 1 ;								      \
  fi ;									      \
  echo "Notarization success: $$STATUS" ;				      \
  exit 0


# Uploading the DMG to the notarizer generated a gatekeeper ticket for
# each enclosed item.  Staple those tickets to the DMG file.
#
# If we had uploaded a .zip, we would need to staple to the enclosed item
# and re-generate the .zip, but I think we can staple directly to a DMG
# without needing to re-generate it?
#
staple::
	@								      \
  set -e ;								      \
  SRC=../version.h ;							      \
  V=`sed -n 's/[^0-9]*\([0-9]\.[0-9][^. ;]*\).*/\1/p' $$SRC` ;		      \
  V=`echo $$V | sed 's/\.//g'` ;					      \
  BASE="DaliClock-$$V" ;						      \
  OUTDIR="../archive" ;							      \
  DMG="$$OUTDIR/$$BASE.dmg" ;						      \
  set -x ;								      \
  xcrun stapler staple "$$DMG" ;					      \
  xcrun stapler validate "$$DMG" ;					      \

notarization_history::
	xcrun altool --notarization-history 0 $(NOTARGS)
	@echo 'now do: xcrun altool $(NOTARGS) --notarization-info <UUID>' ;  \
	echo 'and wget the LogFileURL' ;				      \

