diff --git a/appimage-build.py b/appimage-build.py new file mode 100755 index 00000000..9c746ffc --- /dev/null +++ b/appimage-build.py @@ -0,0 +1,360 @@ +#!/usr/bin/env python2 +# Prepares directory for AppImage +import subprocess, shutil, tarfile, uuid, sys, os +from collections import namedtuple + +APP="syncthing-gtk" +TARGET = "./appimage" +KEEP_BUSYBOX = True +CDN = "http://nl.alpinelinux.org/alpine/v3.10" +APK_TOOLS = "https://github.com/alpinelinux/apk-tools/releases/download/v2.10.4/apk-tools-2.10.4-x86_64-linux.tar.gz" +BUILD_ID = str(uuid.uuid4()) +ALPINE_KEYS = { + "4a6a0840": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1yHJxQgsHQREclQu4O" + + "he\nqxTxd1tHcNnvnQTu/UrTky8wWvgXT+jpveroeWWnzmsYlDI93eLI2ORakxb3gA2O" + + "\nQ0Ry4ws8vhaxLQGC74uQR5+/yYrLuTKydFzuPaS1dK19qJPXB8GMdmFOijnXX4SA\n" + + "jixuHLe1WW7kZVtjL7nufvpXkWBGjsfrvskdNA/5MfxAeBbqPgaq0QMEfxMAn6/R\nL5" + + "kNepi/Vr4S39Xvf2DzWkTLEK8pcnjNkt9/aafhWqFVW7m3HCAII6h/qlQNQKSo\nGuH3" + + "4Q8GsFG30izUENV9avY7hSLq7nggsvknlNBZtFUcmGoQrtx3FmyYsIC8/R+B\nywIDAQ" + + "AB", + "5243ef4b": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvNijDxJ8kloskKQpJd" + + "x+\nmTMVFFUGDoDCbulnhZMJoKNkSuZOzBoFC94omYPtxnIcBdWBGnrm6ncbKRlR+6oy" + + "\nDO0W7c44uHKCFGFqBhDasdI4RCYP+fcIX/lyMh6MLbOxqS22TwSLhCVjTyJeeH7K\n" + + "aA7vqk+QSsF4TGbYzQDDpg7+6aAcNzg6InNePaywA6hbT0JXbxnDWsB+2/LLSF2G\nmn" + + "hJlJrWB1WGjkz23ONIWk85W4S0XB/ewDefd4Ly/zyIciastA7Zqnh7p3Ody6Q0\nsS2M" + + "Jzo7p3os1smGjUF158s6m/JbVh4DN6YIsxwl2OjDOz9R0OycfJSDaBVIGZzg\ncQIDAQ" + + "AB", + "524d27bb": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr8s1q88XpuJWLCZALd" + + "Kj\nlN8wg2ePB2T9aIcaxryYE/Jkmtu+ZQ5zKq6BT3y/udt5jAsMrhHTwroOjIsF9DeG" + + "\ne8Y3vjz+Hh4L8a7hZDaw8jy3CPag47L7nsZFwQOIo2Cl1SnzUc6/owoyjRU7ab0p\n" + + "iWG5HK8IfiybRbZxnEbNAfT4R53hyI6z5FhyXGS2Ld8zCoU/R4E1P0CUuXKEN4p0\n64" + + "dyeUoOLXEWHjgKiU1mElIQj3k/IF02W89gDj285YgwqA49deLUM7QOd53QLnx+\nxrIr" + + "Pv3A+eyXMFgexNwCKQU9ZdmWa00MjjHlegSGK8Y2NPnRoXhzqSP9T9i2HiXL\nVQIDAQ" + + "AB", + "5261cecb": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwlzMkl7b5PBdfMzGdC" + + "T0\ncGloRr5xGgVmsdq5EtJvFkFAiN8Ac9MCFy/vAFmS8/7ZaGOXoCDWbYVLTLOO2qtX" + + "\nyHRl+7fJVh2N6qrDDFPmdgCi8NaE+3rITWXGrrQ1spJ0B6HIzTDNEjRKnD4xyg4j\n" + + "g01FMcJTU6E+V2JBY45CKN9dWr1JDM/nei/Pf0byBJlMp/mSSfjodykmz4Oe13xB\nCa" + + "1WTwgFykKYthoLGYrmo+LKIGpMoeEbY1kuUe04UiDe47l6Oggwnl+8XD1MeRWY\nsWgj" + + "8sF4dTcSfCMavK4zHRFFQbGp/YFJ/Ww6U9lA3Vq0wyEI6MCMQnoSMFwrbgZw\nwwIDAQ" + + "AB", + "58199dcc": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3v8/ye/V/t5xf4JiXL" + + "Xa\nhWFRozsnmn3hobON20GdmkrzKzO/eUqPOKTpg2GtvBhK30fu5oY5uN2ORiv2Y2ht" + + "\neLiZ9HVz3XP8Fm9frha60B7KNu66FO5P2o3i+E+DWTPqqPcCG6t4Znk2BypILcit\n" + + "wiPKTsgbBQR2qo/cO01eLLdt6oOzAaF94NH0656kvRewdo6HG4urbO46tCAizvCR\nCA" + + "7KGFMyad8WdKkTjxh8YLDLoOCtoZmXmQAiwfRe9pKXRH/XXGop8SYptLqyVVQ+\ntegO" + + "D9wRs2tOlgcLx4F/uMzHN7uoho6okBPiifRX+Pf38Vx+ozXh056tjmdZkCaV\naQIDAQ" + + "AB", + "58cbb476": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoSPnuAGKtRIS5fEgYP" + + "XD\n8pSGvKAmIv3A08LBViDUe+YwhilSHbYXUEAcSH1KZvOo1WT1x2FNEPBEFEFU1Eyc" + + "\n+qGzbA03UFgBNvArurHQ5Z/GngGqE7IarSQFSoqewYRtFSfp+TL9CUNBvM0rT7vz\n" + + "2eMu3/wWG+CBmb92lkmyWwC1WSWFKO3x8w+Br2IFWvAZqHRt8oiG5QtYvcZL6jym\nY8" + + "T6sgdDlj+Y+wWaLHs9Fc+7vBuyK9C4O1ORdMPW15qVSl4Lc2Wu1QVwRiKnmA+c\nDsH/" + + "m7kDNRHM7TjWnuj+nrBOKAHzYquiu5iB3Qmx+0gwnrSVf27Arc3ozUmmJbLj\nzQIDAQ" + + "AB", + "58e4f17d": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvBxJN9ErBgdRcPr5g4" + + "hV\nqyUSGZEKuvQliq2Z9SRHLh2J43+EdB6A+yzVvLnzcHVpBJ+BZ9RV30EM9guck9sh" + + "\nr+bryZcRHyjG2wiIEoduxF2a8KeWeQH7QlpwGhuobo1+gA8L0AGImiA6UP3LOirl\n" + + "I0G2+iaKZowME8/tydww4jx5vG132JCOScMjTalRsYZYJcjFbebQQolpqRaGB4iG\nWq" + + "hytWQGWuKiB1A22wjmIYf3t96l1Mp+FmM2URPxD1gk/BIBnX7ew+2gWppXOK9j\n1BJp" + + "o0/HaX5XoZ/uMqISAAtgHZAqq+g3IUPouxTphgYQRTRYpz2COw3NF43VYQrR\nbQIDAQ" + + "AB", +} +PythonDep = namedtuple("PythonDep", "name, version") +NativeDep = namedtuple("NativeDep", "name") + +DEPS = [ + # KindOfDep(name, version) + NativeDep("cairo"), + NativeDep("python2"), + NativeDep("gtk+3.0"), + # NativeDep("gvfs"), # TODO: This brings-in half of appimage size + NativeDep("gdk-pixbuf"), + NativeDep("gobject-introspection"), + NativeDep("py2-pip"), + NativeDep("py2-cffi"), + NativeDep("py2-bcrypt"), + # PythonDep("python-dateutil", "2.8.1"), + NativeDep("py2-dateutil"), + NativeDep("py2-gobject3"), +] + + +def makedirs(a): + try: + os.makedirs(a) + except OSError, e: + if e.errno == 17: # Already exists + return + raise + + +def symlink(a, b): + try: + os.symlink(a, b) + except OSError, e: + if e.errno == 17: # Already exists + return + raise + + +def create_dirs(path): + makedirs(os.path.join(path, "usr/share")) + makedirs(os.path.join(path, "usr/bin")) + makedirs(os.path.join(path, "usr/lib")) + makedirs(os.path.join(path, "lib")) + symlink("usr/bin", os.path.join(path, "bin")) + symlink("bin", os.path.join(path, "usr/sbin")) + symlink("usr/bin", os.path.join(path, "sbin")) + + +def rm_if_exists(path): + try: + os.unlink(path) + except OSError, e: + if e.errno == 2: # File not found + return + raise + + +def download(url, target_filename): + p = subprocess.Popen(["wget", url, "--continue", "-O", target_filename]) + p.communicate() + assert p.returncode == 0, "Download failed" + + +def run_bwrapped(path, tmp, args, bwrap_opts=[]): + """ + Takes subprocess.Popen arguments, returns subprocess.Popen instance of those + arguments chrooted with bwrap + """ + bwrap_opts = list(bwrap_opts) + if os.path.exists(os.path.join(path, "build-uuid")): + old_build_uuid = open(os.path.join(path, "build-uuid"), "r").read() + bwrap_opts += [ + "--symlink", + "/appimage/elf-interpreter", + "/tmp/%s-elf-interpreter" % (old_build_uuid, ), + ] + + cmd = [ + "bwrap", + "--bind", path, "/appimage", + "--symlink", "appimage/usr", "/usr", + "--symlink", "appimage/lib", "/lib", + "--symlink", "appimage/usr/bin", "/bin", + "--symlink", "appimage/usr/bin", "/sbin", + "--symlink", "appimage/var", "/var", + "--symlink", "appimage/etc", "/etc", + "--dev", "/dev", + "--tmpfs", "/tmp", + "--bind", "/sys", "/sys", + "--bind", "/proc", "/proc", + "--ro-bind", "/etc/passwd", "/etc/passwd", + "--ro-bind", "/etc/group", "/etc/group", + "--chdir", "/", + "--unshare-user", "--uid", "0", "--gid", "0", + "--share-net", + ] + bwrap_opts + [ + "--", + ] + args + print " ".join(cmd) + return subprocess.Popen(cmd) + + +def apk(path, tmp, operation, *opts): + p = run_bwrapped(path, tmp, [ + "/appimage/apk", + operation, + "--root", "/appimage", + "--arch", "x86_64", + ] + list(opts)) + p.communicate() + assert p.returncode == 0, "APK failed" + + +def get_interpreted(filename): + p = subprocess.Popen(["readelf", "-l", filename], stdout=subprocess.PIPE) + stdout, _ = p.communicate() + piece = "".join([ x for x in stdout.split("\n") if "interpreter:" in x ]) + return piece.strip("[]\t ").split(":")[-1].strip(" ") + + +def unpack(target_path, tar_gz_filename, *opts): + old_path = os.getcwd() + os.chdir(target_path) + p = subprocess.Popen(["tar", "fxz", tar_gz_filename, "--warning=none"] + list(opts)) + p.communicate() + os.chdir(old_path) + assert p.returncode == 0, "Extraction failed" + + +def prepare_apk_tools(path, tmp): + download(APK_TOOLS, os.path.join(tmp, "/tmp/appimage-build-apk-tools-static.tar.gz")) + unpack(path, os.path.join(tmp, "/tmp/appimage-build-apk-tools-static.tar.gz"), "--strip-components=1") + rm_if_exists(os.path.join(path, ".PKGINFO")) + + makedirs(os.path.join(path, "etc/apk")) + repofile = open(os.path.join(path, "etc/apk/repositories"), "w") + repofile.write(CDN + "/main" + "\n") + repofile.write(CDN + "/community" + "\n") + repofile.close() + + shutil.copy("/etc/resolv.conf", os.path.join(path, "etc/resolv.conf")) + + makedirs(os.path.join(path, "etc/apk/keys")) + for (id, content) in ALPINE_KEYS.items(): + keyfile_name = "etc/apk/keys/alpine-devel@lists.alpinelinux.org-%s.rsa.pub" % (id,) + keyfile = open(os.path.join(path, keyfile_name), "w") + keyfile.write("-----BEGIN PUBLIC KEY-----\n") + keyfile.write(content + "\n") + keyfile.write("-----END PUBLIC KEY-----\n") + keyfile.close() + + apk(path, tmp, "add", "--update-cache", "--initdb", "--no-scripts", "busybox-static") + p = run_bwrapped(path, tmp, ["/bin/busybox.static", "--install", "-s"]) + p.communicate() + assert p.returncode == 0, "Busybox install install failed" + + # fake_install(path, "polkit", "0.116-r0") + # fake_install(path, "linux-pam", "1.3.0-r1") + + +def cleanup(path): + CLEANUP_BINARIES = [ + "gtk3-widget-factory", + "gtk3-demo-application", + "gtk3-demo", + ] + if KEEP_BUSYBOX: + if os.path.exists(os.path.join(path, "usr/bin/busybox")): + symlink("busybox.static", os.path.join(path, "usr/bin/busybox")) + else: + CLEANUP_BINARIES += ["busybox", "busybox.static"] + + for filename in CLEANUP_BINARIES: + full_path = os.path.join(path, "usr/bin", filename) + if os.path.exists(full_path): + os.unlink(full_path) + + +def break_paths(path): + for filename in os.listdir(os.path.join(path, "usr/bin")): + full_path = os.path.join(path, "usr/bin", filename) + if os.path.islink(full_path): + target = os.readlink(full_path) + if target == "/bin/busybox.static" or target == "/bin/busybox": + if KEEP_BUSYBOX: + # Replace absolute path with relative path + os.unlink(full_path) + os.symlink("busybox.static", full_path) + else: + # Remove files linked to busybox + os.unlink(full_path) + elif open(full_path, "rb").read(4) == b"\x7fELF": + # Set ELF interpreter to predictable, absolute path + interpreter = get_interpreted(full_path) + if interpreter == "/lib/ld-musl-x86_64.so.1" or "-elf-interpreter" in interpreter: + p = subprocess.Popen(["patchelf", + "--set-interpreter", "/tmp/%s-elf-interpreter" % (BUILD_ID,), + full_path], stderr=subprocess.PIPE) + p.communicate() + assert p.returncode == 0, "patchelf --set-interpreter failed" + + # Store build-uuid so ELF interpreter path can be reconstructed later + open(os.path.join(path, "build-uuid"), "w").write(BUILD_ID) + symlink("lib/ld-musl-x86_64.so.1", os.path.join(path, "elf-interpreter")) + + +def install_native_deps(path, tmp): + native_deps = [ + dep.name for dep in DEPS + if isinstance(dep, NativeDep) + ] + apk(path, tmp, "add", "--clean-protected", "--no-scripts", "-l", + *native_deps) + + # Run triggers + # + # APK seems to use chroot to execute .post-install scripts and triggers + # chroot fails under bwrap and for that reason, scripts are executed + # using this method after package is installed + def run_script(path, tmp, tar_file, name): + tar_file.extract(name, path=os.path.join(path, "run_script")) + p = run_bwrapped(path, tmp, ["sh", "/appimage/run_script/%s" % (name,)]) + p.communicate() + assert p.returncode == 0 or name.endswith(".trigger"), \ + "Failed to run script '%s'" % (name, ) + shutil.rmtree(os.path.join(path, "run_script"), ignore_errors=True) + + t = tarfile.TarFile(os.path.join(path, "lib/apk/db/scripts.tar"), "r") + triggers = [ + x.name for x in t.getmembers() if x.name.endswith(".trigger") + ] + post_install = [ + x.name for x in t.getmembers() + if x.name.startswith("%s-" % (dep.name,)) and x.name.endswith(".post-install") + ] + for script in post_install + triggers: + run_script(path, tmp, t, script) + t.close() + + run_bwrapped(path, tmp, ["/usr/bin/gio-querymodules", + "/usr/lib/gio/modules"]).communicate() + run_bwrapped(path, tmp, ["/usr/bin/glib-compile-schemas", + "/usr/share/glib-2.0/schemas"]).communicate() + + +def install_python_deps(path, tmp): + py_deps = [ + "%s==%s" % (dep.name, dep.version) for dep in DEPS + if isinstance(dep, PythonDep) + ] + if not py_deps: return + + p = run_bwrapped(path, tmp, ["pip", "install"] + py_deps) + p.communicate() + assert p.returncode == 0, "pip install failed" + + +def install_python_app(path, tmp, dir_with_setup_py): + bwrap_opts = ["--bind", dir_with_setup_py, "/py-app", "--chdir", "/py-app"] + p = run_bwrapped(path, tmp, bwrap_opts=bwrap_opts, + args=["python2", "setup.py", "build"]) + p.communicate() + assert p.returncode == 0, "setup.py build failed" + + p = run_bwrapped(path, tmp, bwrap_opts=bwrap_opts, + args=["python2", "setup.py", "install"]) + p.communicate() + assert p.returncode == 0, "setup.py build failed" + + +if __name__ == "__main__": + path, tmp = os.path.abspath(TARGET), "/tmp" + create_dirs(path) + prepare_apk_tools(path, tmp) + install_native_deps(path, tmp) + install_python_deps(path, tmp) + + # Run setup.py + install_python_app(path, tmp, ".") + + # Copy AppRun script + shutil.copy("scripts/appimage-AppRun.sh", os.path.join(path, "AppRun")) + + # Copy & patch desktop file + desktop = open("%s.desktop" % (APP,), "r").read() + # sed -i "s/Icon=.*/Icon=${APP}/g" ${BUILD_APPDIR}/${APP}.desktop + open(os.path.join(TARGET, "%s.desktop" % (APP,)), "w").write(desktop) + + # Copy icon + shutil.copy("icons/%s.png" % (APP,), os.path.join(TARGET, "%s.png" % (APP,))) + + # Fix path & clean-up directory + cleanup(path) + break_paths(path) + + print "\n==================" + print "Run appimagetool -n %s to finish prepared appimage" % (TARGET,) + diff --git a/appimage-build.sh b/appimage-build.sh deleted file mode 100755 index 77f09446..00000000 --- a/appimage-build.sh +++ /dev/null @@ -1,138 +0,0 @@ -#!/bin/bash -APP="syncthing-gtk" -EXEC="syncthing-gtk" -[ x"$BUILD_APPDIR" == "x" ] && BUILD_APPDIR=$(pwd)/appimage - -function download_dep() { - NAME=$1 - URL=$2 - if [ -e ../../${NAME}.obstargz ] ; then - # Special case for OBS - cp ../../${NAME}.obstargz /tmp/${NAME}.tar.gz - elif [ -e ${NAME}.tar.gz ] ; then - cp ${NAME}.tar.gz /tmp/${NAME}.tar.gz - else - wget -c "${URL}" -O /tmp/${NAME}.tar.gz - fi -} - -function setup_dep() { - NAME="$1" - mkdir -p /tmp/${NAME} - pushd /tmp/${NAME} - tar --extract --strip-components=1 -f /tmp/${NAME}.tar.gz - python2 setup.py build - PYTHONPATH=${BUILD_APPDIR}/usr/lib/python2.7/site-packages python2 \ - setup.py install --optimize=1 \ - --prefix="/usr/" \ - --root="${BUILD_APPDIR}" - popd -} - -function build_dep() { - NAME="$1" - CONFIGURE="$2" - if [ -e ${NAME}.prebuilt.tar.gz ] ; then - cp ${NAME}.prebuilt.tar.gz /tmp/${NAME}.prebuilt.tar.gz - unpack_dep "$NAME.prebuilt" - return $? - fi - mkdir -p /tmp/${NAME} - pushd /tmp/${NAME} - tar --keep-newer-files --extract --strip-components=1 -f /tmp/${NAME}.tar.gz - [ $# -gt 2 ] && $3 - ./configure $(echo $CONFIGURE) - make - make DESTDIR="${BUILD_APPDIR}" install - popd -} - -function unpack_dep() { - NAME="$1" - pushd ${BUILD_APPDIR} - tar --extract --exclude="usr/include**" --exclude="usr/lib/pkgconfig**" \ - --exclude="usr/lib/python3.6**" -f /tmp/${NAME}.tar.gz - popd -} - -function unpack_gi() { - NAME="$1" - pushd ${BUILD_APPDIR} - tar --extract --wildcards "usr/lib/girepository-1.0/*" -f /tmp/${NAME}.tar.gz - popd -} - -set -exu # display commands, no empty vars, terminate on 1st failure - -# Download deps -download_dep "python-dateutil-1.5" "http://labix.org/download/python-dateutil/python-dateutil-1.5.tar.gz" -download_dep "six-1.11.0" "https://pypi.python.org/packages/16/d8/bc6316cf98419719bd59c91742194c111b6f2e85abac88e496adefaf7afe/six-1.11.0.tar.gz" -download_dep "python-bcrypt-3.1.7" "https://archive.archlinux.org/packages/p/python2-bcrypt/python2-bcrypt-3.1.7-1-x86_64.pkg.tar.xz" -download_dep "python-cairo-1.18.1" "https://archive.archlinux.org/packages/p/python2-cairo/python2-cairo-1.18.1-1-x86_64.pkg.tar.xz" -download_dep "python-cffi-1.12.3" "https://archive.archlinux.org/packages/p/python2-cffi/python2-cffi-1.12.3-1-x86_64.pkg.tar.xz" -download_dep "python-gobject-3.32.2" "https://archive.archlinux.org/packages/p/python2-gobject/python2-gobject-3.32.2-1-x86_64.pkg.tar.xz" -download_dep "gir-1.60.2" "https://archive.archlinux.org/packages/g/gobject-introspection-runtime/gobject-introspection-runtime-1.60.2-1-x86_64.pkg.tar.xz" -download_dep "gtk-3.24.7" "https://archive.archlinux.org/packages/g/gtk3/gtk3-3.24.7-1-x86_64.pkg.tar.xz" -download_dep "atk-2.32" "https://archive.archlinux.org/packages/a/atk/atk-2.32-1-x86_64.pkg.tar.xz" -download_dep "glib-2.60.6" "https://archive.archlinux.org/packages/g/glib2/glib2-2.60.6-1-x86_64.pkg.tar.xz" -download_dep "pango-1.44.3" "https://archive.archlinux.org/packages/p/pango/pango-1%3A1.44.3-1-x86_64.pkg.tar.xz" -download_dep "gdk-pixbuf-2.36.9" "http://ftp.gnome.org/pub/gnome/sources/gdk-pixbuf/2.36/gdk-pixbuf-2.36.9.tar.xz" -download_dep "libxml2-2.9.9" "https://archive.archlinux.org/packages/l/libxml2/libxml2-2.9.9-2-x86_64.pkg.tar.xz" -download_dep "librsvg-2.42.2" "http://ftp.gnome.org/pub/gnome/sources/librsvg/2.42/librsvg-2.42.2.tar.xz" -download_dep "libpng-1.6.37" "https://archive.archlinux.org/packages/l/libpng/libpng-1.6.37-1-x86_64.pkg.tar.xz" -download_dep "libepoxy-1.5.3" "https://archive.archlinux.org/packages/l/libepoxy/libepoxy-1.5.3-1-x86_64.pkg.tar.xz" -download_dep "libnotify-0.7.8" "https://archive.archlinux.org/packages/l/libnotify/libnotify-0.7.8-1-x86_64.pkg.tar.xz" -download_dep "libxrandr-1.5.2" "https://archive.archlinux.org/packages/l/libxrandr/libxrandr-1.5.2-1-x86_64.pkg.tar.xz" -download_dep "icu-60.2" "https://ssl.icu-project.org/files/icu4c/60.2/icu4c-60_2-src.tgz" -download_dep "libpcre-8.42" "https://ftp.pcre.org/pub/pcre/pcre-8.42.tar.gz" - -# Prepare & build -mkdir -p ${BUILD_APPDIR}/usr/lib/python2.7/site-packages/ -setup_dep "python-dateutil-1.5" -setup_dep "six-1.11.0" -unpack_dep "python-bcrypt-3.1.7" -unpack_dep "python-cairo-1.18.1" -unpack_dep "python-cffi-1.12.3" -unpack_dep "python-gobject-3.32.2" - -# PYTHON=python2 build_dep "glib-2.56.1" "--disable-selinux --disable-fam --disable-xattr --prefix=/usr" -unpack_dep "glib-2.60.6" -build_dep "icu-60.2" "--prefix=/usr --disable-dyload --enable-rpath --disable-draft --disable-extras --disable-tools --disable-tests --disable-samples" "cd source" -unpack_dep "gtk-3.24.7" -# PYTHON=python2 build_dep "gtk-3.24.5" "--prefix=/usr --disable-rpath --enable-x11-backend --disable-cups --disable-papi --disable-cloudprint --enable-introspection=yes" -build_dep "librsvg-2.42.2" "--prefix=/usr --disable-rpath --disable-static --enable-introspection=yes --disable-tools" -build_dep "libpcre-8.42" "--prefix=/usr --disable-rpath --disable-cpp --disable-static" -build_dep "gdk-pixbuf-2.36.9" "--prefix=/usr --disable-rpath --disable-static --enable-introspection=yes --without-libtiff --with-x11 --with-included-loaders=png,jpeg" -unpack_dep "gir-1.60.2" -unpack_dep "atk-2.32" -unpack_gi "pango-1.44.3" -unpack_dep "libxml2-2.9.9" -unpack_dep "libpng-1.6.37" -unpack_dep "libepoxy-1.5.3" -unpack_dep "libnotify-0.7.8" -unpack_dep "libxrandr-1.5.2" - -# Cleanup -rm -R ${BUILD_APPDIR}/usr/bin -rm -R ${BUILD_APPDIR}/usr/include || true -for x in aclocal gtk-doc gdb gettext libalpm doc man vala locale bash-completion ; do - rm -R ${BUILD_APPDIR}/usr/share/$x || true -done - - -python2 setup.py build -python2 setup.py install --prefix ${BUILD_APPDIR}/usr - -# Move & patch desktop file -mv ${BUILD_APPDIR}/usr/share/applications/${APP}.desktop ${BUILD_APPDIR}/ -sed -i "s/Icon=.*/Icon=${APP}/g" ${BUILD_APPDIR}/${APP}.desktop - -# Copy icon -cp -H icons/${APP}.png ${BUILD_APPDIR}/${APP}.png -[ -e "${BUILD_APPDIR}/usr/share/${APP}/icons/${APP}.png" ] || ln -s "../../../../${APP}.png" "${BUILD_APPDIR}/usr/share/${APP}/icons/${APP}.png" - -# Copy AppRun script -cp scripts/appimage-AppRun.sh ${BUILD_APPDIR}/AppRun -chmod +x ${BUILD_APPDIR}/AppRun - -echo "Run appimagetool -n ${BUILD_APPDIR} to finish prepared appimage" diff --git a/scripts/appimage-AppRun.sh b/scripts/appimage-AppRun.sh index a79a7fe5..c93ad828 100755 --- a/scripts/appimage-AppRun.sh +++ b/scripts/appimage-AppRun.sh @@ -1,41 +1,38 @@ #!/bin/bash +export BUILD_UUID=$(cat ${APPDIR}/build-uuid) + +# General +rm -f "/tmp/${BUILD_UUID}-elf-interpreter" +ln -s "${APPDIR}/elf-interpreter" "/tmp/${BUILD_UUID}-elf-interpreter" export PATH=${APPDIR}:${APPDIR}/usr/bin:$PATH -export LD_LIBRARY_PATH=${APPDIR}/usr/lib:$LD_LIBRARY_PATH -export LD_LIBRARY_PATH=${APPDIR}/usr/lib64:$LD_LIBRARY_PATH +export LD_LIBRARY_PATH=${APPDIR}/usr/lib +export LD_LIBRARY_PATH=${APPDIR}/lib:$LD_LIBRARY_PATH + +# gdk-pixbuf +cat "${APPDIR}/usr/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache" \ + | sed "s|/usr/lib/gdk-pixbuf-2.0|${APPDIR}/usr/lib/gdk-pixbuf-2.0|g" \ + > "/tmp/${BUILD_UUID}-gdk-pixbuf-loaders.cache" export GI_TYPELIB_PATH=${APPDIR}/usr/lib/girepository-1.0 -export PYTHONPATH=${APPDIR}/usr/lib/python2.7/site-packages:$PYTHONPATH -export PYTHONPATH=${APPDIR}/usr/lib64/python2.7/site-packages:$PYTHONPATH +export GDK_PIXBUF_MODULEDIR=${APPDIR}/usr/lib/gdk-pixbuf-2.0/2.10.0/loaders +export GDK_PIXBUF_MODULE_FILE="/tmp/${BUILD_UUID}-gdk-pixbuf-loaders.cache" -function dependency_check_failed() { - # This checks 4 different ways to open error message in addition to - # throwing it to screen directly - echo "$1" >&2 - - [ -e /usr/bin/zenity ] && run_and_die /usr/bin/zenity --no-wrap --error --text "$1" - [ -e /usr/bin/yad ] && run_and_die /usr/bin/yad --error --text "$1" - echo "$1" > /tmp/depcheck.$$.txt - [ -e /usr/bin/Xdialog ] && run_and_die /usr/bin/Xdialog --textbox /tmp/depcheck.$$.txt 10 100 - [ -e /usr/bin/xdg ] && run_and_die /usr/bin/xdg-open /tmp/depcheck.$$.txt - exit 1 -} +# Python +export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$GDK_PIXBUF_MODULEDIR" +export PYTHONPATH=${APPDIR}/usr/lib/python2.7/site-packages +export PYTHONHOME=${APPDIR}/usr/ -function run_and_die() { - "$@" - exit 1 -} # Start if [ "x$1" == "xbash" ] ; then cd "${APPDIR}" bash +elif [ "x$1" == "xsh" ] ; then + cd "${APPDIR}" + bin/busybox sh else - # Check dependencies 1st - python2 -c "pass" \ - || dependency_check_failed "Please, install python package using" - python2 -c 'import gi; gi.require_version("Gtk", "3.0"); from gi.repository import Gtk' \ - || dependency_check_failed "Syncthing-GTK requires GTK and gobject-introspection packages.\n Please, install GTK3 and gobject-introspection packages using your package manager" - python2 -c 'import cairo;' \ - || dependency_check_failed "Cairo library is missing.\n Please, install cairo package using your package manager" - python2 ${APPDIR}/usr/bin/syncthing-gtk $@ fi + +rm -f "/tmp/${BUILD_UUID}-elf-interpreter" \ + "/tmp/${BUILD_UUID}-gdk-pixbuf-loaders.cache" +