#!/bin/bash # Author : Ismael BarrosĀ² # License : BSD http://en.wikipedia.org/wiki/BSD_license pg4l_dir=$(dirname $(readlink -f $0)) . "$pg4l_dir/util.sh" shopt -s extglob # Enable extended globs if [ -z "$*" ]; then echo "Usage: $0 [options]" echo " Package list:" echo " : add 'package'" echo " -: ignore 'package'" echo " Options:" echo " --skip-download: Skip package download" echo " --skip-unpack: Skip package unpacking" echo " --skip-bringup: Skip AppDir bringup" echo " --skip-cleanup: Skip AppDir cleanup" echo " --skip-auto-copy-libs: Skip copying dynamic libraries" echo " --here: AppDir is the current directory" exit fi Distro="$(egrep "^ID_LIKE=(.*)" /etc/os-release | cut -d= -f2)" [ -n "$Distro" ] || Distro="$(egrep "^ID=(.*)" /etc/os-release | cut -d= -f2)" [ -n "$Distro" ] || die "Could not find distro" case "$Distro" in Arch|arch|archlinux) Tag="archlinux" ;; Ubuntu*) Tag="ubuntu" ;; Debian*) Tag="debian" ;; esac case "$Distro" in Arch|arch|archlinux) getPackageInfo() { if [ -f "$1" ]; then pacman -Qip "$1" else yay -Si "$1" fi } getPackageInfoField() { getPackageInfo "$1" | egrep "$2" | cut -d: -f2- | trimp } find_dependencies() { # TODO: Remove version numbers #for pkg in ${pkgs[@]}; do # pkgs=(${pkgs[@]/#$pkg/${pkg%%[<>=]*}}) #done getPackageInfoField "$1" "Depends On" | grep -v None } getPackageName() { getPackageInfoField "$1" "Name"; } getPackageVersion() { v=$(getPackageInfoField "$1" "Version"); echo ${v%-*}; } getPackageURL() { getPackageInfoField "$1" "URL"; } getPackageDeveloper() { true; } getPackageLicenses() { getPackageInfoField "$1" "Licenses"; } find_file_for_package() { pacman -Swddp "$1" | sed "s|file://||"; } uncompress_package_file() { tar -xf $1; } package_files() { pacman -Ql "$1"; } install_package() { yay -S "$1"; } download_package() { case "$1" in aur/*) pkg=${1#*/} [ -f "$(find_file_for_package "$pkg")" ] && { echo "Package $pkg already downloaded"; return; } echo "Building $pkg ..." mkdir -p /tmp/pacman2AppDir_build/ pushd /tmp/pacman2AppDir_build/ || exit 1 yay -G "$pkg" || die "Could not download package from AUR" pushd "$pkg" || exit 1 makepkg -d || exit 1 f=$(echo ${pkg}*.pkg.tar*) sudo mv -v "$f" /var/cache/pacman/pkg/ || exit 1 popd rm -rf "$pkg" popd ;; *) sudo pacman -Swdd --noconfirm "$1" ;; esac } fixAppDir() { rm -vf usr/bin/{ar,as,nm,gprof,elfedit,ld,ld.*,objcopy,objdump,makehrtf,c++filt,addr2line,curl,*-config,*-info,png2pnm,pnm2png,ranlib,readelf,size,strings,strip,wxrc*,xml2-config,xmlcatalog,xmllint,glewinfo,visualinfo,cjpeg,desktop-file-*,djpeg,jpegtran,lua,luac,rdjpgcom,update-desktop-database,wrjpgcom} } cleanAppDir() { rm -f .INSTALL .PKGINFO .MTREE } ;; Ubuntu* | Debian*) getPackageInfo() { if [ -f "$1" ]; then dpkg --info "$1" else apt-get show "$1" fi } getPackageInfoField() { getPackageInfo "$1" | egrep "$2" | cut -d: -f2- | trimp } find_dependencies() { parsedeps() { grep Depends | cut -d: -f2- | sed -e"s/,/\n/g" | trimp | cut -d" " -f1; } if [ -f "$1" ]; then dpkg --info "$1" | parsedeps else apt-cache show "$1" | parsedeps fi } getPackageName() { getPackageInfoField "$1" "Package"; } getPackageVersion() { v=$(getPackageInfoField "$1" "Version"); echo ${v%-*}; } getPackageURL() { getPackageInfoField "$1" "Homepage"; } getPackageDeveloper() { true; } getPackageLicenses() { true; } find_file_for_package() { ls -1t /var/cache/apt/archives/${1}_*_{all,i386}.deb 2>/dev/null| head -n1; } uncompress_package_file() { dpkg-deb -x "$1" .; } package_files() { dpkg -L "$1"; } download_package() { sudo apt-get -y --force-yes --download-only install --reinstall "$1"; } install_package() { sudo apt-get -y --force-yes install "$1"; } fixAppDir() { ls lib/i386-linux-gnu/ if [ -d usr/games/ ]; then mkdir -p usr/bin/ mv -v usr/games/* usr/bin/ rmdir -v usr/games fi # etc/ld.so.conf.d/i686-linux-gnu.conf if [ -d lib/i386-linux-gnu/ ]; then mkdir -p usr/lib/ rsync -av lib/i386-linux-gnu/ usr/lib/ rm -rf lib/i386-linux-gnu unlink lib/ld-linux.so.2 rmdir -v lib fi if [ -d usr/lib/i386-linux-gnu/ ]; then mkdir -p usr/lib/ rsync -av usr/lib/i386-linux-gnu/ usr/lib/ rm -rf usr/lib/i386-linux-gnu/ fi rm -f etc/ld.so.conf.d/i686-linux-gnu.conf rmdir etc/ld.so.conf.d/ rmdir etc/ rm -rf usr/share/menu/ rm -rf usr/share/lintian/ } cleanAppDir() { true } ;; *) die "Distro ${Distro} is not supported" ;; esac DEPENDENCIES=1 DOWNLOAD=1 UNPACK=1 CLEANUP=1 BRINGUP=1 CREATE_APPDIR=1 AUTOCOPYLIBS=1 INSTALLPKGS= MainPackage= MainPackageFile= MainPackageExec= MainPackageName= MainPackageVersion= MainPackageURL= MainPackageDeveloper= MainPackageLicenses= Suffix="-$Tag" declare -a mainpkgs=() declare -a pkgs=() declare -a files=() declare -a ignore=() # Recolect list of packages for i in $@; do case $i in --skip-dependencies) DEPENDENCIES=; shift ;; --skip-download) DOWNLOAD=; shift ;; --skip-unpack) UNPACK=; shift ;; --skip-cleanup) CLEANUP=; shift ;; --skip-bringup) BRINGUP=; shift ;; --skip-auto-copy-libs) AUTOCOPYLIBS=; shift ;; --install-pkgs) INSTALLPKGS=1; shift ;; --here) CREATE_APPDIR=; shift ;; -*) ignore+=("${i#*-}") ;; *) if [ -f "$i" ]; then # Argument is a file file="$(readlink -f "$i")" files+=($file) else # Argument is the name of a package mainpkgs+=("$i") pkgs+=("$i") fi ;; esac done # Find dependencies if [ $DEPENDENCIES ]; then for i in ${mainpkgs[@]}; do pkgs+=("$i") for dep in $(find_dependencies "$i"); do pkgs+=("$dep") done done for i in ${files[@]}; do for dep in $(find_dependencies "$i"); do pkgs+=("$dep") done done fi # Download and unpack packages [ "$pkgs" -o "$files" ] || { die "Nothing to do"; } [ "$files" ] && { echo "These files will be included:" for i in $files; do echo " $i" done } if [ "$pkgs" ]; then case "$Distro" in Arch|arch|archlinux) pkgs+=("xdg-utils") ignore+=("libgl" "hicolor-icon-theme" "gtk-update-icon-cache") ;; Ubuntu* | Debian*) pkgs+=("xdg-utils") ignore+=("libgl1-mesa-glx") ;; esac for ign in ${ignore[@]}; do for (( i=0; i<=$(( ${#pkgs[*]} -1 )); i++ )); do if [ "$ign" = "${pkgs[$i]}" ]; then echo "Ignoring $ign ..." unset pkgs[$i] fi done done echo -e ${HILITE}"These packages will be included:"${NORMAL} for i in ${pkgs[@]}; do echo " $i" done fi if [ "$DOWNLOAD" ]; then # Make sure all packages are downloaded for pkg in ${pkgs[@]}; do if [ "$INSTALLPKGS" ]; then install_package "$pkg" || die "Could not install package $pkg" else download_package "$pkg" || die "Could not download package $pkg" fi done else echo "Skipping download" fi # Find the file corresponding with each package for i in ${pkgs[@]}; do pkg=${i#*/} file=$(find_file_for_package $pkg) if [ -f "$file" ]; then files+=" $file" else die "!! Could not find file for package '$pkg'" fi done [ "$files" ] || { die "!! No files found"; } MainPackageFileNames= for i in $files; do MainPackageFileNames+="$(basename "$i");" if [ ! "$MainPackageVersion" ]; then MainPackage=$(getPackageName "$i") MainPackageFile=$(basename "$i") MainPackageName="$MainPackage" MainPackageVersion=$(getPackageVersion "$i") MainPackageURL=$(getPackageURL "$i") MainPackageDeveloper=$(getPackageDeveloper "$i") MainPackageLicenses=$(getPackageLicenses "$i") echo "Assuming main package is $MainPackageFile with version $MainPackageVersion" if [ "$CREATE_APPDIR" ]; then [ "$MainPackage" ] || { die "Could not find package name"; } appDir_path="$PWD/${MainPackage}.AppDir" echo "Using AppDir $appDir_path ..." mkdir -pv "$appDir_path" || exit 1 cd "$appDir_path" || exit 1 fi fi done MainPackageFileNames=${MainPackageFileNames%?} # Trim last semicolon if [ "$UNPACK" ]; then if [ "$INSTALLPKGS" ]; then for i in ${pkgs[@]}; do echo "Copying files of package $i ..." for i in $(package_files "$i"); do if [ -d "$i" ]; then mkdir ./"$i" elif [ -f "$i" ]; then cp -av "$i" ./"$i" fi done done else for i in $files; do echo "Uncompressing $i ..." uncompress_package_file "$i" || die "Could not uncompress package $i" done fi # Force applications to use usr instead of opt if [ -d opt ]; then mkdir -p usr/ mv -v opt/* usr/ rmdir opt fi fixAppDir else echo "Skipping unpack" fi [ "$BRINGUP" ] && { for i in $(find usr/share/applications/ -iname "*.desktop" 2>/dev/null); do PackageName=$(desktopFile_getParameter "$i" "Name") PackageExec=$(desktopFile_getParameter "$i" "Exec") PackageIcon=$(desktopFile_getParameter "$i" "Icon") PackageCategories=$(desktopFile_getParameter "$i" "Categories") echo "Found .desktop file '$PackageName' ($PackageExec)" [ "$MainPackageExec" ] || { echo " Using it as main program" MainPackageName="$PackageName" MainPackageExec=$(basename $PackageExec) IconFile="./$PackageIcon" [ -f "$IconFile" ] || IconFile=usr/share/pixmaps/$PackageIcon [ -f "$IconFile" ] || IconFile=usr/share/icons/$PackageIcon [ -f "$IconFile" ] || IconFile=$(find usr/share/{icons,pixmaps}/ -iname "${PackageIcon}.png" 2>/dev/null | head -n1) [ -f "$IconFile" ] || IconFile=$(find usr/share/{icons,pixmaps}/ -iname "${PackageIcon}.*" 2>/dev/null | head -n1) [ -f "$IconFile" ] || IconFile=$(find usr/share/{icons,pixmaps}/ -iname "${PackageIcon}" 2>/dev/null | head -n1) if [ -f "$IconFile" ]; then echo "Using icon on $IconFile" convert -resize 48x "$IconFile" AppRun.png [ -f "AppRun-0.png" ] && { mv -v AppRun-0.png AppRun.png rm -v AppRun-?.png } optipng AppRun.png >/dev/null 2>/dev/null else echo "! Icon $PackageIcon not found" >&2 echo "usr/share/pixmaps:" >&2 find usr/share/pixmaps >&2 fi } [ -f "./$PackageExec" ] && { echo "Patching absolute paths in ./$PackageExec" "$pg4l_dir/patchAbsolutePaths" "./$PackageExec" } done if [ ! -f AppRun.desktop ]; then [ "$MainPackageVersion" ] || { "! Main package version not found, using _VERSION_" >&2 MainPackageVersion=_VERSION_ } echo "Creating AppRun.desktop from '$MainPackageName $MainPackageVersion' ($i, Exec=$PackageExec)..." cp "$pg4l_dir/data/AppRun.desktop" . desktopFile_setParameter "AppRun.desktop" "Name" "$MainPackageName $MainPackageVersion-r1$Suffix" desktopFile_setParameter "AppRun.desktop" "Categories" "$PackageCategories" desktopFile_setParameter "AppRun.desktop" "X-AppImage-Title" "$MainPackageName" desktopFile_setParameter "AppRun.desktop" "X-AppImage-Version" "$MainPackageVersion" desktopFile_setParameter "AppRun.desktop" "X-AppImage-Release" "1" desktopFile_setParameter "AppRun.desktop" "X-AppImage-URL" "$MainPackageURL" desktopFile_setParameter "AppRun.desktop" "X-AppImage-Developer" "$MainPackageDeveloper" desktopFile_setParameter "AppRun.desktop" "X-AppImage-Licenses" "$MainPackageLicenses" desktopFile_setParameter "AppRun.desktop" "X-AppImage-ID" "$MainPackage" #desktopFile_setParameter "AppRun.desktop" "X-AppImage-SourcePackages" "$MainPackageFile" desktopFile_setParameter "AppRun.desktop" "X-AppImage-SourcePackages" "$MainPackageFileNames" desktopFile_setParameter "AppRun.desktop" "X-AppImage-Tags" "linker,$Tag" fi if [ ! -f AppRun ]; then [ "$MainPackageExec" ] || { echo "! Main package executable not found, using _BINARY_" MainPackageExec="_BINARY_" } echo "Creating AppRun with Exec='${MainPackageExec}'..." cp "$pg4l_dir/data/AppRun_linker" AppRun sed -e"s|_BINARY_|bin/$MainPackageExec|g" AppRun -i chmod +x AppRun fi cp "$pg4l_dir/data/util.sh" . || exit 1 # Actually, patch'em all, for good measure. "$pg4l_dir/patchAbsolutePaths" usr/bin/* if [ $AUTOCOPYLIBS ]; then echo "Copying missing libraries for usr/bin/${MainPackageExec}..." chmod +x usr/lib/*.so* "$pg4l_dir/copyMissingLibraries" "usr/bin/$MainPackageExec" "usr/lib" fi } || { echo "Skipping bringup" } if [ "$CLEANUP" ]; then rubbish="usr/include usr/share/applications usr/share/desktop-directories usr/share/pixmaps usr/share/icons usr/share/man usr/share/info usr/share/doc usr/share/mime usr/share/aclocal usr/lib/pkgconfig usr/lib/*.a" for i in $rubbish; do [ -e "$i" ] && { echo "Deleting $i..." rm -rf "$i" } done cleanAppDir else echo "Skipping cleanup" fi