File indexing completed on 2024-05-12 04:28:29

0001 #!/usr/bin/env zsh
0002 #
0003 #  SPDX-License-Identifier: GPL-3.0-or-later
0004 #
0005 
0006 # macstoreprep
0007 # 
0008 # Script to prepare a dmg for mac Store submission format
0009 #
0010 
0011 if [[ -n "$ZSH_VERSION" ]]; then
0012     emulate -L ksh;
0013 fi
0014 
0015 if [[ -z $BUILDROOT ]]; then
0016     echo "ERROR: BUILDROOT env not set!"
0017     echo "\t Must point to the root of the buildfiles as stated in 3rdparty Readme"
0018     echo "exiting..."
0019     exit 1
0020 fi
0021 
0022 #recieves a path without filename
0023 get_absolute_path() {
0024     local origLoc="$(pwd)"
0025 
0026     local filename="${1}"
0027     local location="${filename}"
0028 
0029     if [[ -e "${filename}" && ! -d "${filename}" ]]; then
0030         location="$(dirname "${filename}")"
0031     fi
0032 
0033     local absolute="$(cd "${location}"; pwd)"
0034     cd "${origLoc}"
0035 
0036     echo ${absolute}
0037 }
0038 
0039 # make sure BUILDROOT is always an absolute path
0040 BUILDROOT=$(get_absolute_path "${BUILDROOT}")
0041 
0042 KRITADMG_WDIR="${BUILDROOT}/kritadmg_store"
0043 KRITADMG_MOUNT="kritadmg"
0044 if [[ -z "${KIS_SRC_DIR}" ]]; then
0045     KIS_SRC_DIR=${BUILDROOT}/krita
0046 fi
0047 if [[ -z "${KIS_BUILD_DIR}" ]]; then
0048     KIS_BUILD_DIR=${BUILDROOT}/kisbuild
0049 fi
0050 KIS_ENTITLEMENTS_DIR="${KIS_SRC_DIR}/packaging/macos/"
0051 # we look for the provisioning file in the script the directory was called
0052 KIS_PROVISION="$(get_absolute_path ".")/embedded.provisionprofile"
0053 
0054 KIS_BUNDLE_ID="org.kde.krita"
0055 
0056 # print status messages
0057 print_msg() {
0058     printf "\e[32m${1}\e[0m\n" "${@:2}"
0059     # printf "%s\n" "${1}" >> ${OUTPUT_LOG}
0060 }
0061 
0062 # print error
0063 print_error() {
0064     printf "\e[31m%s %s\e[0m\n" "Error:" "${1}"
0065 }
0066 
0067 get_script_dir() {
0068     if [[ -n "$ZSH_VERSION" ]]; then
0069         script_source="${(%):-%x}"
0070     else
0071         # transitional, macos should use ZSH
0072         script_source="${BASH_SOURCE[0]}"
0073     fi
0074     # go to target until finding root.
0075     while [ -L "${script_source}" ]; do
0076         script_target="$(readlink ${script_source})"
0077         if [[ "${script_source}" = /* ]]; then
0078             script_source="$script_target"
0079         else
0080             script_dir="$(dirname "${script_source}")"
0081             script_source="${script_dir}/${script_target}"
0082         fi
0083     done
0084     echo "$(dirname ${script_source})"
0085 }
0086 
0087 findEntitlementsFile() {
0088     if [[ -e ${KIS_ENTITLEMENTS} ]]; then
0089         return
0090     fi
0091 
0092     local fileName="macStore-entitlements.plist"
0093     local subEntitlementsFile="sandboxdev_sub-entitlements.plist"
0094 
0095     if [[ -f "${DIR_CURRENT}/${fileName}" ]]; then
0096         KIS_ENTITLEMENTS="${DIR_CURRENT}/${fileName}"
0097         KIS_SUB_ENTITLEMENTS="${DIR_CURRENT}/${subEntitlementsFile}"
0098     elif [[ -f "${KIS_ENTITLEMENTS_DIR}/${fileName}" ]]; then
0099         KIS_ENTITLEMENTS="${KIS_ENTITLEMENTS_DIR}/${fileName}"
0100         KIS_SUB_ENTITLEMENTS="${KIS_ENTITLEMENTS_DIR}/${subEntitlementsFile}"
0101     fi
0102 }
0103 
0104 # calls /usr/libexec/PlistBuddy with basic args
0105 # $1 file.plist to modify
0106 # $2 -c command
0107 # $3 plist key to modify
0108 # $4 plist value for key
0109 plistbuddy() {
0110     local plistbuddy="/usr/libexec/PlistBuddy"
0111     local filename="${1}"
0112     local cmd="${2}"
0113     local key="${3}"
0114     local value="${4}"
0115     
0116     ${plistbuddy} "${filename}" -c "${cmd}:${key} ${value}"
0117 }
0118 
0119 modifyInfoPlistContents() {
0120     local plistbuddy="/usr/libexec/PlistBuddy"
0121     local PLIST_LOC="${KRITADMG_WDIR}/krita.app/Contents"
0122     
0123     plistbuddy "${PLIST_LOC}/Info.plist" Set CFBundleIdentifier ${KIS_BUNDLE_ID}
0124     plistbuddy "${PLIST_LOC}/Info.plist" Set CFBundleVersion ${KIS_BUILD_VERSION}
0125     plistbuddy "${PLIST_LOC}/Info.plist" Set CFBundleShortVersionString ${KIS_VERSION}
0126     plistbuddy "${PLIST_LOC}/Info.plist" CFBundleLongVersionString ${KIS_VERSION}
0127 
0128     plistbuddy "${PLIST_LOC}/Library/QuickLook/kritaquicklook.qlgenerator/Contents/Info.plist" CFBundleIdentifier ${KIS_BUNDLE_ID}.quicklook
0129     plistbuddy "${PLIST_LOC}/Library/Spotlight/kritaspotlight.mdimporter/Contents/Info.plist" CFBundleIdentifier ${KIS_BUNDLE_ID}.spotlight
0130 }
0131 
0132 
0133 clean_dmg() {
0134     cd "${KRITADMG_WDIR}/krita.app/Contents/MacOS"
0135     rm krita_version
0136     rm kritarunner
0137 }
0138 
0139 batch_codesign() {
0140     local entitlements="${1}"
0141     if [[ -z "${1}" ]]; then
0142         entitlements="${KIS_ENTITLEMENTS}"
0143     fi
0144     xargs -P4 -I FILE codesign --options runtime --timestamp -f -s "${CODE_SIGNATURE}" --entitlements "${entitlements}" FILE
0145 }
0146 # Code sign must be done as recommended by apple "sign code inside out in individual stages"
0147 signBundle() {
0148     cd ${KRITADMG_WDIR}
0149 
0150     # sign Frameworks and libs
0151     cd ${KRITADMG_WDIR}/krita.app/Contents/Frameworks
0152     # remove debug version as both versions can't be signed.
0153     rm ${KRITADMG_WDIR}/krita.app/Contents/Frameworks/QtScript.framework/Versions/Current/QtScript_debug
0154     # Do not sign binaries inside frameworks except for Python's
0155     find . -type d -path "*.framework" -prune -false -o -perm +111 -not -type d | batch_codesign
0156     find Python.framework -type f -name "*.o" -or -name "*.so" -or -perm +111 -not -type d -not -type l | batch_codesign
0157     find . -type d -name "*.framework" | xargs printf "%s/Versions/Current\n" | batch_codesign
0158 
0159     # Sign all other files in Framework (needed)
0160     # there are many files in python do we need to sign them all?
0161     find krita-python-libs -type f | batch_codesign
0162     # find python -type f | batch_codesign
0163 
0164     # Sign only libraries and plugins
0165     cd ${KRITADMG_WDIR}/krita.app/Contents/PlugIns
0166     find . -type f | batch_codesign
0167 
0168     cd ${KRITADMG_WDIR}/krita.app/Contents/Library/QuickLook
0169     printf "kritaquicklook.qlgenerator" | batch_codesign
0170 
0171     cd ${KRITADMG_WDIR}/krita.app/Contents/Library/Spotlight
0172     printf "kritaspotlight.mdimporter" | batch_codesign
0173 
0174     # It is necessary to sign every binary Resource file
0175     cd ${KRITADMG_WDIR}/krita.app/Contents/Resources
0176     find . -perm +111 -type f | batch_codesign
0177 
0178     printf "${KRITADMG_WDIR}/krita.app/Contents/MacOS/ffmpeg" | batch_codesign "${KIS_SUB_ENTITLEMENTS}"
0179     printf "${KRITADMG_WDIR}/krita.app/Contents/MacOS/ffprobe" | batch_codesign "${KIS_SUB_ENTITLEMENTS}"
0180     #Finally sign krita and krita.app
0181     printf "${KRITADMG_WDIR}/krita.app/Contents/MacOS/krita" | batch_codesign
0182     printf "${KRITADMG_WDIR}/krita.app" | batch_codesign
0183 
0184     cd ${KRITADMG_WDIR}
0185 }
0186 
0187 sign_hasError() {
0188     local CODESIGN_STATUS=0
0189     for f in $(find "${KRITADMG_WDIR}/krita.app" -type f); do
0190         if [[ -z $(file ${f} | grep "Mach-O") ]]; then
0191             continue
0192         fi
0193 
0194         CODESIGN_RESULT=$(codesign -vvv --strict ${f} 2>&1 | grep "not signed")
0195 
0196         if [[ -n "${CODESIGN_RESULT}" ]]; then
0197             CODESIGN_STATUS=1
0198             printf "${f} not signed\n" >&2
0199         fi
0200     done
0201     echo ${CODESIGN_STATUS}
0202 }
0203 
0204 
0205 print_usage () {
0206     printf "USAGE:
0207   macstoreprep.sh -f=<krita.dmg> [-s=<identity>] [-notarize-ac=<apple-account>]
0208 
0209     -bv \t\t bundle version: mac store needs to identify each submission as unique. for this
0210         \t\t we do not bump the krita version but the bundle version. The format is [M.m.p] and
0211         \t\t is totally independent from krita release version.
0212 
0213     -s \t\t\t Sign Identity for 3rd party application
0214 
0215     -sins \t\t Sign Identity for 3rd party Dev installer
0216 
0217     -notarize-ac \t Apple account name for notarization purposes
0218         \t\t script will attempt to get password from keychain, if fails provide one with
0219         \t\t the -notarize-pass option: To add a password run
0220 
0221         \t\t security add-generic-password -a \"AC_USERNAME\" -w <secret_password> -s \"AC_PASSWORD\"
0222 
0223     -notarize-pass \t If given, the Apple account password. Otherwise an attempt will be macdeployqt_exists
0224         \t\t to get the password from keychain using the account given in <notarize-ac> option.
0225 
0226     -asc-provider \t some AppleIds might need this option pass the <shortname>
0227 
0228     -f \t\t\t input dmg
0229 "
0230 }
0231 
0232 
0233 ### Script starts
0234 SCRIPT_SOURCE_DIR="$(get_script_dir)"
0235 
0236 DIR_CURRENT="$(pwd)"
0237 cd "$(get_script_dir)"
0238 SCRIPT_SOURCE_DIR="$(pwd)"
0239 cd "${DIR_CURRENT}"
0240 
0241 # Attempt to detach previous mouted DMG
0242 # if [[ -d "/Volumes/${DMG_title}" ]]; then
0243 #     echo "WARNING: Another Krita DMG is mounted!"
0244 #     echo "Attempting eject…"
0245 #     hdiutil detach "/Volumes/${DMG_title}"
0246 #     if [ $? -ne 0  ]; then
0247 #         exit 1
0248 #     fi
0249 #     echo "Success!"
0250 # fi
0251 
0252 
0253 # -- Parse input args
0254 for arg in "${@}"; do
0255     # If string starts with -sign
0256 #    if [[ ${arg} = -v=* ]]; then
0257 #        KIS_VERSION="${arg#*=}"
0258 #    fi
0259 
0260     if [[ ${arg} = -bv=* ]]; then
0261         KIS_BUILD_VERSION="${arg#*=}"
0262     fi
0263 
0264     if [[ ${arg} = -s=* ]]; then
0265         CODE_SIGNATURE="${arg#*=}"
0266     fi
0267 
0268     if [[ ${arg} = -sins=* ]]; then
0269         SIGN_DEV_INSTALL="${arg#*=}"
0270     fi
0271 
0272     if [[ ${arg} = -f=* ]]; then
0273         INPUT_STR="${arg#*=}"
0274         INPUT_DIR="$(cd $(dirname ${INPUT_STR}); pwd -P)"
0275         INPUT_DMG="${INPUT_DIR}/$(basename ${INPUT_STR})"
0276     fi
0277 
0278     if [[ ${arg} = -notarize-ac=* ]]; then
0279         NOTARIZE_ACC="${arg#*=}"
0280     fi
0281 
0282     if [[ ${arg} = -notarize-pass=* ]]; then
0283         NOTARIZE_PASS="${arg#*=}"
0284     fi
0285 
0286     if [[ ${arg} = -asc-provider=* ]]; then
0287         APPLE_TEAMID="${arg#*=}"
0288     fi
0289 
0290     if [[ ${arg} = "-h" || ${arg} = "--help" ]]; then
0291         print_usage
0292         exit 1
0293     fi
0294 done
0295 
0296 ### Code Signature & NOTARIZATION
0297 NOTARIZE="false"
0298 if [[ -n "${CODE_SIGNATURE}" ]]; then
0299     print_msg "Code will be signed with %s" "${CODE_SIGNATURE}"
0300 fi
0301 
0302 if [[ -z "${KIS_BUILD_VERSION}" ]]; then
0303     print_error "option -bv is not set!"
0304     echo "run with --help for assistance"
0305     exit
0306 fi
0307 
0308 # mount dmg
0309 
0310 if [[ ! -d "${KRITADMG_WDIR}" ]]; then
0311     mkdir "${KRITADMG_WDIR}"
0312 fi
0313 
0314 cd "${KRITADMG_WDIR}"
0315 echo "cleaning last run..."
0316 rm -rf "${KRITADMG_WDIR}/krita.app"
0317 
0318 echo "mounting ${INPUT_DMG} ..."
0319 hdiutil attach "${INPUT_DMG}" -mountpoint "${KRITADMG_MOUNT}"
0320 rsync -prult --delete "${KRITADMG_MOUNT}/krita.app/" "krita.app"
0321 
0322 hdiutil detach "${KRITADMG_MOUNT}"
0323 
0324 # attach provisioning profile
0325 cp -X "${KIS_PROVISION}" "${KRITADMG_WDIR}/krita.app/Contents/"
0326 chmod 644 "${KRITADMG_WDIR}/krita.app/Contents/${KIS_PROVISION}"
0327 
0328 # clean krita version string (app store format does not allow dashes
0329 KIS_VERSION="$(${KRITADMG_WDIR}/krita.app/Contents/MacOS/krita_version 2> /dev/null | awk '{print $1}')"
0330 KIS_VERSION=${KIS_VERSION%%-*}
0331 
0332 # try to fix permissions
0333 for f in $(find ${KRITADMG_WDIR} -not -perm +044); do
0334     chmod +r ${f}
0335 done
0336 
0337 rootfiles="$(find ${KRITADMG_WDIR} -user root -perm +400 -and -not -perm +044)"
0338 if [[ -n ${rootfiles} ]]; then
0339     echo "files \n ${rootfiles} \n cannot be read by non-root users!"
0340     echo "submission will fail, please fix and relaunch script"
0341 fi
0342 
0343 # replace signature
0344 findEntitlementsFile
0345 if [[ -z ${KIS_ENTITLEMENTS} ]]; then
0346     echo "Could not find entitlements file use for codesign"
0347     exit
0348 else
0349     echo "using ${KIS_ENTITLEMENTS}"
0350 fi
0351 
0352 modifyInfoPlistContents
0353 
0354 clean_dmg
0355 
0356 # Code sign krita.app if signature given
0357 if [[ -n "${CODE_SIGNATURE}" ]]; then
0358     signBundle
0359     if [[ $(sign_hasError) -eq 1 ]]; then
0360         print_error "CodeSign errors!"
0361         echo "stopping...."
0362         exit 1
0363     fi
0364     echo "no codesign errors"
0365     echo "preparing pkg"
0366 fi
0367 
0368 if [[ -z ${APPLE_TEAMID} ]]; then
0369     APPLE_TEAMID="<team_identifier>"
0370 fi
0371 
0372 KRITA_DMG_BASENAME="$(basename ${INPUT_STR})"
0373 KRITA_PKG_NAME="${KRITA_DMG_BASENAME%.*}.pkg"
0374 # productbuild --component ${KIS_APPLOC}/krita.app  /Applications krita5_submit.pkg --sign \"3rd Party Mac Developer Installer: ...\" 
0375 if [[ -n "${SIGN_DEV_INSTALL}" ]]; then
0376     echo "creating krita5_submit.pkg ..."
0377     productbuild --component "${KRITADMG_WDIR}/krita.app"  "/Applications" "${KRITADMG_WDIR}/${KRITA_PKG_NAME}" --sign "${SIGN_DEV_INSTALL}"
0378 fi
0379 
0380 echo "done"
0381 
0382 print_msg "
0383 Use altool to submit the Pkg:
0384 
0385     \t xcrun altool --upload-package "${KRITADMG_WDIR}/${KRITA_PKG_NAME}" --bundle-id ${KIS_BUNDLE_ID} -t macos -u "${NOTARIZE_ACC}" --password <pass> [--asc-provider "${APPLE_TEAMID}"] --bundle-version ${KIS_BUILD_VERSION} --bundle-short-version-string ${KIS_VERSION} --apple-id <app-id_fromStore>
0386 
0387 To get <app-id_fromStore> from store go to: https://appstoreconnect.apple.com/apps ,select the app you wish to upload to,
0388 click on App information on the left side, and search for 'Apple ID' field.
0389 
0390 \n"