File pkg2appimage of Package build-pkg2appimage

#!/bin/bash

#
# pkg 2 appimage converter
# really in alpha state atm
# GOAL: Only build/OBS specific parts shall be inside
# GOAL: As much as possible should be moved to Recipe and functions.sh
#

# stolen from Recipe file
parse_yaml() {
    local prefix=$2
    local s
    local w
    local fs
    s='[[:space:]]*'
    w='[a-zA-Z0-9_]*'
    fs="$(echo @|tr @ '\034')"
    sed -ne "s|^\($s\)\($w\)$s:$s\"\(.*\)\"$s\$|\1$fs\2$fs\3|p" \
        -e "s|^\($s\)\($w\)$s[:-]$s\(.*\)$s\$|\1$fs\2$fs\3|p" "$1" |
    awk -F"$fs" '{
    indent = length($1)/2;
    vname[indent] = $2;
    for (i in vname) {if (i > indent) {delete vname[i]}}
        if (length($3) > 0) {
            vn=""; for (i=0; i<indent; i++) {vn=(vn)(vname[i])("_")}
            printf("%s%s%s=(\"%s\")\n", "'"$prefix"'",vn, $2, $3);
        }
    }' | sed 's/_=/+=/g'
}
shell_execute() {
  if [ -f /tmp/recipe_script ] ; then
    rm /tmp/recipe_script
  fi
  parse_yaml $BUILD_SOURCE_DIR/appimage.yml "_" | grep "^$2+=" > /tmp/recipe_script
  sed -i -e 's|^'$2'+=("||g' /tmp/recipe_script
  sed -i -e 's|")$||g' /tmp/recipe_script
  if [ ! -s /tmp/recipe_script ]; then
     echo "ERROR: Empty or missing script section!"
     echo "       (or parser error, ensure to follow the '2 space2' rule for indenting)"
     exit 1
  fi
  bash -ex /tmp/recipe_script || exit 1
  rm /tmp/recipe_script
}
# Echo highest glibc version needed by the executable files in the current directory
glibc_needed()
{
  find . -name *.so -or -name *.so.* -or -type f -executable  -exec readelf -s '{}' 2>/dev/null \; | sed -n 's/.*@GLIBC_//p'| awk '{print $1}' | sort --version-sort | tail -n 1
}
fix_desktop() {
  # fix trailing semicolons
  for key in Actions Categories Implements Keywords MimeType NotShowIn OnlyShowIn; do
    sed -i '/'"$key"'.*[^;]$/s/$/;/' $1
  done
}

export TOPDIR="${PWD%/*}"
export STATIC_FILES=/usr/lib/appimagetool
. $STATIC_FILES/functions.sh

export BUILD_SOURCE_DIR=$TOPDIR/SOURCES/

RELEASE="Build0"
if [ "$1" == "--release" ]; then
  RELEASE="Build$2"
fi

# find out details about our master package... is there a better way?
PKG_NAME=`sed -n -e 's,^app: \(.*\),\1,p' appimage.yml`
PKG_ARCH=`uname -m`
if grep -q ^ingredients: appimage.yml; then
  APP_PKG_NAME="$PKG_NAME"
  if ! rpm -q "$PKG_NAME" >& /dev/null; then
    desktop_file=`find /usr/share/applications -iname "*${PKG_NAME}.desktop" | head -n 1`
    [ -n "$desktop_file" ] && APP_PKG_NAME=`rpm -qf $desktop_file --qf '%{NAME}'`
  fi

  if rpm -q "$APP_PKG_NAME" >& /dev/null; then
    PKG_NAME="$APP_PKG_NAME"
    PKG_VERSION=`rpm -q --qf '%{VERSION}-%{RELEASE}' "$PKG_NAME"`
#   PKG_ARCH=`rpm -q --qf '%{ARCH}' "$PKG_NAME"` #bad idea for noarch when additional libs get added
    # extend build number with a . since the dash is part of PKG_VERSION already
    PKG_VERSION="${PKG_VERSION}.${RELEASE}"
    export BUILD_APPDIR="$TOPDIR/${PKG_NAME}-${PKG_VERSION}-${PKG_ARCH}"
  fi
fi

# fallback for manual compile
if [ -z "$PKG_VERSION" ]; then
  # we build from source only
  PKG_VERSION="0"
  # try to get the version from .obsinfo
  if [ -e "${PKG_NAME}.obsinfo" ]; then
    PKG_VERSION=`sed -n -e 's,^version: \(.*\),\1,p' "${PKG_NAME}.obsinfo"`
  fi
  # add a dash before release since PKG_VERSION contains *no* build number
  PKG_VERSION="${PKG_VERSION}-${RELEASE}"
  export BUILD_APPDIR="$TOPDIR/${PKG_NAME}-${PKG_VERSION}-${PKG_ARCH}"
fi

ZYPPER="zypper --root=$BUILD_APPDIR -n --config $HOME/.pkg2appimage.zypp.conf"
# create zypp.conf
echo "[main]"                        >  $HOME/.pkg2appimage.zypp.conf
echo "rpm.install.excludedocs = yes" >> $HOME/.pkg2appimage.zypp.conf

