File indexing completed on 2024-05-12 16:02:32
0001 #!/usr/bin/env zsh 0002 # 0003 # SPDX-License-Identifier: GPL-3.0-or-later 0004 # 0005 0006 # Krita tool to create dmg from installed source 0007 # Copies all files to a folder to be converted into the final dmg 0008 0009 # osxdeploy.sh automates the creation of the release DMG. 0010 # default background and style are used if none provided 0011 0012 # A short explanation of what it does: 0013 0014 # - Copies krita.app contents to kritadmg folder 0015 # - Copies i/share to Contents/Resources excluding unnecessary files 0016 # - Copies translations, qml and quicklook PlugIns 0017 # - Copies i/plugins and i/lib/plugins to Contents/PlugIns 0018 0019 # - Runs macdeployqt: macdeployqt is not built by default in ext_qt 0020 # build by: 0021 # cd ${BUILDROOT}/depbuild/ext_qt/ext_qt-prefix/src/ext_qt/qttools/src 0022 # make sub-macdeployqt-all 0023 # make sub-macdeployqt-install_subtargets 0024 # make install 0025 0026 # the script changes dir to installation/bin to run macdeployqt as it can be buggy 0027 # if not run from the same folder as the binary is on. 0028 0029 # - Fix rpath from krita bin 0030 # - Find missing libraries from plugins and copy to Frameworks or plugins. 0031 # This uses oTool iterative to find all unique libraries, then it searches each 0032 # library fond in <kritadmg> folder, and if not found attempts to copy contents 0033 # to the appropriate folder, either Frameworks (if frameworks is in namefile, or 0034 # library has plugin isnot in path), or plugin if otherwise. 0035 0036 # - Builds DMG 0037 # Building DMG creates a new dmg with the contents of <kritadmg> 0038 # mounts the dmg and sets the style for dmg. 0039 # unmount 0040 # Compress resulting dmg into krita_nightly-<gitsha>.dmg 0041 # deletes temporary files. 0042 0043 if [[ -n "$ZSH_VERSION" ]]; then 0044 emulate -L ksh; 0045 fi 0046 0047 if [[ -z $BUILDROOT ]]; then 0048 echo "ERROR: BUILDROOT env not set!" 0049 echo "\t Must point to the root of the buildfiles as stated in 3rdparty Readme" 0050 echo "exiting..." 0051 exit 1 0052 fi 0053 0054 BUILDROOT="${BUILDROOT%/}" 0055 0056 # print status messages 0057 print_msg() { 0058 printf "\e[32m${1}\e[0m\n" "${@:2}" 0059 # printf "%s\n" "${1}" >> ${OUPUT_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 DMG_title="krita" #if changed krita.temp.dmg must be deleted manually 0088 SCRIPT_SOURCE_DIR="$(get_script_dir)" 0089 0090 # There is some duplication between build and deploy scripts 0091 # a config env file could would be a nice idea. 0092 KIS_SRC_DIR=${BUILDROOT}/krita 0093 KIS_INSTALL_DIR=${BUILDROOT}/i 0094 KIS_BUILD_DIR=${BUILDROOT}/kisbuild # only used for getting git sha number 0095 KRITA_DMG=${BUILDROOT}/kritadmg 0096 KRITA_DMG_TEMPLATE=${BUILDROOT}/kritadmg-template 0097 0098 export PATH=${KIS_INSTALL_DIR}/bin:$PATH 0099 0100 # flags for OSX environment 0101 # We only support from 10.13 up 0102 export MACOSX_DEPLOYMENT_TARGET=10.13 0103 export QMAKE_MACOSX_DEPLOYMENT_TARGET=10.13 0104 0105 0106 print_usage () { 0107 printf "USAGE: 0108 osxdeploy.sh [-s=<identity>] [-notarize-ac=<apple-account>] [-style=<style.txt>] [-bg=<background-image>] 0109 0110 -s \t\t\t Code sign identity for codesign 0111 0112 -notarize-ac \t Apple account name for notarization purposes 0113 \t\t\t script will attempt to get password from keychain, if fails provide one with 0114 \t\t\t the -notarize-pass option: To add a password run 0115 0116 \t\t\t security add-generic-password -a \"AC_USERNAME\" -w <secret_password> -s \"AC_PASSWORD\" 0117 0118 -notarize-pass \t If given, the Apple account password. Otherwise an attempt will be macdeployqt_exists 0119 \t\t\t to get the password from keychain using the account given in <notarize-ac> option. 0120 0121 -asc-provider \t some AppleIds might need this option pass the <shortname> 0122 0123 -style \t\t Style file defined from 'dmgstyle.sh' output 0124 0125 -bg \t\t Set a background image for dmg folder. 0126 0127 -name \t\t Set the DMG name output. 0128 0129 \t\t\t osxdeploy needs an input image to attach to the dmg background 0130 \t\t\t image recommended size is at least 950x500 0131 " 0132 } 0133 0134 # Attempt to detach previous mouted DMG 0135 if [[ -d "/Volumes/${DMG_title}" ]]; then 0136 echo "WARNING: Another Krita DMG is mounted!" 0137 echo "Attempting eject…" 0138 hdiutil detach "/Volumes/${DMG_title}" 0139 if [ $? -ne 0 ]; then 0140 exit 1 0141 fi 0142 echo "Success!" 0143 fi 0144 0145 # -- Parse input args 0146 for arg in "${@}"; do 0147 if [ "${arg}" = -bg=* -a -f "${arg#*=}" ]; then 0148 DMG_validBG=0 0149 bg_filename=${arg#*=} 0150 echo "attempting to check background is valid jpg or png..." 0151 BG_FORMAT=$(sips --getProperty format ${bg_filename} | awk '{printf $2}') 0152 0153 if [[ "png" = ${BG_FORMAT} || "jpeg" = ${BG_FORMAT} ]];then 0154 echo "valid image file" 0155 DMG_background=$(cd "$(dirname "${bg_filename}")"; pwd -P)/$(basename "${bg_filename}") 0156 DMG_validBG=1 0157 # check imageDPI 0158 BG_DPI=$(sips --getProperty dpiWidth ${DMG_background} | grep dpi | awk '{print $2}') 0159 if [[ $(echo "${BG_DPI} > 150" | bc -l) -eq 1 ]]; then 0160 printf "WARNING: image dpi has an effect on apparent size! 0161 Check dpi is adequate for screen display if image appears very small 0162 Current dpi is: %s\n" ${BG_DPI} 0163 fi 0164 fi 0165 fi 0166 # If string starts with -sign 0167 if [[ ${arg} = -s=* ]]; then 0168 CODE_SIGNATURE="${arg#*=}" 0169 fi 0170 0171 if [[ ${arg} = -name=* ]]; then 0172 DMG_NAME="${arg#*=}" 0173 fi 0174 0175 if [[ ${arg} = -notarize-ac=* ]]; then 0176 NOTARIZE_ACC="${arg#*=}" 0177 fi 0178 0179 if [[ ${arg} = -notarize-pass=* ]]; then 0180 NOTARIZE_PASS="${arg#*=}" 0181 fi 0182 0183 if [[ ${arg} = -style=* ]]; then 0184 style_filename="${arg#*=}" 0185 if [[ -f "${style_filename}" ]]; then 0186 DMG_STYLE="${style_filename}" 0187 fi 0188 fi 0189 0190 if [[ ${arg} = -asc-provider=* ]]; then 0191 APPLE_TEAMID="${arg#*=}" 0192 fi 0193 0194 if [[ ${arg} = "-h" || ${arg} = "--help" ]]; then 0195 print_usage 0196 exit 1 0197 fi 0198 done 0199 0200 # -- Checks and messages 0201 0202 ### PYTHONAttempt to find python_version 0203 local_PY_MAYOR_VERSION=$(python -c "import sys; print(sys.version_info[0])") 0204 local_PY_MINOR_VERSION=$(python -c "import sys; print(sys.version_info[1])") 0205 PY_VERSION="${local_PY_MAYOR_VERSION}.${local_PY_MINOR_VERSION}" 0206 0207 print_msg "Detected Python %s" "${PY_VERSION}" 0208 0209 ### Code Signature & NOTARIZATION 0210 NOTARIZE="false" 0211 if [[ -z "${CODE_SIGNATURE}" ]]; then 0212 echo "WARNING: No code signature provided, Code will not be signed" 0213 else 0214 print_msg "Code will be signed with %s" "${CODE_SIGNATURE}" 0215 ### NOTARIZATION 0216 # check if we can perform notarization using notarytool 0217 xcrun notarytool history --keychain-profile KritaNotarizeAccount 1> /dev/null 0218 if [[ ${?} -eq 0 ]]; then 0219 NOTARYTOOL="short" 0220 NOTARIZE="true" 0221 fi 0222 0223 if [[ ${NOTARIZE} = "false" && -n "${NOTARIZE_ACC}" ]]; then 0224 NOTARIZE="true" 0225 ASC_PROVIDER_OP="" 0226 0227 if [[ -z ${APPLE_TEAMID} ]]; then 0228 echo "No team id provided, extracting from signature" 0229 APPLE_TEAMID=${CODE_SIGNATURE[-11,-2]} 0230 fi 0231 0232 if [[ -n "${APPLE_TEAMID}" ]]; then 0233 ASC_PROVIDER_OP="--asc-provider ${APPLE_TEAMID}" 0234 fi 0235 0236 if [[ -z "${NOTARIZE_PASS}" ]]; then 0237 NOTARIZE_PASS="@keychain:AC_PASSWORD" 0238 KEYCHAIN_PASS="true" 0239 fi 0240 0241 # check if we can perform notarization 0242 0243 xcrun notarytool history --apple-id "${NOTARIZE_ACC}" --password "${NOTARIZE_PASS}" --team-id "${APPLE_TEAMID}" 1> /dev/null 0244 if [[ ${?} -ne 0 ]]; then 0245 echo "Unable to use notarytool: not setup/missing password, trying altool" 0246 ALTOOL="true" 0247 xcrun altool --notarization-history 0 --username "${NOTARIZE_ACC}" --password "${NOTARIZE_PASS}" ${ASC_PROVIDER_OP} 1> /dev/null 0248 0249 if [[ ${?} -ne 0 ]]; then 0250 NOTARIZE="false" 0251 echo "No password given for notarization or AC_PASSWORD missig in keychain" 0252 fi 0253 else 0254 NOTARYTOOL="long" 0255 fi 0256 fi 0257 fi 0258 0259 if [[ ${NOTARIZE} = "true" ]]; then 0260 print_msg "Notarization checks complete, This build will be notarized" 0261 else 0262 echo "WARNING: Account information missing, Notarization will not be performed" 0263 fi 0264 0265 0266 ### STYLE for DMG 0267 if [[ ! ${DMG_STYLE} ]]; then 0268 DMG_STYLE="${SCRIPT_SOURCE_DIR}/default.style" 0269 fi 0270 0271 print_msg "Using style from: %s" "${DMG_STYLE}" 0272 0273 ### Background for DMG 0274 if [[ ${DMG_validBG} -eq 0 ]]; then 0275 echo "No jpg or png valid file detected!!" 0276 echo "Using default style" 0277 DMG_background="${SCRIPT_SOURCE_DIR}/krita_dmgBG.jpg" 0278 fi 0279 0280 0281 0282 # Helper functions 0283 countArgs () { 0284 echo "${#}" 0285 } 0286 0287 stringContains () { 0288 echo "$(grep "${2}" <<< "${1}")" 0289 } 0290 0291 waiting_fixed() { 0292 local message="${1}" 0293 local waitTime=${2} 0294 0295 for i in $(seq ${waitTime}); do 0296 sleep 1 0297 printf -v dots '%*s' ${i} 0298 printf -v spaces '%*s' $((${waitTime} - $i)) 0299 printf "\r%s [%s%s]" "${message}" "${dots// /.}" "${spaces}" 0300 done 0301 printf "\n" 0302 } 0303 0304 add_lib_to_list() { 0305 local llist=${2} 0306 if [[ -z "$(grep ${1##*/} <<< ${llist})" ]]; then 0307 local llist="${llist} ${1##*/} " 0308 fi 0309 echo "${llist}" 0310 } 0311 0312 # Find all @rpath and Absolute to buildroot path libs 0313 # Add to libs_used 0314 # converts absolute buildroot path to @rpath 0315 find_needed_libs () { 0316 # echo "Analyzing libraries with oTool..." >&2 0317 local libs_used="" # input lib_lists founded 0318 0319 for libFile in ${@}; do 0320 if [[ -z "$(file ${libFile} | grep 'Mach-O')" ]]; then 0321 # echo "skipping ${libFile}" >&2 0322 continue 0323 fi 0324 0325 oToolResult=$(otool -L ${libFile} | awk '{print $1}') 0326 resultArray=(${oToolResult}) # convert to array 0327 0328 for lib in ${resultArray[@]:1}; do 0329 if [[ "${lib:0:1}" = "@" ]]; then 0330 local libs_used=$(add_lib_to_list "${lib}" "${libs_used}") 0331 fi 0332 if [[ "${lib:0:${#BUILDROOT}}" = "${BUILDROOT}" ]]; then 0333 printf "Fixing %s: %s\n" "${libFile#${KRITA_DMG}/}" "${lib##*/}" >&2 0334 if [[ "${lib##*/}" = "${libFile##*/}" ]]; then 0335 install_name_tool -id ${lib##*/} "${libFile}" 0336 else 0337 install_name_tool -change ${lib} "@rpath/${lib##*/i/lib/}" "${libFile}" 0338 local libs_used=$(add_lib_to_list "${lib}" "${libs_used}") 0339 fi 0340 fi 0341 done 0342 done 0343 echo "${libs_used}" # return updated list 0344 } 0345 0346 find_missing_libs (){ 0347 # echo "Searching for missing libs on deployment folders…" >&2 0348 local libs_missing="" 0349 for lib in ${@}; do 0350 if [[ -z "$(find ${KRITA_DMG}/krita.app/Contents/ -name ${lib})" ]]; then 0351 # echo "Adding ${lib} to missing libraries." >&2 0352 libs_missing="${libs_missing} ${lib}" 0353 fi 0354 done 0355 echo "${libs_missing}" 0356 } 0357 0358 copy_missing_libs () { 0359 for lib in ${@}; do 0360 result=$(find -L "${BUILDROOT}/i" -name "${lib}") 0361 0362 if [[ $(countArgs ${result}) -eq 1 ]]; then 0363 if [ "$(stringContains "${result}" "plugin")" ]; then 0364 cp -pv ${result} ${KRITA_DMG}/krita.app/Contents/PlugIns/ 0365 krita_findmissinglibs "${KRITA_DMG}/krita.app/Contents/PlugIns/${result##*/}" 0366 else 0367 cp -pv ${result} ${KRITA_DMG}/krita.app/Contents/Frameworks/ 0368 krita_findmissinglibs "${KRITA_DMG}/krita.app/Contents/Frameworks/${result##*/}" 0369 fi 0370 else 0371 echo "${lib} might be a missing framework" 0372 if [ "$(stringContains "${result}" "framework")" ]; then 0373 echo "copying framework ${BUILDROOT}/i/lib/${lib}.framework to dmg" 0374 # rsync only included ${lib} Resources Versions 0375 rsync -priul ${BUILDROOT}/i/lib/${lib}.framework/${lib} ${KRITA_DMG}/krita.app/Contents/Frameworks/${lib}.framework/ 0376 rsync -priul ${BUILDROOT}/i/lib/${lib}.framework/Resources ${KRITA_DMG}/krita.app/Contents/Frameworks/${lib}.framework/ 0377 rsync -priul ${BUILDROOT}/i/lib/${lib}.framework/Versions ${KRITA_DMG}/krita.app/Contents/Frameworks/${lib}.framework/ 0378 krita_findmissinglibs "$(find "${KRITA_DMG}/krita.app/Contents/Frameworks/${lib}.framework/" -type f -perm 755)" 0379 fi 0380 fi 0381 done 0382 } 0383 0384 krita_findmissinglibs() { 0385 neededLibs=$(find_needed_libs "${@}") 0386 missingLibs=$(find_missing_libs ${neededLibs}) 0387 0388 if [[ $(countArgs ${missingLibs}) -gt 0 ]]; then 0389 printf "Found missing libs: %s\n" "${missingLibs}" 0390 copy_missing_libs ${missingLibs} 0391 fi 0392 } 0393 0394 strip_python_dmginstall() { 0395 # reduce size of framework python 0396 # Removes tests, installers, pyenv, distutils 0397 echo "Removing unnecessary files from Python.Framework to be packaged..." 0398 PythonFrameworkBase="${KRITA_DMG}/krita.app/Contents/Frameworks/Python.framework" 0399 0400 cd "${PythonFrameworkBase}" 0401 find . -name "test*" -type d | xargs rm -rf 0402 find "${PythonFrameworkBase}/Versions/${PY_VERSION}/bin" -not -name "python*" \( -type f -or -type l \) | xargs rm -f 0403 cd "${PythonFrameworkBase}/Versions/${PY_VERSION}/lib/python${PY_VERSION}" 0404 rm -rf distutils tkinter ensurepip venv lib2to3 idlelib turtledemo 0405 # remove tkinter module 0406 rm "./lib-dynload/_tkinter.cpython-${local_PY_MAYOR_VERSION}${local_PY_MINOR_VERSION}-darwin.so" 0407 0408 cd "${PythonFrameworkBase}/Versions/${PY_VERSION}/lib/python${PY_VERSION}/site-packages" 0409 rm -rf pip* PyQt_builder* setuptools* sip* easy-install.pth 0410 0411 cd "${PythonFrameworkBase}/Versions/${PY_VERSION}/Resources" 0412 rm -rf Python.app 0413 } 0414 0415 # Remove any missing rpath poiting to BUILDROOT 0416 libs_clean_rpath () { 0417 for libFile in ${@}; do 0418 rpath=$(otool -l "${libFile}" | grep "path ${BUILDROOT}" | awk '{$1=$1;print $2}') 0419 if [[ -n "${rpath}" ]]; then 0420 echo "removed rpath _${rpath}_ from ${libFile}" 0421 install_name_tool -delete_rpath "${rpath}" "${libFile}" 0422 fi 0423 done 0424 } 0425 0426 # Multhread version 0427 # of libs_clean_rpath, but makes assumptions 0428 delete_install_rpath() { 0429 xargs -P4 -I FILE install_name_tool -delete_rpath "${BUILDROOT}/i/lib" FILE 2> "${BUILDROOT}/deploy_error.log" 0430 } 0431 0432 fix_python_framework() { 0433 # Fix python.framework rpath and slims down installation 0434 PythonFrameworkBase="${KRITA_DMG}/krita.app/Contents/Frameworks/Python.framework" 0435 0436 # Fix permissions 0437 find "${PythonFrameworkBase}" -name "*.so" | xargs -P4 -I FILE chmod a+x FILE 2> "${BUILDROOT}/deploy_error.log" 0438 cd "${PythonFrameworkBase}/Versions/${PY_VERSION}/lib/python${PY_VERSION}" 0439 chmod a+x pydoc.py 0440 0441 # Fix main library 0442 pythonLib="${PythonFrameworkBase}/Python" 0443 install_name_tool -id "${pythonLib##*/}" "${pythonLib}" 0444 install_name_tool -add_rpath @loader_path/../../../ "${pythonLib}" 2> /dev/null 0445 install_name_tool -change @loader_path/../../../../libintl.9.dylib @loader_path/../../../libintl.9.dylib "${pythonLib}" 0446 0447 # Fix all executables 0448 install_name_tool -add_rpath @executable_path/../../../../../../../ "${PythonFrameworkBase}/Versions/Current/Resources/Python.app/Contents/MacOS/Python" 0449 install_name_tool -change "${KIS_INSTALL_DIR}/lib/Python.framework/Versions/${PY_VERSION}/Python" @executable_path/../../../../../../Python "${PythonFrameworkBase}/Versions/Current/Resources/Python.app/Contents/MacOS/Python" 0450 install_name_tool -add_rpath @executable_path/../../../../ "${PythonFrameworkBase}/Versions/Current/bin/python${PY_VERSION}" 0451 install_name_tool -add_rpath @executable_path/../../../../ "${PythonFrameworkBase}/Versions/Current/bin/python${PY_VERSION}m" 0452 0453 # Fix rpaths from Python.Framework 0454 find "${PythonFrameworkBase}" -type f -perm 755 | delete_install_rpath 0455 find "${PythonFrameworkBase}/Versions/Current/lib/python${PY_VERSION}/site-packages/PyQt5" -type f -name "*.so" | delete_install_rpath 0456 } 0457 0458 # Checks for macdeployqt 0459 # If not present attempts to install 0460 # If it fails shows an informatve message 0461 # (For now, macdeployqt is fundamental to deploy) 0462 macdeployqt_exists() { 0463 printf "Checking for macdeployqt... " 0464 0465 if [[ ! -e "${KIS_INSTALL_DIR}/bin/macdeployqt" ]]; then 0466 printf "Not Found!\n" 0467 printf "Attempting to install macdeployqt\n" 0468 0469 cd "${BUILDROOT}/depbuild/ext_qt/ext_qt-prefix/src/ext_qt/qttools/src" 0470 make sub-macdeployqt-all 0471 make sub-macdeployqt-install_subtargets 0472 make install 0473 0474 if [[ ! -e "${KIS_INSTALL_DIR}/bin/macdeployqt" ]]; then 0475 printf " 0476 ERROR: Failed to install macdeployqt! 0477 0478 Compile and install from qt source directory 0479 Source code to build could be located in qttools/src in qt source dir: 0480 0481 ${BUILDROOT}/depbuild/ext_qt/ext_qt-prefix/src/ext_qt/qttools/src 0482 0483 From the source dir, build and install: 0484 0485 make sub-macdeployqt-all 0486 make sub-macdeployqt-install_subtargets 0487 make install 0488 " 0489 printf "\nexiting...\n" 0490 exit 1 0491 else 0492 echo "Done!" 0493 fi 0494 else 0495 echo "Found!" 0496 fi 0497 } 0498 0499 krita_deploy () { 0500 # check for macdeployqt 0501 macdeployqt_exists 0502 0503 cd ${BUILDROOT} 0504 # Update files in krita.app 0505 echo "Deleting previous kritadmg run..." 0506 rm -rf ./krita.dmg ${KRITA_DMG} 0507 # Copy new builtFiles 0508 echo "Preparing ${KRITA_DMG} for deployment..." 0509 0510 echo "Copying krita.app..." 0511 mkdir "${KRITA_DMG}" 0512 0513 rsync -prul ${KIS_INSTALL_DIR}/bin/krita.app ${KRITA_DMG} 0514 0515 mkdir -p ${KRITA_DMG}/krita.app/Contents/PlugIns 0516 mkdir -p ${KRITA_DMG}/krita.app/Contents/Frameworks 0517 0518 echo "Copying share..." 0519 # Deletes old copies of translation and qml to be recreated 0520 cd ${KIS_INSTALL_DIR}/share/ 0521 rsync -prul --delete ./ \ 0522 --exclude krita_SRCS.icns \ 0523 --exclude aclocal \ 0524 --exclude doc \ 0525 --exclude ECM \ 0526 --exclude eigen3 \ 0527 --exclude emacs \ 0528 --exclude gettext \ 0529 --exclude gettext-0.19.8 \ 0530 --exclude info \ 0531 --exclude kf5 \ 0532 --exclude kservices5 \ 0533 --exclude man \ 0534 --exclude ocio \ 0535 --exclude pkgconfig \ 0536 --exclude mime \ 0537 --exclude translations \ 0538 --exclude qml \ 0539 ${KRITA_DMG}/krita.app/Contents/Resources 0540 0541 cd ${BUILDROOT} 0542 0543 echo "Copying translations..." 0544 rsync -prul ${KIS_INSTALL_DIR}/translations/ \ 0545 ${KRITA_DMG}/krita.app/Contents/Resources/translations 0546 0547 echo "Copying QuickLook plugin..." 0548 mkdir -p ${KRITA_DMG}/krita.app/Contents/Library/QuickLook 0549 rsync -prul ${KIS_INSTALL_DIR}/plugins/kritaquicklook.qlgenerator ${KRITA_DMG}/krita.app/Contents/Library/QuickLook 0550 echo "Copying Spotlight plugin..." 0551 mkdir -p ${KRITA_DMG}/krita.app/Contents/Library/Spotlight 0552 rsync -prul ${KIS_INSTALL_DIR}/plugins/kritaspotlight.mdimporter ${KRITA_DMG}/krita.app/Contents/Library/Spotlight 0553 # TODO fix and reenable - https://bugs.kde.org/show_bug.cgi?id=430553 0554 # echo "Copying QuickLook Thumbnailing extension..." 0555 # rsync -prul ${KIS_INSTALL_DIR}/plugins/kritaquicklookng.appex ${KRITA_DMG}/krita.app/Contents/PlugIns 0556 0557 cd ${KRITA_DMG}/krita.app/Contents 0558 ln -shF Resources share 0559 0560 echo "Copying qml..." 0561 rsync -prul ${KIS_INSTALL_DIR}/qml Resources/qml 0562 0563 echo "Copying plugins..." 0564 # exclude kritaquicklook.qlgenerator/ 0565 cd ${KIS_INSTALL_DIR}/plugins/ 0566 rsync -prul --delete --delete-excluded ./ \ 0567 --exclude kritaquicklook.qlgenerator \ 0568 --exclude kritaspotlight.mdimporter \ 0569 ${KRITA_DMG}/krita.app/Contents/PlugIns 0570 0571 cd ${BUILDROOT} 0572 rsync -prul ${KIS_INSTALL_DIR}/lib/kritaplugins/ ${KRITA_DMG}/krita.app/Contents/PlugIns 0573 0574 # rsync -prul {KIS_INSTALL_DIR}/lib/libkrita* Frameworks/ 0575 0576 # To avoid errors macdeployqt must be run from bin location 0577 # ext_qt will not build macdeployqt by default so it must be build manually 0578 # cd ${BUILDROOT}/depbuild/ext_qt/ext_qt-prefix/src/ext_qt/qttools/src 0579 # make sub-macdeployqt-all 0580 # make sub-macdeployqt-install_subtargets 0581 # make install 0582 echo "Running macdeployqt..." 0583 cd ${KIS_INSTALL_DIR}/bin 0584 ./macdeployqt ${KRITA_DMG}/krita.app \ 0585 -verbose=0 \ 0586 -executable=${KRITA_DMG}/krita.app/Contents/MacOS/krita \ 0587 -libpath=${KIS_INSTALL_DIR}/lib \ 0588 -qmldir=${KIS_INSTALL_DIR}/qml \ 0589 # -extra-plugins=${KIS_INSTALL_DIR}/lib/kritaplugins \ 0590 # -extra-plugins=${KIS_INSTALL_DIR}/lib/plugins \ 0591 # -extra-plugins=${KIS_INSTALL_DIR}/plugins 0592 0593 cd ${BUILDROOT} 0594 echo "macdeployqt done!" 0595 0596 echo "Copying python..." 0597 # Copy this framework last! 0598 # It is best that macdeployqt does not modify Python.framework 0599 # folders with period in name are treated as Frameworks for codesign 0600 rsync -prul ${KIS_INSTALL_DIR}/lib/Python.framework ${KRITA_DMG}/krita.app/Contents/Frameworks/ 0601 rsync -prul ${KIS_INSTALL_DIR}/lib/krita-python-libs ${KRITA_DMG}/krita.app/Contents/Frameworks/ 0602 # change perms on Python to allow header change 0603 chmod +w ${KRITA_DMG}/krita.app/Contents/Frameworks/Python.framework/Python 0604 0605 fix_python_framework 0606 strip_python_dmginstall 0607 0608 # fix python pyc 0609 # precompile all pyc so the dont alter signature 0610 echo "Precompiling all python files..." 0611 cd ${KRITA_DMG}/krita.app 0612 ${KIS_INSTALL_DIR}/bin/python -m compileall . &> /dev/null 0613 0614 install_name_tool -delete_rpath @loader_path/../../../../lib ${KRITA_DMG}/krita.app/Contents/MacOS/krita 0615 rm -rf ${KRITA_DMG}/krita.app/Contents/PlugIns/kf5/org.kde.kwindowsystem.platforms 0616 0617 # Fix permissions 0618 find "${KRITA_DMG}/krita.app/Contents" -type f -name "*.dylib" -or -name "*.so" -or -path "*/Contents/MacOS/*" | xargs -P4 -I FILE chmod a+x FILE 0619 find "${KRITA_DMG}/krita.app/Contents/Resources/applications" -name "*.desktop" | xargs -P4 -I FILE chmod a-x FILE 0620 0621 # repair krita for plugins 0622 printf "Searching for missing libraries\n" 0623 krita_findmissinglibs $(find ${KRITA_DMG}/krita.app/Contents -type f -perm 755 -or -name "*.dylib" -or -name "*.so") 0624 0625 # Fix rpath for plugins 0626 # Uncomment if the Finder plugins (kritaquicklook, kritaspotlight) lack the rpath below 0627 # printf "Repairing rpath for Finder plugins\n" 0628 # find "${KRITA_DMG}/krita.app/Contents/Library" -type f -path "*/Contents/MacOS/*" -perm 755 | xargs -I FILE install_name_tool -add_rpath @loader_path/../../../../../Frameworks FILE 0629 0630 printf "removing absolute or broken linksys, if any\n" 0631 find "${KRITA_DMG}/krita.app/Contents" -type l \( -lname "/*" -or -not -exec test -e {} \; \) -print | xargs rm 0632 0633 printf "clean any left over rpath\n" 0634 libs_clean_rpath $(find "${KRITA_DMG}/krita.app/Contents" -type f -perm 755 -or -name "*.dylib" -or -name "*.so") 0635 # libs_clean_rpath $(find "${KRITA_DMG}/krita.app/Contents/" -type f -name "lib*") 0636 0637 echo "Done!" 0638 0639 } 0640 0641 0642 # helper to define function only once 0643 batch_codesign() { 0644 xargs -P4 -I FILE codesign --options runtime --timestamp -f -s "${CODE_SIGNATURE}" --entitlements "${KIS_SRC_DIR}/packaging/macos/entitlements.plist" FILE 0645 } 0646 # Code sign must be done as recommended by apple "sign code inside out in individual stages" 0647 signBundle() { 0648 cd ${KRITA_DMG} 0649 0650 # sign Frameworks and libs 0651 cd ${KRITA_DMG}/krita.app/Contents/Frameworks 0652 # remove debug version as both versions can't be signed. 0653 rm ${KRITA_DMG}/krita.app/Contents/Frameworks/QtScript.framework/Versions/Current/QtScript_debug 0654 # Do not sign binaries inside frameworks except for Python's 0655 find . -type d -path "*.framework" -prune -false -o -perm +111 -not -type d | batch_codesign 0656 find Python.framework -type f -name "*.o" -or -name "*.so" -or -perm +111 -not -type d -not -type l | batch_codesign 0657 find . -type d -name "*.framework" | xargs printf "%s/Versions/Current\n" | batch_codesign 0658 0659 # Sign all other files in Framework (needed) 0660 # there are many files in python do we need to sign them all? 0661 find krita-python-libs -type f | batch_codesign 0662 # find python -type f | batch_codesign 0663 0664 # Sign only libraries and plugins 0665 cd ${KRITA_DMG}/krita.app/Contents/PlugIns 0666 find . -type f | batch_codesign 0667 0668 cd ${KRITA_DMG}/krita.app/Contents/Library/QuickLook 0669 printf "kritaquicklook.qlgenerator" | batch_codesign 0670 0671 cd ${KRITA_DMG}/krita.app/Contents/Library/Spotlight 0672 printf "kritaspotlight.mdimporter" | batch_codesign 0673 0674 # It is necessary to sign every binary Resource file 0675 cd ${KRITA_DMG}/krita.app/Contents/Resources 0676 find . -perm +111 -type f | batch_codesign 0677 0678 #Finally sign krita and krita.app 0679 printf "${KRITA_DMG}/krita.app/Contents/MacOS/krita" | batch_codesign 0680 printf "${KRITA_DMG}/krita.app" | batch_codesign 0681 } 0682 0683 sign_hasError() { 0684 local CODESIGN_STATUS=0 0685 for f in $(find "${KRITA_DMG}" -type f); do 0686 if [[ -z $(file ${f} | grep "Mach-O") ]]; then 0687 continue 0688 fi 0689 0690 CODESIGN_RESULT=$(codesign -vvv --strict ${f} 2>&1 | grep "not signed") 0691 0692 if [[ -n "${CODESIGN_RESULT}" ]]; then 0693 CODESIGN_STATUS=1 0694 printf "${f} not signed\n" >&2 0695 fi 0696 done 0697 echo ${CODESIGN_STATUS} 0698 } 0699 0700 # Notarize build on macOS servers 0701 # based on https://github.com/Beep6581/RawTherapee/blob/6fa533c40b34dec527f1176d47cc6c683422a73f/tools/osx/macosx_bundle.sh#L225-L250 0702 notarize_build() { 0703 local NOT_SRC_DIR=${1} 0704 local NOT_SRC_FILE=${2} 0705 0706 if [[ ${NOTARIZE} = "true" ]]; then 0707 printf "performing notarization of %s\n" "${2}" 0708 cd "${NOT_SRC_DIR}" 0709 0710 ditto -c -k --sequesterRsrc --keepParent "${NOT_SRC_FILE}" "${BUILDROOT}/tmp_notarize/${NOT_SRC_FILE}.zip" 0711 0712 if [[ ${NOTARYTOOL} = "short" ]]; then 0713 xcrun notarytool submit "${BUILDROOT}/tmp_notarize/${NOT_SRC_FILE}.zip" --wait --keychain-profile KritaNotarizeAccount 0714 0715 elif [[ ${NOTARYTOOL} = "long" ]]; then 0716 xcrun notarytool submit "${BUILDROOT}/tmp_notarize/${NOT_SRC_FILE}.zip" --wait --apple-id "${NOTARIZE_ACC}" --password "${NOTARIZE_PASS}" --team-id "${APPLE_TEAMID}" 0717 0718 else 0719 # echo "xcrun altool --notarize-app --primary-bundle-id \"org.krita\" --username \"${NOTARIZE_ACC}\" --password \"${NOTARIZE_PASS}\" --file \"${BUILDROOT}/tmp_notarize/${NOT_SRC_FILE}.zip\"" 0720 local altoolResponse="$(xcrun altool --notarize-app --primary-bundle-id "org.krita" --username "${NOTARIZE_ACC}" --password "${NOTARIZE_PASS}" ${ASC_PROVIDER_OP} --file "${BUILDROOT}/tmp_notarize/${NOT_SRC_FILE}.zip" 2>&1)" 0721 0722 if [[ -n "$(grep 'Error' <<< ${altoolResponse})" ]]; then 0723 printf "ERROR: xcrun altool exited with the following error! \n\n%s\n\n" "${altoolResponse}" 0724 printf "This could mean there is an error in AppleID authentication!\n" 0725 printf "aborting notarization\n" 0726 NOTARIZE="false" 0727 return 0728 else 0729 printf "Response:\n\n%s\n\n" "${altoolResponse}" 0730 fi 0731 0732 local uuid="$(grep 'RequestUUID' <<< ${altoolResponse} | awk '{ print $NF }')" 0733 echo "RequestUUID = ${uuid}" # Display identifier string 0734 0735 waiting_fixed "Waiting to retrieve notarize status" 120 0736 0737 while true ; do 0738 fullstatus=$(xcrun altool --notarization-info "${uuid}" --username "${NOTARIZE_ACC}" --password "${NOTARIZE_PASS}" ${ASC_PROVIDER_OP} 2>&1) # get the status 0739 notarize_status=`echo "${fullstatus}" | grep 'Status\:' | awk '{ print $2 }'` 0740 echo "${fullstatus}" 0741 if [[ "${notarize_status}" = "success" ]]; then 0742 xcrun stapler staple "${NOT_SRC_FILE}" #staple the ticket 0743 xcrun stapler validate -v "${NOT_SRC_FILE}" 0744 print_msg "Notarization success!" 0745 break 0746 elif [[ "${notarize_status}" = "in" ]]; then 0747 waiting_fixed "Notarization still in progress, wait before checking again" 60 0748 else 0749 echo "Notarization failed! full status below" 0750 echo "${fullstatus}" 0751 exit 1 0752 fi 0753 done 0754 fi 0755 fi 0756 } 0757 0758 createDMG () { 0759 printf "Creating of dmg with contents of %s...\n" "${KRITA_DMG}" 0760 cd ${BUILDROOT} 0761 DMG_size=1500 0762 0763 if [[ -z "${DMG_NAME}" ]]; then 0764 # Add git version number 0765 GIT_SHA=$(grep "#define KRITA_GIT_SHA1_STRING" ${KIS_BUILD_DIR}/libs/version/kritagitversion.h | awk '{gsub(/"/, "", $3); printf $3}') 0766 DMG_NAME="krita-nightly_${GIT_SHA}.dmg" 0767 else 0768 DMG_NAME="${DMG_NAME}.dmg" 0769 fi 0770 0771 ## Build dmg from folder 0772 0773 # create dmg on local system 0774 # usage of -fsargs minimize gaps at front of filesystem (reduce size) 0775 hdiutil create -srcfolder "${KRITA_DMG}" -volname "${DMG_title}" -fs APFS \ 0776 -format UDIF -verbose -size ${DMG_size}m krita.temp.dmg 0777 0778 # Next line is only useful if we have a dmg as a template! 0779 # previous hdiutil must be uncommented 0780 # cp krita-template.dmg krita.dmg 0781 device=$(hdiutil attach -readwrite -noverify -noautoopen "krita.temp.dmg" | egrep '^/dev/' | sed 1q | awk '{print $1}') 0782 0783 # rsync -priul --delete ${KRITA_DMG}/krita.app "/Volumes/${DMG_title}" 0784 0785 # Set style for dmg 0786 if [[ ! -d "/Volumes/${DMG_title}/.background" ]]; then 0787 mkdir "/Volumes/${DMG_title}/.background" 0788 fi 0789 cp -v ${DMG_background} "/Volumes/${DMG_title}/.background/" 0790 0791 mkdir "/Volumes/${DMG_title}/Terms of Use" 0792 cp -v "${KIS_SRC_DIR}/packaging/macos/Terms_of_use.rtf" "/Volumes/${DMG_title}/Terms of Use/" 0793 ln -s "/Applications" "/Volumes/${DMG_title}/Applications" 0794 0795 ## Apple script to set style 0796 style="$(<"${DMG_STYLE}")" 0797 printf "${style}" "${DMG_title}" "${DMG_background##*/}" | osascript 0798 0799 #Set Icon for DMG 0800 cp -v "${SCRIPT_SOURCE_DIR}/KritaIcon.icns" "/Volumes/${DMG_title}/.VolumeIcon.icns" 0801 SetFile -a C "/Volumes/${DMG_title}" 0802 0803 chmod -Rf go-w "/Volumes/${DMG_title}" 0804 0805 # ensure all writing operations to dmg are over 0806 sync 0807 0808 hdiutil detach $device 0809 hdiutil convert "krita.temp.dmg" -format UDZO -imagekey -zlib-level=9 -o krita-out.dmg 0810 0811 0812 mv krita-out.dmg ${DMG_NAME} 0813 echo "moved krita-out.dmg to ${DMG_NAME}" 0814 rm krita.temp.dmg 0815 0816 if [[ -n "${CODE_SIGNATURE}" ]]; then 0817 printf "${DMG_NAME}" | batch_codesign 0818 fi 0819 0820 notarize_build "${BUILDROOT}" "${DMG_NAME}" 0821 0822 echo "dmg done!" 0823 } 0824 0825 ####################### 0826 # Program starts!! 0827 ######################## 0828 # Run deploy command, installation is assumed to exist in BUILDROOT/i 0829 krita_deploy 0830 0831 # Code sign krita.app if signature given 0832 if [[ -n "${CODE_SIGNATURE}" ]]; then 0833 signBundle 0834 fi 0835 0836 # Manually check every single Mach-O file for signature status 0837 if [[ "${NOTARIZE}" = "true" ]]; then 0838 print_msg "Checking if all files are signed before sending for notarization..." 0839 if [[ $(sign_hasError) -eq 1 ]]; then 0840 print_error "CodeSign errors cannot send to notarize!" 0841 echo "krita.app not sent to notarization, stopping...." 0842 exit 1 0843 fi 0844 print_msg "Done! all files appear to be correct." 0845 0846 # notarize apple 0847 notarize_build "${KRITA_DMG}" krita.app 0848 fi 0849 0850 # Create DMG from files inside ${KRITA_DMG} folder 0851 createDMG 0852 0853 if [[ "${NOTARIZE}" = "false" ]]; then 0854 macosVersion="$(sw_vers | grep ProductVersion | awk ' 0855 BEGIN { FS = "[ .\t]" } 0856 { print $3} 0857 ')" 0858 if (( ${macosVersion} == 15 )); then 0859 print_error "Build not notarized! Needed for macOS versions above 10.14" 0860 fi 0861 fi