1#!/usr/bin/env bash 2# MSYS2 build and test script for MyPaint. 3# All rights waived: https://creativecommons.org/publicdomain/zero/1.0/ 4# 5#: Usage: 6#: $ msys2_build.sh [OPTIONS] 7#: 8#: OPTIONS: 9#: installdeps Build+install dependencies. 10#: build Build MyPaint itself from this source tree. 11#: clean Clean the build tree. 12#: tests Runs tests on the built source. 13#: doctest Check to make sure all python docs work. 14#: bundle Creates installer bundles in ./out/bundles 15#: 16#: This script is designed to be called by AppVeyor or Tea-CI. However 17#: it's clean enough to run from an interactive shell. It expects to be 18#: called with MSYSTEM="MINGW{64,32}", i.e. from an MSYS2 "native" shell. 19#: 20#: Build artifacts are written to ./out/pkgs and ./out/bundles by default. 21 22set -e 23 24# ANSI control codes 25RED='\033[0;31m' 26GREEN='\033[0;32m' 27CYAN='\033[0;36m' 28NC='\033[0m' # No Color 29 30# Script name and location. 31SCRIPT=`basename "$0"` 32SCRIPTDIR=`dirname "$0"` 33cd "$SCRIPTDIR/.." 34 35# Main repository location, as an absolute path. 36TOPDIR=`pwd` 37cd "$TOPDIR" 38 39# Ensure we're being run from one of MSYS2's "native shells". 40case "$MSYSTEM" in 41 "MINGW64") 42 PKG_PREFIX="mingw-w64-x86_64" 43 MINGW_INSTALLS="mingw64" 44 BUNDLE_ARCH="w64" 45 ;; 46 "MINGW32") 47 PKG_PREFIX="mingw-w64-i686" 48 MINGW_INSTALLS="mingw32" 49 BUNDLE_ARCH="w32" 50 ;; 51 *) 52 echo >&2 "$SCRIPT must only be called from a MINGW64/32 login shell." 53 exit 1 54 ;; 55esac 56export MINGW_INSTALLS 57 58# This script pulls down and maintains a clone of the pkgbuild tree for 59# MSYS2's MINGW32 and MINGW64 software. 60SRC_ROOT="${SRC_ROOT:-/tmp/src}" 61SRC_PROJECT="mingw" 62SRC_DIR="${SRC_ROOT}/${SRC_PROJECT}" 63SRC_CLONEURI="https://github.com/Alexpux/MINGW-packages.git" 64 65# Output location for build artifacts. 66OUTPUT_ROOT="${OUTPUT_ROOT:-$TOPDIR/out}" 67 68install_dependencies() { 69 70 loginfo "Removing potential package conflicts..." 71 pacman --remove --noconfirm ${PKG_PREFIX}-mypaint || true 72 pacman --remove --noconfirm ${PKG_PREFIX}-mypaint || true 73 pacman --remove --noconfirm ${PKG_PREFIX}-libmypaint || true 74 pacman --remove --noconfirm ${PKG_PREFIX}-mypaint-brushes2 || true 75 76 loginfo "Installing pre-built dependencies for MyPaint" 77 pacman -S --noconfirm --needed --noprogressbar \ 78 ${PKG_PREFIX}-toolchain \ 79 ${PKG_PREFIX}-pkg-config \ 80 ${PKG_PREFIX}-glib2 \ 81 ${PKG_PREFIX}-gtk3 \ 82 ${PKG_PREFIX}-json-c \ 83 ${PKG_PREFIX}-lcms2 \ 84 ${PKG_PREFIX}-python3-cairo \ 85 ${PKG_PREFIX}-pygobject-devel \ 86 ${PKG_PREFIX}-python3-gobject \ 87 ${PKG_PREFIX}-python3-numpy \ 88 ${PKG_PREFIX}-hicolor-icon-theme \ 89 ${PKG_PREFIX}-librsvg \ 90 ${PKG_PREFIX}-gobject-introspection \ 91 ${PKG_PREFIX}-python3-nose \ 92 ${PKG_PREFIX}-python3-setuptools \ 93 ${PKG_PREFIX}-swig \ 94 ${PKG_PREFIX}-gsettings-desktop-schemas \ 95 base-devel \ 96 git 97 98 loginfo "Installing pre-built dependencies for Styrene + its install" 99 pacman -S --noconfirm --needed --noprogressbar \ 100 ${PKG_PREFIX}-nsis \ 101 ${PKG_PREFIX}-gcc \ 102 ${PKG_PREFIX}-binutils \ 103 ${PKG_PREFIX}-python3 \ 104 ${PKG_PREFIX}-python3-pip \ 105 zip \ 106 p7zip 107 108 logok "Dependencies installed." 109 110 gdk-pixbuf-query-loaders --update-cache 111 logok "Pixbuf query loaders cache updated" 112} 113 114 115loginfo() { 116 echo -ne "${CYAN}" 117 echo -n "$@" 118 echo -e "${NC}" 119} 120 121 122logok() { 123 echo -ne "${GREEN}" 124 echo -n "$@" 125 echo -e "${NC}" 126} 127 128 129logerr() { 130 echo -ne "${RED}ERROR: " 131 echo -n "$@" 132 echo -e "${NC}" 133} 134 135 136check_output_dir() { 137 type="$1" 138 if test -d "$OUTPUT_ROOT/$type"; then 139 return 140 fi 141 mkdir -vp "$OUTPUT_ROOT/$type" 142} 143 144 145update_mingw_src() { 146 # Initialize or update the managed MINGW-packages sources dir. 147 if test -d "$SRC_DIR"; then 148 loginfo "Updating $SRC_DIR..." 149 pushd "$SRC_DIR" 150 git pull 151 else 152 loginfo "Creating $SRC_ROOT" 153 mkdir -vp "$SRC_ROOT" 154 pushd "$SRC_ROOT" 155 loginfo "Shallow-cloning $SRC_CLONEURI into $SRC_DIR..." 156 git clone --depth 1 "$SRC_CLONEURI" "$SRC_PROJECT" 157 fi 158 popd 159 logok "Updated $SRC_DIR" 160} 161 162 163seed_mingw_src_mypaint_repo() { 164 # Seed the MyPaint source repository that makepkg-mingw wants 165 # from this one if it doesn't yet exist. 166 # The mypaint repo is quite big, so let's save some bandwidth! 167 repo="$SRC_DIR/mingw-w64-mypaint/mypaint" 168 test -d "$TOPDIR/.git" || return 169 test -d "$repo" && return 170 loginfo "Seeding $repo..." 171 git clone --local --no-hardlinks --bare "$TOPDIR" "$repo" 172 pushd "$repo" 173 git remote remove origin 174 git remote add origin https://github.com/mypaint/mypaint.git 175 git fetch --tags origin 176 popd 177 logok "Seeded $repo" 178} 179 180 181build_pkg() { 182 # Build and optionally install a .pkg.tar.zst from the 183 # managed tree of PKGBUILDs. 184 # 185 # Usage: build_pkg PKGNAMESTEM {true|false} 186 187 if ! test -d "$SRC_DIR"; then 188 logerr "Managed src dir $SRC_DIR does not exist (update_mingw_src 1st)" 189 exit 2 190 fi 191 192 pkgstem="$1" 193 install="$2" 194 src="${SRC_DIR}/mingw-w64-$pkgstem" 195 pushd "$src" 196 rm -vf *.pkg.tar.zst 197 198 # This only builds for the arch in MINGW_INSTALLS, i.e. the current 199 # value of MSYSTEM. 200 loginfo "Building in $src for $MINGW_INSTALLS ..." 201 MSYSTEM=MSYS2 bash --login -c 'cd "$1" && makepkg-mingw -f' - "$src" 202 logok "Build finished." 203 204 if $install; then 205 loginfo "Installing built packages..." 206 pacman -U --noconfirm *.pkg.tar.zst 207 logok "Install finished." 208 fi 209 popd 210 211 loginfo "Capturing build artifacts..." 212 check_output_dir "pkgs" 213 mv -v "$src"/*.pkg.tar.zst "$OUTPUT_ROOT/pkgs" 214 logok "Packages moved." 215} 216 217 218bundle_mypaint() { 219 # Convert local and repository *.pkg.tar.zst into nice bundles 220 # for users to install. 221 # Needs the libmypaint and mypaint .pkg.tar.zst artifacts. 222 styrene_path=`which styrene||true` 223 if [ "x$styrene_path" = "x" ]; then 224 mkdir -vp "$SRC_ROOT" 225 pushd "$SRC_ROOT" 226 if [ -d styrene ]; then 227 loginfo "Updating managed Styrene source" 228 pushd styrene 229 git pull 230 else 231 loginfo "Cloning managed Styrene source" 232 git clone https://github.com/mypaint/mypaint-styrene.git styrene 233 pushd styrene 234 fi 235 loginfo "Installing styrene with pip3..." 236 pip3 install . 237 loginfo "Installed styrene." 238 popd 239 popd 240 fi 241 242 check_output_dir "bundles" 243 loginfo "Creating installer bundles..." 244 245 tmpdir="/tmp/styrene.$$" 246 mkdir -p "$tmpdir" 247 styrene --colour=yes \ 248 --no-zip \ 249 --7z \ 250 --pkg-dir="$OUTPUT_ROOT/pkgs" \ 251 --output-dir="$tmpdir" \ 252 "$TOPDIR/windows/styrene/mypaint.cfg" 253 254 output_version=$(echo $BUNDLE_ARCH-$APPVEYOR_BUILD_VERSION | sed -e 's/[^a-zA-Z0-9._-]/-/g') 255 256 mv -v "$tmpdir"/*-standalone.7z \ 257 "$OUTPUT_ROOT/bundles/mypaint-$output_version-standalone.7z" 258 mv -v "$tmpdir"/*-installer.exe \ 259 "$OUTPUT_ROOT/bundles/mypaint-$output_version-installer.exe" 260 261 ls -l "$OUTPUT_ROOT/bundles"/*.* 262 263 rm -fr "$tmpdir" 264 265 logok "Bundle creation finished." 266} 267 268# Test Build, Clean, and Install tools to make sure all of setup.py is 269# working as intended. 270 271build_for_testing() { 272 loginfo "Building MyPaint from source" 273 python3 setup.py build 274 logok "Build finished." 275} 276 277clean_local_repo() { 278 loginfo "Cleaning local build" 279 python3 setup.py clean --all 280 rm -vf lib/*_wrap.c* 281 logok "Clean finished." 282} 283 284install_test(){ 285 # TODO: Look into this to find out why it is failing. 286 loginfo "Testing setup.py managed installation commands" 287 python3 setup.py managed_install 288 python3 setup.py managed_uninstall 289 logok "Install-test finished finished." 290} 291 292# Can't test everything from TeaCI due to wine crashing. 293# However, it's always appropriate to run the doctests. 294# With Appveyor, the tests scripts should run just fine. 295 296run_doctest() { 297 loginfo "Running unit tests." 298 python3 setup.py nosetests --tests lib 299 logok "Unit tests done." 300} 301 302run_tests() { 303 loginfo "Runnning startup/shutdown test" 304 MYPAINT_DEBUG=1 python setup.py demo --args='--run-and-quit' 305 loginfo "Running conformance tests." 306 python3 setup.py test 307 logok "Tests done." 308} 309 310 311# Command line processing 312 313case "$1" in 314 installdeps) 315 install_dependencies 316 update_mingw_src 317 src="${SRC_DIR}/mingw-w64-libmypaint" 318 cp ./windows/PKGBUILD-libmypaint $src/PKGBUILD 319 build_pkg "libmypaint" true 320 src="${SRC_DIR}/mingw-w64-mypaint-brushes2" 321 cp ./windows/PKGBUILD-mypaint-brushes2 $src/PKGBUILD 322 build_pkg "mypaint-brushes2" true 323 ;; 324 build) 325 build_for_testing 326 ;; 327 clean) 328 clean_local_repo 329 ;; 330 tests) 331 run_tests 332 # install_test 333 ;; 334 doctest) 335 run_doctest 336 ;; 337 bundle) 338 update_mingw_src 339 seed_mingw_src_mypaint_repo 340 src="${SRC_DIR}/mingw-w64-mypaint" 341 cp ./windows/PKGBUILD-mypaint $src/PKGBUILD 342 build_pkg "mypaint" false 343 bundle_mypaint 344 ;; 345 *) 346 grep '^#:' $0 | cut -d ':' -f 2-50 347 exit 2 348 ;; 349esac 350