# prepare AppDir
rm -rf "$BUILD_APPDIR"
mkdir -p "$BUILD_APPDIR"

# package base only
if [ -n "$ZYPPER" ]; then
  cp -al /.build.binaries "$BUILD_APPDIR/"
  $ZYPPER ar --no-gpgcheck /.build.binaries BUILD
  $ZYPPER ref
  # rpm only for now
  export BUILD_PKG_INSTALL="$ZYPPER install --no-recommends"
  # install ingredients
  ingredients=$( parse_yaml appimage.yml | sed -n '/^ingredients_packages+=/ s,.*("\(.*\)"),\1,p' )
  if [ -n "$ingredients" ]; then
     echo "Echo installing ingredients"
     $BUILD_PKG_INSTALL $ingredients || exit 1
  fi

  # deinstall blacklisted
  if [ -n "$ZYPPER" ]; then
    grep -v ^# /usr/lib/appimagetool/excludesuselist | while read i; do
      rpm --root="$BUILD_APPDIR" -q "$i" > /dev/null && rpm --root="$BUILD_APPDIR" -e --noscripts --nodeps "$i" && echo "deinstalled $i"
    done
    parse_yaml appimage.yml | sed -n '/^ingredients_exclude+=/ s,.*("\(.*\)"),\1,p' | while read i; do
      rpm --root="$BUILD_APPDIR" -q "$i" > /dev/null && rpm --root="$BUILD_APPDIR" -e --noscripts --nodeps "$i" && echo "deinstalled $i"
    done
  fi

  rm "$BUILD_APPDIR/etc/ld.so.cache"
fi

#
# build somehow
# OUTDATED Recipe file
#if [ -e "/$BUILD_SOURCE_DIR/Recipe" ]; then
#  pushd "/$BUILD_SOURCE_DIR/"
#  chmod a+x "Recipe"
#  . "./Recipe" appimage.yml
#  popd
#else
  pushd "$BUILD_APPDIR"
  # Execute extra steps defined in appimage.yml
  shell_execute $BUILD_SOURCE_DIR/appimage.yml _script
  popd
#fi

pushd "$BUILD_APPDIR"

if ! ls -d *.desktop >& /dev/null ; then
  echo "No .desktop file found, skipping AppImage creation"
  exit 1
fi

# glibc version extension
PKG_VERSION="${PKG_VERSION}.glibc$(glibc_needed)"

# Add the AppRun either way.
#if [ -n "$ZYPPER" ]; then
  [ -L AppRun ] && rm -f AppRun
  [ -x AppRun ] || cp -a /usr/lib/appimagetool/AppRun .
#fi

DESKTOP=$(find . -name '*.desktop' | sort | head -n 1)

# desktop-file-validate complains about missing trailing semicolons for some
# keys although the format definition says that they are optional
fix_desktop "$DESKTOP"

# ensure to have removed also all files from generic excludelist
delete_blacklisted

popd

#
# create image
#
rm -rf "$BUILD_APPDIR/.build.binaries"
mkdir -p "$TOPDIR/OTHER/"

# in sync with appimagetool string
img="$TOPDIR/OTHER/${PKG_NAME}-${PKG_VERSION}-${PKG_ARCH}.AppImage"

# NOTE: first sed argument is turning http:// to :///, but it gets fixed by the anyway needed // -> /
#
# AppImage lacks a built-in validation of content and relies on SSL.
# We are aware that SSL is not good enough, because every CA or mirror can manipulate data
# but we have nothing better yet. So, enforce https at least...
ZSYNC_URL="$( rpm --eval '%{_download_url}/%{_project}/%{_repository}'|sed -e 's,:,:/,g' -e 's,//,/,g' )"
[ "${ZSYNC_URL:0:5}" == "http:" ] && ZSYNC_URL="https:${ZSYNC_URL#http:}"
ZSYNC_URL="zsync|$ZSYNC_URL/${PKG_NAME}-latest-${PKG_ARCH}.AppImage.zsync"
echo "echo zsync_url: $ZSYNC_URL"
if [ -x /usr/bin/appimagetool ]; then
  echo "Use appimagetool"
  pushd "$TOPDIR/OTHER/"
  PATH=/usr/lib/appimagetool/:$PATH appimagetool -u "$ZSYNC_URL" "$BUILD_APPDIR" "$img" || exit 1
  popd
else
  MKSQUASHFS=mksquashfs
  [ -x /usr/lib/appimagetool/mksquashfs ] && MKSQUASHFS=/usr/lib/appimagetool/mksquashfs
  $MKSQUASHFS "$BUILD_APPDIR" "${PKG_NAME}.squashfs" -root-owned -noappend || exit 1
  cat /usr/lib/appimagetool/runtime "${PKG_NAME}.squashfs" > "$img" || exit 1
  rm "${PKG_NAME}.squashfs"
  chmod a+x "$img" || exit 1
  zsyncmake "$img" -u "${img##*/}" -o "${img}.zsync" || exit 1
fi
/usr/lib/appimagetool/digest "$img" > "${img}.digest" || exit 1

#
# validate image if linter exists
#
if [ -x /usr/bin/appimagelint ]; then
  /usr/bin/appimagelint "$img" || exit 1
fi

exit 0

openSUSE Build Service is sponsored by