aboutsummaryrefslogtreecommitdiff
path: root/bin
diff options
context:
space:
mode:
Diffstat (limited to 'bin')
-rwxr-xr-xbin/InstallPackage-RPM311
-rwxr-xr-xbin/RPMFinder84
2 files changed, 395 insertions, 0 deletions
diff --git a/bin/InstallPackage-RPM b/bin/InstallPackage-RPM
new file mode 100755
index 0000000..20a4517
--- /dev/null
+++ b/bin/InstallPackage-RPM
@@ -0,0 +1,311 @@
+#!/bin/bash
+
+source ScriptFunctions
+Import File
+Import GoboLinux
+Import Log
+Import OptionParser
+
+### Options ###################################################################
+
+scriptDescription="Install RPM packages on GoboLinux."
+scriptCredits="Copyright (C) Lucas C. Villa Real, 2016 - Released under the GNU GPL."
+helpOnNoArguments=yes
+scriptUsage="<file.rpm>"
+scriptExample="LibreOffice_5.2.3_Linux_x86-64_rpm"
+
+Add_Option_Entry "l" "symlink" "If symlinks should be created and wether they should be forced on conflicts." "yes" "yes no force"
+Parse_Options "$@"
+
+### Functions #################################################################
+
+function uncompress_rpm() {
+ local payload_compressor=$(rpminfo --compressor "$rpmfile")
+ local cpiofile=$(basename "$rpmfile").cpio${payload_compressor:+.$payload_compressor}
+
+ Log_Normal "Extracting RPM payload."
+ rpm2cpio < "$rpmfile" > "$cpiofile"
+
+ if [ "$payload_compressor" = "xz" ]
+ then
+ Log_Normal "Decompressing $payload_compressor payload."
+ xz -d "$cpiofile"
+ cpiofile=$(basename "$rpmfile").cpio
+ fi
+
+ Log_Normal "Extracting CPIO archive."
+ cpio -d -i < "$cpiofile"
+ rm -f -- "$cpiofile"
+}
+
+function flatten_rpm() {
+ Log_Normal "Flattening directory structure."
+ if [ -d "./usr" ]
+ then
+ cp -a ./usr/* .
+ rm -rf -- ./usr
+ fi
+ if [ -d "./etc" ]
+ then
+ mkdir -p Resources/Defaults/Settings
+ mv ./etc/* Resources/Defaults/Settings
+ rm -rf -- ./etc
+ fi
+ if [ -d "./opt" ]
+ then
+ mkdir -p Resources/Unmanaged/opt
+ if ls ./opt/* 2> /dev/null | grep -q "bin\|sbin\|lib\|lib64\|libexec\|include"
+ then
+ # 1-level dir: opt/pkgname/{bin,sbin,...}
+ cp -va ./opt/*/* .
+ for pkgdir in $(basename ./opt/*)
+ do
+ ln -s $goboIndex/ Resources/Unmanaged/opt/$pkgdir
+ done
+ realpath ./opt/* | sed "s,$(realpath $PWD),,g" >> Resources/UnmanagedFiles
+ elif ls ./opt/*/* 2> /dev/null | grep -q "bin\|sbin\|lib\|lib64\|libexec\|include"
+ then
+ # 2-level dir: opt/vendorname/pkgname/{bin,sbin,...}
+ # XXX needs testing
+ cp -va ./opt/*/*/* .
+ for vendordir in $(basename ./opt/*)
+ do
+ mkdir -p Resources/Unmanaged/opt/$vendordir
+ for pkgdir in $(basename ./opt/*)
+ do
+ ln -s $goboIndex/ Resources/Unmanaged/opt/$vendordir/$optdir
+ done
+ done
+ realpath ./opt/*/* | sed "s,$(realpath $PWD),,g" >> Resources/UnmanagedFiles
+ fi
+ rm -rf -- ./opt
+ fi
+ if [ -d "./var" ]
+ then
+ mkdir -p Resources/Unmanaged/$goboVariable
+ find ./var | sed "s,./var,$goboVariable,g" >> Resources/UnmanagedFiles
+ mv ./var/* Resources/Unmanaged/$goboVariable
+ rm -rf -- ./var
+ fi
+ rmdir * 2> /dev/null
+}
+
+function populate_resources() {
+ local arch=$(rpminfo --arch "$rpmfile")
+ local description=$(rpminfo --description "$rpmfile")
+
+ Log_Normal "Populating Resources."
+ mkdir -p Resources
+ if [ "$arch" ] && [ "$arch" != "noarch" ]
+ then
+ echo "$arch" > Resources/Architecture
+ fi
+ if [ "$description" ]
+ then
+ cat /dev/null > Resources/Description
+ echo "[Name] $(rpminfo --name $rpmfile)" >> Resources/Description
+ echo "[Summary] $(rpminfo --summary $rpmfile)" >> Resources/Description
+ echo "[License] $(rpminfo --license $rpmfile)" >> Resources/Description
+ echo "[Description] $(rpminfo --description $rpmfile)" >> Resources/Description
+ echo "[Homepage] $(rpminfo --url $rpmfile)" >> Resources/Description
+ fi
+}
+
+function lookup_symbol() {
+ local depname="$1"
+ local testversion="$2"
+ local arch="$3"
+ local symbol="$4"
+ local testarch=$(cat "$goboPrograms/$depname/$testversion/Resources/Architecture" 2> /dev/null)
+
+ if [ "$testarch" ] && [ "$testarch" = "$arch" ]
+ then
+ Log_Verbose "Looking for symbol $symbol on $goboPrograms/$depname/$testversion/$path"
+ if nm "$goboPrograms/$depname/$testversion/$path" 2> /dev/null | grep --max-count=1 -q "$symbol"
+ then
+ Log_Verbose "Match: $depname $testversion"
+ echo "$depname $testversion"
+ return 0
+ fi
+ fi
+ return 1
+}
+
+function take_dependency_from_path() {
+ local originalpath="$1"
+ local path="$(echo $1 | sed 's,/usr,,g')"
+ local symbol="$2"
+ local fullpath="$(readlink -f $path)"
+ local arch=$(rpminfo --arch "$rpmfile")
+ local distro=$(rpminfo --distribution "$rpmfile")
+
+ local depname=
+ local depversion=
+
+ if echo "$fullpath" | grep -q "^${goboPrograms}"
+ then
+ # If given, we search for the presence of @symbol on the given target file.
+ # We iterate over different installations of the same program looking for
+ # that symbol. If none of the installations have it, we fallback to printing
+ # the dependency currently linked on /System/Index.
+ #
+ # Note that when iterating over installed programs we skip those entries whose
+ # Resources/Architecture do not match the output of $(rpminfo --arch).
+
+ depname=$(echo "$fullpath" | cut -d/ -f3)
+ depversion=$(echo "$fullpath" | cut -d/ -f4)
+ if [ "$symbol" ]
+ then
+ for testversion in $(ls $goboPrograms/$depname/ | grep -v "Settings\|Variable\|Current")
+ do
+ lookup_symbol "$depname" "$testversion" "$arch" "$symbol" && return 0
+ done
+ fi
+
+ Log_Verbose "Fallback: $depname $depversion"
+ echo "$depname $depversion"
+ else
+ # We have a path, but we don't have a link to that file under /System/Index.
+ # Our first attempt is to search over the list of installed programs anyhow,
+ # because some programs may not be currently activated.
+
+ for fullpath in $(ls $goboPrograms/*/*/$path 2> /dev/null | grep -v "Current")
+ do
+ depname=$(echo "$fullpath" | cut -d/ -f3)
+ testversion=$(echo "$fullpath" | cut -d/ -f4)
+ [ -z "$depversion" ] && depversion="$testversion"
+ Log_Verbose "Looking for symbol on candidate file $candidate ($depname, $testversion)"
+ lookup_symbol "$depname" "$testversion" "$arch" "$symbol" && return 0
+ done
+
+ # We don't have a match. If we have a file name that satisfies the path but
+ # that doesn't contain the requested symbol, we simply return that path.
+
+ if [ "$depname" ] && [ "$depversion" ]
+ then
+ echo "$depname $depversion"
+ return 0
+ fi
+
+ # We don't have a matching filename under /System/Index nor under /Programs/*/*.
+ # What we do now is to query remote RPM databases to find which package hosts the
+ # dependency file.
+
+ Log_Normal "Searching the remote RPM database for the package hosting $originalpath"
+ depname=$(RPMFinder --path="$originalpath" --arch="$arch" --distro="$distro")
+ if [ "$depname" ]
+ then
+ # TODO: we could now lookup the GoboLinux recipe store to find whether we
+ # have it or not
+ echo "$(GuessProgramCase $depname)"
+ return 0
+ fi
+ fi
+}
+
+function lookup_pkgname() {
+ local dependency="$1"
+ local pkgname=$(echo "$dependency" | cut -d'(' -f1)
+
+ # Do we have a GoboLinux package installed with a matching name?
+ for testname in $(ls $goboPrograms/*)
+ do
+ # Case-insensitive omparison (requires Bash 4)
+ if [ "${testname,,}" = "{$pkgname,,}" ]
+ then
+ echo "$pkgname" && return 0
+ fi
+ done
+
+ # Query the remote RPM database
+ return 1
+}
+
+function is_basic_symbol() {
+ local dependency="$1"
+ echo "$dependency" | grep -q "^rtld(" && return 0
+ return 1
+}
+
+function is_rpmlib_symbol() {
+ local dependency="$1"
+ echo "$dependency" | grep -q "^VersionedDependencies" && return 0
+ echo "$dependency" | grep -q "^PayloadFilesHavePrefix" && return 0
+ echo "$dependency" | grep -q "^CompressedFileNames" && return 0
+ echo "$dependency" | grep -q "^PayloadIs" && return 0
+ return 1
+}
+
+function populate_dependencies_loop() {
+ rpminfo --dependencies "$rpmfile" | while read dependency
+ do
+ if echo "$dependency" | grep -q "^/"
+ then
+ depinfo=$(take_dependency_from_path $dependency "")
+ if [ "$depinfo" ]
+ then echo "$depinfo"
+ else echo "# Unresolved dependency: $dependency"
+ fi
+ elif echo "$dependency" | grep -q "^lib.*.so*"
+ then
+ libname=$(echo "$dependency" | cut -d'(' -f1)
+ wantedsymbol=$(echo "$dependency" | cut -d'(' -f2 | cut -d')' -f1)
+ depinfo="$(take_dependency_from_path $goboLibraries/$libname $wantedsymbol)"
+ if [ "$depinfo" ]
+ then echo "$depinfo"
+ else echo "# Unresolved dependency: $dependency"
+ fi
+ elif is_basic_symbol "$dependency"
+ then
+ Log_Verbose "Skipping basic symbol: $dependency"
+ elif is_rpmlib_symbol "$dependency"
+ then
+ Log_Verbose "Skipping internal symbol: $dependency"
+ else
+ depinfo=$(lookup_pkgname "$dependency")
+ if [ "$depinfo" ]
+ then echo "$depinfo"
+ else echo "# Unresolved dependency: $dependency"
+ fi
+ fi
+ done
+}
+
+function populate_dependencies() {
+ Log_Normal "Processing dependencies."
+ populate_dependencies_loop | sort -n | uniq
+}
+
+### Operation #################################################################
+
+Is_Writable "${goboPrograms}" || Verify_Superuser
+
+symlink="$(Entry symlink)"
+rpmfile="$(readlink -f $(Arg 1))"
+programname=$(rpminfo --name "$rpmfile")
+programversion=$(printf "%s_%s" $(rpminfo --version "$rpmfile") $(rpminfo --release "$rpmfile"))
+
+PrepareProgram -t "$programname" "$programversion"
+
+# Update program name (PrepareProgram may have changed its case)
+programname=$(ls $goboPrograms/ | grep -i "^${programname}$")
+target="$goboPrograms/$programname/$programversion"
+
+# Installation pipeline
+Quiet pushd "$target" || Die "Could not enter $target"
+uncompress_rpm
+flatten_rpm
+populate_resources
+populate_dependencies
+Quiet popd
+
+# Symlinking
+if [ "$symlink" = "no" ]
+then
+ Log_Normal "Done."
+ exit 0
+fi
+
+[ -d "$target/Resources/Defaults/Settings" ] && UpdateSettings "$programname" "$programversion"
+SymlinkProgram "$programname" "$programversion"
+Log_Normal "Done."
diff --git a/bin/RPMFinder b/bin/RPMFinder
new file mode 100755
index 0000000..1797174
--- /dev/null
+++ b/bin/RPMFinder
@@ -0,0 +1,84 @@
+#!/usr/bin/env python
+
+# Searches over the network to find out which RPM package distributes
+# a given file.
+#
+# Written by Lucas C. Villa Real <lucasvr@gobolinux.org>
+# Released under the GNU GPL version 2 or above.
+
+import os
+import sys
+import argparse
+import subprocess
+from HTMLParser import HTMLParser
+
+
+class RPMFind_Parser(HTMLParser):
+ '''
+ Parses the HTML data output by rpmfind.net
+ '''
+ def __init__(self):
+ self.tags = []
+ self.candidates = []
+ HTMLParser.__init__(self)
+
+ def handle_starttag(self, tag, attrs):
+ self.tags.append(tag)
+
+ def handle_endtag(self, tag):
+ self.tags.pop()
+
+ def handle_data(self, data):
+ if len(self.tags) and self.tags[-1] == "a" and data.find(".rpm") >= 0:
+ self.candidates.append(data)
+
+ def get_pkgname(self):
+ if len(self.candidates) == 0:
+ return ""
+ name = os.path.commonprefix(self.candidates)
+ if name.endswith("-"):
+ name = name[:-1]
+ return name
+
+
+class RPMFinder:
+ def find(self, path, arch, distro):
+ '''
+ Searches rpmfind.net for a given file. Arch and distro can
+ be provided to reduce the search scope. Returns the package
+ name on success or an empty string if no matches were found.
+ '''
+ self.path = path
+ self.arch = arch
+ self.distro = distro
+ return self.__search_rpmfind_net()
+
+ def __search_rpmfind_net(self):
+ path = self.path.replace("/", "%2F")
+ arch = self.arch
+ baseuri = "http://rpmfind.net/linux/rpm2html/search.php"
+ query = "?query={0}&submit=Search+...&system=&arch={1}".format(path, arch)
+ html = subprocess.check_output(["wget", "--quiet", "{0}{1}".format(baseuri, query), "-O", "-"])
+
+ htmlparser = RPMFind_Parser()
+ htmlparser.feed(html)
+ return htmlparser.get_pkgname()
+
+
+def main():
+ argparser = argparse.ArgumentParser(argument_default="")
+ argparser.add_argument("--path", type=str, help="File name to search for in the remote RPM databases")
+ argparser.add_argument("--arch", type=str, help="Architecture (optional)")
+ argparser.add_argument("--distro", type=str, help="Distribution (optional)")
+ args = argparser.parse_args()
+
+ if len(args.path) == 0:
+ argparser.print_help()
+ sys.exit(1)
+
+ pkgname = RPMFinder().find(args.path, args.arch, args.distro)
+ if len(pkgname):
+ print pkgname
+
+if __name__ == "__main__":
+ main()