summaryrefslogtreecommitdiff
path: root/src/toru
diff options
context:
space:
mode:
Diffstat (limited to 'src/toru')
-rwxr-xr-xsrc/toru/toru314
-rwxr-xr-xsrc/toru/toru-info28
-rwxr-xr-xsrc/toru/toru-path48
-rwxr-xr-xsrc/toru/toru-utils76
-rwxr-xr-xsrc/toru/toru-where7
5 files changed, 473 insertions, 0 deletions
diff --git a/src/toru/toru b/src/toru/toru
new file mode 100755
index 0000000..28f0b8a
--- /dev/null
+++ b/src/toru/toru
@@ -0,0 +1,314 @@
+#!/bin/bash
+# Queries the ABS
+# License: GPL3
+
+## TODO
+# * Add license text
+# * Create symlinks from pkgbase to pkgname[@] for easy package finding
+
+## GOALS
+# * Have a searchable database of PKGBUILD metadata
+# * Have an interface for source-only builds
+# * Possibility to hook up ABS dirs besides ABSROOT (low priority)
+# * Tell updates and non available binary packages (working on this)
+
+source $(dirname $(command -v $0))/toru-utils
+
+# Saves contents on a named cache
+# $1 cache name (repo)
+# $2+ contents
+function store_cache {
+ cache=$1; shift
+
+ [ -z "$cache" ] && return 1
+
+ cat $@ > ${TORUPATH}/${cache}.cache
+
+ return $?
+}
+
+# Return cache contents
+# $1 cache name
+read_cache() {
+ cat ${TORUPATH}/${1}.cache 2>/dev/null
+
+ return $?
+}
+
+##
+# usage : get_full_version( $epoch, $pkgver, $pkgrel )
+# return : full version spec, including epoch (if necessary), pkgver, pkgrel
+##
+get_full_version() {
+ if [[ $1 -eq 0 ]]; then
+ # zero epoch case, don't include it in version
+ echo $2-$3
+ else
+ echo $1:$2-$3
+ fi
+}
+
+# Outputs an ordered package-fullpkgver array
+print_package_array() {
+ echo "$@" | tr " " "\n" | sort -u
+}
+
+
+# Gets repo.db contents (unordered)
+# $1 repo
+get_db_contents() {
+ [ ! -r /var/lib/pacman/sync/$1.db ] && return 0
+
+ bsdtar -tf /var/lib/pacman/sync/$1.db | cut -d'/' -f1 | sort -u
+}
+
+# Get the pkgname
+# pkgname from pkgver separator can be either '-' or ' '
+extract_pkgname() {
+ echo "$@" | tr " " "\n" | sed "s/^\(.\+\)[- ][^-]\+-[^-]\+$/\1/"
+}
+
+# Get all the pkgnames from a file
+# pkgname from pkgver separator can be either '-' or ' '
+extract_pkgname_from_file() {
+ sed "s/^\(.\+\)[- ][^-]\+-[^-]\+$/\1/" $1
+}
+
+# Split pkgnames from pkgvers
+split_pkgname_from_pkgver() {
+ sed "s/^\(.\+\)-\([^-]\+-[^-]\+\)$/\1 \2/" $1
+}
+
+# Get the fullpkgver
+# pkgname from pkgver separator can be either '-' or ' '
+extract_fullpkgver() {
+ echo "$@" | tr " " "\n" | sed "s/^.\+[ -]\([^-]\+-[^-]\+\)$/\1/"
+}
+
+# Checks if $1 is a valid repo
+is_repo() {
+ if ! in_array ${1} ${REPOS[@]}; then
+ $quiet || warning "${1} is not a valid repo (check REPOS array at libretools.conf)"
+ return 1
+ fi
+}
+
+# Updates the database by finding all PKGBUILDS
+# Workflow:
+# * Find all PKGBUILDs on the ABS repo specified
+# * Get all packages already on package repos
+# * Compare them
+# Args:
+update() {
+ local update_sync_file=false
+# The PKGBUILDs found
+ local -a pkgbuilds=()
+# The list of pkgname-fullpkgver
+ local -a packages_in_abs=()
+ local -a pkg_updates=()
+ local -a package_paths=()
+
+# Traverse all specified repos
+ for __repo in $@; do
+# Check if the repo is set as such, otherwise skip
+ is_repo ${__repo} || continue
+
+# Fullpath of the repo
+ _repopath=$(readlink -f ${__repo})
+
+# This is the syncfile, stores the last date as content and mtime
+ local lastsyncfile=${TORUPATH}/${__repo}.lastsync
+
+# Find all the PKGBUILDs newer than the last update
+# Update newer, otherwise everything
+ if [[ $force = true || ! -e ${lastsyncfile} ]]; then
+
+ $quiet || warning "Forcing upgrade"
+# Get all PKGBUILDs
+ pkgbuilds=($(find ${_repopath} -maxdepth 2 -type f -name 'PKGBUILD'))
+
+ else
+
+# Only find newer than lastsyncfile and read everything else from cache
+ pkgbuilds=($(find ${_repopath} -maxdepth 2 -type f -name 'PKGBUILD' -newer ${lastsyncfile}))
+ packages_in_abs=($(read_cache ${__repo}))
+
+ $quiet || msg2 "Getting ${#packages_in_abs[@]} packages from cache"
+
+ fi
+
+ package_paths=($(read_cache ${__repo}.paths || true))
+
+# Inform how many PKGBUILDS were found and quit immediately if none
+ $quiet || msg "Found $((${#pkgbuilds[*]}-1)) PKGBUILDs to update"
+
+# Traverse all found PKGBUILDs
+ for _pkgbuild in ${pkgbuilds[@]}; do
+# Update the sync file because there are pkgbuilds to update
+ update_sync_file=true
+
+# Load PKGBUILD's metadata
+ source ${_pkgbuild} || continue
+
+# Guess pkgbase from PKGBUILD's basedir
+ _pkgpath=$(dirname "${_pkgbuild}")
+ _pkgbase=${pkgbase:-${pkgname[0]}}
+
+# We won't need this (all unsets are for memory efficiency)
+ unset build package url md5sums install pkgdesc backup options
+# TODO fill a license list
+ unset license
+# TODO create source tarballs?
+ unset mksource
+# TODO solve dependency tree?
+ unset depends makedepends
+
+ for _pkg in ${pkgname[@]}; do
+# Keep removing unneeded stuff
+ unset package_${_pkg} >/dev/null 2>&1 || true
+# Fill the list of packages to find
+ packages_in_abs+=($_pkg-$(get_full_version ${epoch:-0} $pkgver $pkgrel))
+ package_paths+=($_pkg:$_pkgpath)
+ done # end pkgnames
+
+ unset pkgbase pkgname pkgver pkgrel source epoch
+ done # end pkgbuilds
+
+# Sync! (Only if there was an actual sync)
+ ${update_sync_file} && lastsync ${lastsyncfile}
+
+ if [ "${lastsyncfile}" -nt "${TORUPATH}/${__repo}.paths.cache" ]; then
+ print_package_array "${package_paths[@]}" > $TMPDIR/paths
+ store_cache ${__repo}.paths $TMPDIR/paths
+ fi
+
+# If there isn't an update cache or it's older than the last update, we check
+ if [ "${lastsyncfile}" -nt "${TORUPATH}/${__repo}.updates.cache" ]; then
+
+# Get repo database contents
+ packages_in_sync=($(get_db_contents ${__repo}))
+# Drops arrays into files
+ print_package_array "${packages_in_abs[@]}" > ${TMPDIR}/packages_in_abs
+ print_package_array "${packages_in_sync[@]}" > ${TMPDIR}/packages_in_sync
+
+# Work with files
+ unset packages_in_abs package_in_sync
+
+# Use a different separator for pkgnames and pkgvers
+# so we can join them by pkgname (first field)
+ split_pkgname_from_pkgver ${TMPDIR}/packages_in_abs | sort -k1b,1 > ${TMPDIR}/in_abs
+ split_pkgname_from_pkgver ${TMPDIR}/packages_in_sync | sort -k1b,1 > ${TMPDIR}/in_sync
+
+ $quiet || msg "These packages are available to update"
+# Join both files by pkgname, the end result is:
+# pkgname syncver absver
+ join ${TMPDIR}/in_sync ${TMPDIR}/in_abs | \
+ while read need_line; do
+ _pkg=$(echo "${need_line}" | cut -d' ' -f1)
+ _syncver=$(echo "${need_line}" | cut -d' ' -f2)
+ _absver=$(echo "${need_line}" | cut -d' ' -f3)
+
+# If the versions differ we need an update
+# TODO move this to update query
+ if [ "${_syncver}" != "${_absver}" ]; then
+ $quiet || msg2 "$_pkg update from $_syncver to $_absver"
+ $quiet && echo "$_pkg"
+
+# FIXME this works all right but it's unset once the while ends
+ #pkg_updates+=("$_pkg")
+
+# Fix for the above problem, but it access the file every time instead of
+# puting all packages together once
+ echo $_pkg >> ${TMPDIR}/updates
+
+ fi
+ done # end need_line
+
+ unset _pkg _syncver _absver need_line
+
+# Save the cache
+ store_cache ${__repo} ${TMPDIR}/packages_in_abs
+
+# See above FIXME
+ # print_package_array "${updates[@]}" > ${TMPDIR}/updates
+ if [ -r ${TMPDIR}/updates ]; then
+ store_cache ${__repo}.updates ${TMPDIR}/updates
+ fi
+
+ else
+ $quiet || msg "Reading updates from cache..."
+ read_cache ${__repo}.updates
+ fi
+
+ done # end repos
+}
+
+# Find all the packages that are missing from the repo dbs (aka not built)
+missing() {
+ true
+}
+
+## Finds a PKGBUILD on toru's path cache
+## usage: where_is <pkgname>
+# Look in all caches but pick the first one
+where_is() {
+ local __repo
+ local _path
+ for __repo in ${REPOS[@]}; do
+ _path=$(grep "^${1}:" "${TORUPATH}/${__repo}.paths.cache" 2>/dev/null |
+ cut -d: -f2)
+
+ [ -n "${_path}" ] && break
+ done
+
+ [ -z "$_path" ] && return 1
+
+ echo ${_path}
+}
+
+# TODO: clean usage instructions
+function usage {
+ echo ""
+ echo "$0 [options] repo1 ... repon"
+ echo ""
+ echo "Make a db containing PKGBUILD metadata."
+ echo ""
+ echo "-h : this message"
+# echo "-a : update all repos at once"
+ echo "-u : update repo information"
+ echo "-q : quiet"
+ echo "-f : rebuild the db even if it is updated"
+ echo "-p <pkgname>: return the path for pkgname"
+ echo ""
+ exit 1
+}
+
+## MAIN
+commands=()
+repos=()
+quiet=false
+force=false
+while getopts 'haqfpum' arg; do
+ case $arg in
+ h) usage; exit 0 ;;
+# TODO: Update all repos on $REPOS array
+# a) update_all_repos ;;
+ q) quiet=true ;;
+ f) force=true ;;
+ u) commands+=(update);;
+ p) shift $(( OPTIND - 1 ))
+ where_is "$1" || exit 1;;
+ m) commands+=(missing);;
+ esac
+
+ shift $(( OPTIND - 1 ))
+done
+
+
+TMPDIR=$(mktemp -d)
+
+[[ -z ${TMPDIR} ]] && exit 1
+
+${commands[0]} ${@}
+
+exit $?
diff --git a/src/toru/toru-info b/src/toru/toru-info
new file mode 100755
index 0000000..523f682
--- /dev/null
+++ b/src/toru/toru-info
@@ -0,0 +1,28 @@
+#!/bin/bash
+# Prints info about a given pkgname
+source /etc/libretools.conf
+
+for _pkg in $@; do
+ _pkgbuild="$(toru-where $_pkg)"
+
+ if [ -f "$_pkgbuild/PKGBUILD" ]; then
+ source "$_pkgbuild/PKGBUILD" 2>/dev/null || {
+ warning "Errors on %s" $_pkg
+ continue
+ }
+
+ deps="${depends[@]} ${makedepends[@]} ${checkdepends[@]}"
+ repo="$(basename $(dirname "$_pkgbuild"))"
+
+ unset build package depends makedepends checkdepends optdepends source md5sums
+
+ msg "%s/%s %s-%s" $repo $_pkg $pkgver $pkgrel
+ msg2 "$pkgdesc"
+ msg2 "$url"
+ msg2 "Depends: ${deps}"
+ else
+ warning "%s doesn't exist" $_pkg
+ fi
+
+ unset pkgname pkgver pkgrel pkgdesc url
+done
diff --git a/src/toru/toru-path b/src/toru/toru-path
new file mode 100755
index 0000000..957f49b
--- /dev/null
+++ b/src/toru/toru-path
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+source $(dirname $(command -v $0))/toru-utils
+
+TORUPATH=${T:-${TORUPATH}}
+VERBOSE=${V:-false}
+
+if [ ! -w "$TORUPATH" ]; then
+ error "Toru's path isn't writable. Please check $TORUPATH"
+ exit 1
+fi
+
+LASTSYNCFILE=${TORUPATH}/lastsync.paths
+PATHFILE=${TORUPATH}/paths.tch
+
+if [ ! -e "${PATHFILE}" ]; then
+ tcamgr create "${PATHFILE}"
+fi
+
+# TODO pass other paths via flags
+# ABSROOT has trailing slash
+fullrepos=()
+for (( i = ${#REPOS[@]}-1 ; i >= 0 ; i-- )); do
+ ${VERBOSE} && msg "Processing [%s]" ${REPOS[$i]}
+ fullrepos+=("${ABSROOT}${REPOS[$i]}")
+done
+pkgbuilds=($(get_pkgbuilds ${fullrepos[@]}))
+
+msg "Updating path cache"
+msg2 "${#pkgbuilds[@]} PKGBUILDs to update"
+for _pkgbuild in ${pkgbuilds[@]}; do
+# plain "$_pkgbuild"
+ source ${_pkgbuild} >/dev/null 2>&1 || {
+ error "${_pkgbuild} contains errors, skipping"
+ continue
+ }
+
+ fullpath=$(dirname ${_pkgbuild})
+
+ for _pkg in ${pkgbase} ${pkgname[@]} ${provides[@]}; do
+ $VERBOSE && msg2 "${_pkg} -> ${fullpath}"
+ tcamgr put ${PATHFILE} ${_pkg/[<>=]*} ${fullpath}
+ done
+
+ unset pkgbase pkgname provides
+done
+
+lastsync ${LASTSYNCFILE}
diff --git a/src/toru/toru-utils b/src/toru/toru-utils
new file mode 100755
index 0000000..316e6b8
--- /dev/null
+++ b/src/toru/toru-utils
@@ -0,0 +1,76 @@
+#!/bin/bash
+
+source /etc/abs.conf
+source /etc/libretools.conf
+
+LASTSYNCFILE=${TORUPATH}/lastsync
+FORCE=false
+QUIET=false
+DEBUG=false
+
+# usage : in_array( $needle, $haystack )
+function in_array {
+ [[ $2 ]] || return 1 # Not found
+
+ local needle=$1; shift
+ local item
+
+ for item in "$@"; do
+ [[ ${item#@} = $needle ]] && return 0 # Found
+ done
+
+ return 1 # Not Found
+}
+
+# Stores the lastsync date
+lastsync() {
+ local lastsyncfile
+
+ lastsyncfile=$1
+
+ [ -e ${lastsyncfile} -a ! -w ${lastsyncfile} ] && {
+ error "The sync date can't be saved. ${lastsyncfile} isn't writable."
+ return 1
+ }
+
+ date +%s > ${lastsyncfile}
+ touch ${lastsyncfile}
+}
+
+get_dbs() {
+ local _db
+ for _db in /var/lib/pacman/sync/*.db; do
+ bsdtar tf ${_db} | cut -d'/' -f1 | sort -u
+ done
+}
+
+# repo paths
+get_pkgbuilds() {
+ pkgbuilds=()
+
+ if [[ $FORCE = true || ! -e ${LASTSYNCFILE} ]]; then
+
+ $QUIET || warning "Forcing upgrade"
+# Get all PKGBUILDs
+ extra=""
+ else
+# Only find newer than lastsyncfile and read everything else from cache
+ extra=" -newer ${LASTSYNCFILE}"
+ fi
+
+# Return all PKGBUILDs found
+ find $@ -mindepth 2 -maxdepth 3 -type f -name 'PKGBUILD' ${extra}
+}
+
+# End inmediately but print a useful message
+trap_exit() {
+ error "$@"
+
+ exit 1
+}
+
+# Trap signals from makepkg
+set -E
+trap 'trap_exit "TERM signal caught. Exiting..."' TERM HUP QUIT
+trap 'trap_exit "Aborted by user! Exiting..."' INT
+trap 'trap_exit "An unknown error has occurred. Exiting..."' ERR
diff --git a/src/toru/toru-where b/src/toru/toru-where
new file mode 100755
index 0000000..e9ab29d
--- /dev/null
+++ b/src/toru/toru-where
@@ -0,0 +1,7 @@
+#!/bin/bash
+# Locates a PKGBUILD dir on toru's path cache
+source /etc/libretools.conf
+
+PATHFILE=${TORUPATH}/paths.tch
+
+tcamgr get ${PATHFILE} $1 2>/dev/null || echo ""