summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile2
-rw-r--r--src/abslibre-tools/Makefile1
-rwxr-xr-xsrc/abslibre-tools/createworkdir64
-rwxr-xr-xsrc/abslibre-tools/diff-unfree89
-rwxr-xr-xsrc/abslibre-tools/libreaddiff90
-rwxr-xr-xsrc/abslibre-tools/librerelease212
-rwxr-xr-xsrc/abslibre-tools/librestage112
-rwxr-xr-xsrc/aur163
-rw-r--r--src/chroot-tools/.gitignore5
-rw-r--r--src/chroot-tools/Makefile44
-rwxr-xr-xsrc/chroot-tools/chcleanup102
-rw-r--r--src/chroot-tools/chroot.conf13
-rwxr-xr-xsrc/chroot-tools/distcc-tool244
-rw-r--r--src/chroot-tools/hooks-chcleanup.sh16
-rw-r--r--src/chroot-tools/hooks-check.sh39
-rw-r--r--src/chroot-tools/hooks-distcc.sh87
-rwxr-xr-xsrc/chroot-tools/librechroot325
-rwxr-xr-xsrc/chroot-tools/libremakepkg249
-rw-r--r--src/chroot-tools/makechrootpkg.sh.patch303
-rw-r--r--src/devtools/.gitignore3
-rw-r--r--src/devtools/Makefile8
-rw-r--r--src/fullpkg/Makefile1
-rwxr-xr-xsrc/fullpkg/fullpkg34
-rwxr-xr-xsrc/fullpkg/fullpkg-build193
-rwxr-xr-xsrc/fullpkg/fullpkg-find197
-rwxr-xr-xsrc/is_built46
-rw-r--r--src/lib/.gitignore3
-rw-r--r--src/lib/Makefile30
-rw-r--r--src/lib/common.sh.bottom1
-rw-r--r--src/lib/common.sh.top26
-rw-r--r--src/lib/conf.sh190
-rwxr-xr-xsrc/lib/libreblacklist148
-rwxr-xr-xsrc/lib/librelib79
-rwxr-xr-xsrc/lib/libremessages131
-rw-r--r--src/librefetch/Makefile1
-rwxr-xr-xsrc/librefetch/librefetch331
-rw-r--r--src/librefetch/librefetch.8.ronn162
-rw-r--r--src/librefetch/librefetch.conf2
-rw-r--r--src/librefetch/librefetch.conf.5.ronn36
-rw-r--r--src/libregit/Makefile1
-rwxr-xr-xsrc/libregit/libregit74
-rw-r--r--src/libretools.conf83
-rw-r--r--src/mips64el-tools/Makefile1
-rwxr-xr-xsrc/mips64el-tools/add-mips64el6
-rwxr-xr-xsrc/mips64el-tools/librebasebuilder84
-rwxr-xr-xsrc/mips64el-tools/mips-add8
-rwxr-xr-xsrc/mips64el-tools/mipsrelease61
-rwxr-xr-xsrc/pkgbuild-check-licenses126
-rwxr-xr-xsrc/pkgbuild-check-nonfree121
-rw-r--r--src/toru/Makefile1
-rwxr-xr-xsrc/toru/toru301
-rwxr-xr-xsrc/toru/toru-info25
-rwxr-xr-xsrc/toru/toru-path48
-rwxr-xr-xsrc/toru/toru-utils64
-rwxr-xr-xsrc/toru/toru-where9
-rwxr-xr-xsrc/treepkg224
56 files changed, 5019 insertions, 0 deletions
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..63f7782
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,2 @@
+pkgconfdir=$(sysconfdir)
+include ../common.mk
diff --git a/src/abslibre-tools/Makefile b/src/abslibre-tools/Makefile
new file mode 100644
index 0000000..2c76089
--- /dev/null
+++ b/src/abslibre-tools/Makefile
@@ -0,0 +1 @@
+include ../../common.mk
diff --git a/src/abslibre-tools/createworkdir b/src/abslibre-tools/createworkdir
new file mode 100755
index 0000000..99214ab
--- /dev/null
+++ b/src/abslibre-tools/createworkdir
@@ -0,0 +1,64 @@
+#!/usr/bin/env bash
+# CreateWorkDir
+# Creates a dir structure for working with Parabola packages
+
+# Copyright 2010 Nicolás Reynolds
+
+# ---------- GNU General Public License 3 ----------
+
+# This file is part of Parabola.
+
+# Parabola is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# Parabola is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with Parabola. If not, see <http://www.gnu.org/licenses/>.
+
+. libremessages
+. $(librelib conf.sh)
+load_files libretools
+check_vars libretools WORKDIR REPOS ABSLIBREGIT || exit 1
+
+[[ ! -d ${WORKDIR} ]] && { # Create the WORKDIR
+
+ msg "Creating WORKDIR on ${WORKDIR}"
+ mkdir -p ${WORKDIR} ||{
+ error "Could not create ${WORKDIR}"; exit 1
+ }
+
+}
+
+for _repo in "${REPOS[@]}"; do # Create the staging dirs
+
+ [[ ! -d ${WORKDIR}/staging/${_repo} ]] && {
+ mkdir -p ${WORKDIR}/staging/${_repo} || {
+ error "Can't create ${WORKDIR}/staging/${_repo}"
+ exit 1
+ }
+ }
+
+done
+
+[[ ! -d ${WORKDIR}/abslibre/.git ]] && {
+ msg "Cloning into ABSLibre"
+ CMD="git clone ${ABSLIBREGIT} ${WORKDIR}/abslibre"
+ ${CMD} || {
+ error "Could not clone ABSLibre"
+ plain "Try running this command:"
+ echo
+ plain "${CMD}"
+ exit 1
+ }
+}
+
+msg "Finished, your packaging dir tree looks like this now:"
+ls --color=always ${WORKDIR}/*/*
+
+exit 0
diff --git a/src/abslibre-tools/diff-unfree b/src/abslibre-tools/diff-unfree
new file mode 100755
index 0000000..07f2ca2
--- /dev/null
+++ b/src/abslibre-tools/diff-unfree
@@ -0,0 +1,89 @@
+#!/usr/bin/env bash
+# This script will help you diff a *-libre PKGBUILD against the unfree one
+# to check for updates.
+# Copyright 2010 Nicolás Reynolds
+
+# ---------- GNU General Public License 3 ----------
+
+# This file is part of Parabola.
+
+# Parabola is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# Parabola is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with Parabola. If not, see <http://www.gnu.org/licenses/>.
+
+. libremessages
+. $(librelib conf.sh)
+load_files libretools
+check_vars libretools DIFFTOOL || exit 1
+
+cmd=${0##*/}
+
+usage() {
+ echo "Usage: $cmd [community|packages] [unfree-package] [repo]"
+ echo "Usage: $cmd --help"
+ echo "Helps you diff build scripts from ABSLibre against (Unfree) ABS."
+ echo ""
+ echo "Package name and repo will we guessed if you don't specify them."
+}
+
+main() {
+ if [[ "$1" == "--help" ]]; then
+ usage
+ exit 0
+ fi
+
+ local package_guess=${PWD##*/}
+ local repo=${1:-$(basename ${PWD%/*})}
+ local package=${2:-${package_guess%-libre}}
+ local trunk=${3:-trunk}
+
+ svnrepo="packages"
+ case $repo in
+ community*) svnrepo="community";;
+ multilib*) svnrepo="community";;
+ *) :;;
+ esac
+
+ if [[ ! -r PKGBUILD ]]; then
+ error "This is not a build dir."
+ exit 1
+ fi
+
+
+ tmp_dir="$(mktemp --tmpdir -d ${package}.XXXXXX)"
+ if [[ ! -d "${tmp_dir}" ]]; then
+ error "Can't create temp dir"
+ exit 1
+ fi
+ unfree_dir="${tmp_dir}/${svnrepo}/${package}/${trunk}"
+
+ pushd "${tmp_dir}" &>/dev/null
+
+ msg "Getting diff from $repo/$package..."
+
+ svn checkout --depth=empty svn://svn.archlinux.org/$svnrepo &>/dev/null
+
+ cd ${svnrepo}
+ svn update ${package}
+
+ # Back to start dir
+ popd &>/dev/null
+
+ msg "Diffing files"
+
+ for _file in ${unfree_dir}/*; do
+ msg2 "$(basename "${_file}")"
+ ${DIFFTOOL} "$PWD/$(basename "${_file}")" "${_file}"
+ done
+}
+
+main "$@"
diff --git a/src/abslibre-tools/libreaddiff b/src/abslibre-tools/libreaddiff
new file mode 100755
index 0000000..03d0ad0
--- /dev/null
+++ b/src/abslibre-tools/libreaddiff
@@ -0,0 +1,90 @@
+#!/usr/bin/env bash
+set -e
+# -*- coding: utf-8 -*-
+# Copyright (C) 2011, 2012 Michał Masłowski <mtjm@mtjm.eu>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+. $(librelib conf.sh)
+load_files libretools
+check_vars libretools WORKDIR
+
+for arg in "$@" ; do
+ case "$arg" in
+ -h|--h|--he|--hel|--help|-\?)
+ echo 'Usage: libreaddiff repo [arch]
+
+This script outputs a diff of package names and versions in repo
+between pacman'\''s sync db and abslibre checkout.' >&2
+ exit 0
+ ;;
+ esac
+done
+
+# The repo to find missing packages in.
+repo=$1
+# The arch to check in Arch repos, other will have all arches checked.
+arch=${2:-mips64el}
+# A Python tuple of repos which don't have arch=any packages.
+archrepos='("core", "extra", "community")'
+
+diff -U0 \
+ <( (
+ cd /var/lib/pacman/sync
+ for f in $repo.db ; do
+ tar xOf $f | python -c 'import sys
+arch = None
+name = None
+version = None
+it = iter(sys.stdin)
+try:
+ while True:
+ line = next(it)
+ if line == "%ARCH%\n":
+ arch = next(it)
+ if arch == "'"$arch"'\n" or "'$repo'" not in '"$archrepos"':
+ print("%s-%s" % (name.strip(), version.strip()))
+ if line == "%NAME%\n":
+ name = next(it)
+ if line == "%VERSION%\n":
+ version = next(it)
+except StopIteration:
+ pass
+'
+ done
+ ) | sort ) \
+ <( (
+ cd "${WORKDIR}/abslibre"
+ # Needed to not include pkgnames specific to other arches.
+ CARCH=$arch
+ for f in $repo/* ; do
+ load_PKGBUILD "$f/PKGBUILD" || continue
+ is_here=false
+ for arc in ${arch[@]} ; do
+ if [ "$arc" = "any" -o "$arc" = "$CARCH" ] ; then
+ is_here=true
+ break
+ fi
+ done
+ if [ "$is_here" = "true" ] ; then
+ for name in ${pkgname[@]} ; do
+ if [ -z "$epoch" ] ; then
+ echo $name-$pkgver-$pkgrel
+ else
+ echo $name-$epoch:$pkgver-$pkgrel
+ fi
+ done
+ fi
+ done
+ ) | sort ) | sed -rn 's/^[+-][^+-].+$/&/p'
diff --git a/src/abslibre-tools/librerelease b/src/abslibre-tools/librerelease
new file mode 100755
index 0000000..5913670
--- /dev/null
+++ b/src/abslibre-tools/librerelease
@@ -0,0 +1,212 @@
+#!/usr/bin/env bash
+# Librerelease
+# Uploads packages into [staging]
+
+# Copyright 2010 Nicolás Reynolds
+# Copyright 2013 Luke Shumaker
+# For just the create_signature() function:
+# Copyright (c) 2006-2013 Pacman Development Team <pacman-dev@archlinux.org>
+# Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
+# Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
+# Copyright (c) 2006 by Miklos Vajna <vmiklos@frugalware.org>
+# Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu>
+# Copyright (c) 2006 by Alex Smith <alex@alex-smith.me.uk>
+# Copyright (c) 2006 by Andras Voroskoi <voroskoi@frugalware.org>
+# Copyright (c) 2006-2013 Pacman Development Team <pacman-dev@archlinux.org>
+# Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
+# Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
+# Copyright (c) 2006 by Miklos Vajna <vmiklos@frugalware.org>
+# Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu>
+# Copyright (c) 2006 by Alex Smith <alex@alex-smith.me.uk>
+# Copyright (c) 2006 by Andras Voroskoi <voroskoi@frugalware.org>
+#
+# This file is part of Parabola.
+#
+# Parabola is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Parabola is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Parabola. If not, see <http://www.gnu.org/licenses/>.
+
+. libremessages
+. $(librelib conf.sh)
+
+function usage {
+ print "Usage: %s [OPTIONS]" "${0##*/}"
+ echo
+ print 'This script uploads packages on $WORKDIR/stagging'
+ print "to parabola server."
+ echo
+ print "Options:"
+ print ' -c Clean packages on $WORKDIR/staging'
+ print " -l Only list packages but not upload them"
+ print " -n Dry-run; don't actually do anything"
+ print " -h Show this message"
+}
+
+function list_packages {
+ find "$WORKDIR/staging/" -mindepth 1 -type d -not -empty -printf '%f\n' | sort |
+ while read -r repo; do
+ msg2 "$repo"
+ find "${WORKDIR}/staging/${repo}" -type f -printf "%f\n" | sort
+ done
+}
+
+# This function is taken almost verbatim from makepkg
+create_signature() {
+ local ret=0
+ local filename="$1"
+ msg "$(gettext "Signing package...")"
+
+ local SIGNWITHKEY=""
+ if [[ -n $GPGKEY ]]; then
+ SIGNWITHKEY="-u ${GPGKEY}"
+ fi
+ # The signature will be generated directly in ascii-friendly format
+ gpg --detach-sign --use-agent ${SIGNWITHKEY} "$filename" &>/dev/null || ret=$?
+
+
+ if (( ! ret )); then
+ msg2 "$(gettext "Created signature file %s.")" "$filename.sig"
+ else
+ error "$(gettext "Failed to sign package file.")"
+ return $ret
+ fi
+}
+
+function sign_packages {
+ if [ -z "${GPG_AGENT_INFO}" ]; then
+ warning "It's better to use gpg-agent to sign packages in batches"
+ fi
+
+ for package in $(find "${WORKDIR}/staging/" -type f -iname '*.pkg.tar.?z'); do
+ if [ -f "${package}.sig" ]; then
+ msg2 "Package signature found, verifying..."
+
+ # Verify that the signature is correct, else remove for re-signing
+ if ! gpg --quiet --verify "${package}.sig" >/dev/null 2>&1; then
+ error "Failed! Re-signing..."
+ rm -f "${package}.sig"
+ fi
+ fi
+
+ if ! [ -f "${package}.sig" ]; then
+ create_signature "$package" || return 2
+ fi
+ done
+}
+
+# Remove everything that's not a package or a signature
+function clean_non_packages {
+ find $WORKDIR/staging/ -type f \
+ \! -iname "*.pkg.tar.?z" -a \! -iname "*.pkg.tar.?z.sig" \
+ -delete
+}
+
+# Clean everything if not on dry-run mode
+function clean {
+ if [[ -n "${dryrun}" ]]; then
+ :
+ else
+ msg "Removing files from local staging directory"
+ # use '-exec rm' instead of '-delete' to be verbose
+ find "${WORKDIR}/staging" -type f -exec rm -fv {} +
+ fi
+}
+
+function main {
+ if [ -w / ]; then
+ error "This program should be run as regular user"
+ return 1
+ fi
+
+ # Parse options
+ local dryrun=""
+ local mode="release_packages"
+ while getopts 'clnh' arg; do
+ case $arg in
+ c) mode=clean ;;
+ l) mode=list_packages ;;
+ n) dryrun="--dry-run" ;;
+ h) mode=usage ;;
+ *) usage >/dev/stderr; return 1 ;;
+ esac
+ done
+ shift $(($OPTIND - 1))
+ if [[ $# != 0 ]]; then
+ usage >/dev/stderr
+ return 1
+ fi
+
+ if [[ $mode == usage ]]; then
+ usage
+ return 0
+ fi
+
+ load_files makepkg
+ check_vars makepkg GPGKEY
+ load_files libretools
+ check_vars libretools WORKDIR REPODEST || return 1
+ # The following variables are actually optional
+ #check_vars libretools HOOKPRERELEASE HOOKPOSTRELEASE || return 1
+
+ lock 10 "${WORKDIR}/staging.lock" 'Waiting for an exclusive lock on the staging directory'
+ "$mode"
+}
+
+function release_packages {
+ if [[ -n $HOOKPRERELEASE ]]; then
+ msg "Running HOOKPRERELEASE..."
+ bash -c "${HOOKPRERELEASE}"
+ fi
+
+ clean_non_packages
+ sign_packages || return 1
+
+ # Make the permissions of the packages 644 otherwise the user will get access
+ # denied error when they try to download (rsync --no-perms doesn't seem to
+ # work).
+ find ${WORKDIR}/staging -type f -exec chmod 644 {} \;
+ find ${WORKDIR}/staging -type d -exec chmod 755 {} \;
+
+ msg "%s to upload" $(du -h -d 0 ${WORKDIR}/staging | tr "\t" " " | cut -d" " -f1)
+ msg "Uploading packages..."
+ if ! rsync --recursive \
+ ${dryrun} \
+ --no-group \
+ --no-perms \
+ --copy-links \
+ --hard-links \
+ --partial \
+ --prune-empty-dirs \
+ --human-readable \
+ --progress \
+ -e "ssh " \
+ ${WORKDIR}/staging \
+ ${REPODEST}/
+ then
+ error "Sync failed, try again"
+ return 1
+ fi
+
+ clean
+
+ msg "Running db-update on repos"
+ ssh ${REPODEST%%:*} dbscripts/db-update
+
+ if [[ -n $HOOKPOSTRELEASE ]]; then
+ msg "Running HOOKPOSTRELEASE..."
+ bash -c "${HOOKPOSTRELEASE}"
+ fi
+
+ return 0
+}
+
+main "$@"
diff --git a/src/abslibre-tools/librestage b/src/abslibre-tools/librestage
new file mode 100755
index 0000000..57846fc
--- /dev/null
+++ b/src/abslibre-tools/librestage
@@ -0,0 +1,112 @@
+#!/usr/bin/env bash
+# LibreStage
+# Prepares packages for upload
+
+# Copyright 2010-2011 Nicolás Reynolds
+# Copyright 2013 Luke Shumaker
+#
+# This file is part of Parabola.
+#
+# Parabola is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Parabola is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Parabola. If not, see <http://www.gnu.org/licenses/>.
+
+. libremessages
+. $(librelib conf.sh)
+
+cmd=${0##*/}
+usage() {
+ print "Usage: %s REPO [REPO2 REPO3...]" "$cmd"
+ print "Stages the package(s) build by ./PKGBUILD for upload."
+ echo
+ print "The package(s) are staged for the named repositories."
+ print "It is in general a bad idea to stage a package on multiple"
+ print "repositories, but it supported by this tool."
+}
+
+main() {
+ if [[ -w / ]]; then
+ error "This program should be run as regular user"
+ return 1
+ fi
+
+ # Parse options, set up
+ while getopts 'h' arg; do
+ case $arg in
+ h) usage; return 0;;
+ *) usage >/dev/stderr; return 1;;
+ esac
+ done
+ repos=("$@")
+ if [[ ${#repos[@]} -eq 0 ]]; then
+ usage >>/dev/stderr
+ return 1;
+ fi
+
+ [[ ! -e ./PKGBUILD ]] && {
+ error "PKGBUILD not found"
+ return 1
+ }
+
+ # Load configuration
+ load_files libretools
+ check_vars libretools WORKDIR ARCHES || return 1
+ load_files makepkg # for PKGDEST, which is optional
+
+ # Load the PKGBUILD
+ load_PKGBUILD
+
+ # Now for the main routine.
+ staged=false
+ slock 10 "${WORKDIR}/staging.lock" 'Waiting for a shared lock on the staging directory'
+ for CARCH in "${ARCHES[@]}" any; do
+ for _pkgname in "${pkgname[@]}"; do
+ pkgfile=${_pkgname}-$(get_full_version $_pkgname)-${CARCH}${PKGEXT}
+ pkgpath="$(find . "${PKGDEST:-.}" -maxdepth 1 -type f -name "$pkgfile"|sed 1q)"
+
+ if [[ ! -f "${pkgpath}" ]]; then
+ continue
+ else
+ pkgpath="$(readlink -f "$pkgpath")"
+ fi
+
+ msg "Found ${pkgfile}"
+
+ canonical="" # is empty for the first iteration, set after that
+ for repo in "${repos[@]}"; do
+ mkdir -p "${WORKDIR}/staging/${repo}"
+ if [[ -z $canonical ]]; then
+ canonical="${WORKDIR}/staging/${repo}/${pkgfile}"
+ cmd=(cp "$pkgpath" "$canonical")
+ else
+ cmd=(ln "$canonical" "${WORKDIR}/staging/${repo}/${pkgfile}")
+ fi
+ if "${cmd[@]}"; then
+ msg2 "%s staged on [%s]" "$_pkgname" "$repo"
+ staged=true
+ else
+ error "Can't put %s on [%s]" "$_pkgname" "$repo"
+ return 1
+ fi
+ done
+ done
+ done
+
+ if $staged ; then
+ return 0
+ else
+ error "No package was staged"
+ return 1
+ fi
+}
+
+main "$@"
diff --git a/src/aur b/src/aur
new file mode 100755
index 0000000..08de67e
--- /dev/null
+++ b/src/aur
@@ -0,0 +1,163 @@
+#!/usr/bin/env bash
+# Copyright 2010 Joshua Ismael
+# Copyright 2010 Nicolás Reynolds
+# Copyright 2013 Luke Shumaker
+#
+# This file is part of Parabola.
+#
+# Parabola is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# Parabola is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Parabola. If not, see <http://www.gnu.org/licenses/>.
+
+. libremessages
+
+cmd=${0##*/}
+usage() {
+ echo "Usage: $cmd [-h] pkgname-from-aur1 [pkgname-from-aur2 ...]"
+ echo
+ echo "This script will download packages from AUR to the current"
+ echo "directory and check their license for nonfree issues. This does"
+ echo "not mean that they are free; they may be incorrectly labeled, or"
+ echo "have other freedom issues. It's a tool to help Parabola"
+ echo "packagers, not to help users install things directly from AUR."
+}
+
+main() {
+ while getopts 'h' arg; do
+ case $arg in
+ h) usage; return 0;;
+ *) usage >&2; return 1;;
+ esac
+ done
+ if [[ $# -lt 1 ]]; then
+ usage >&2
+ return 1
+ fi
+
+ . $(librelib conf.sh)
+ load_files libretools
+ check_vars libretools DIFFTOOL || exit 1
+
+ local startdir="$(pwd)"
+ local missing_deps=()
+ local ret=0
+ local pkg
+ local copy_new
+ local copy_old
+ for pkg in "$@"; do
+ pkg="${pkg%%[<>=]*}" # remove the version
+ msg "Processing package: %s" "$pkg"
+ copy_new="$startdir/$pkg"
+ copy_old=
+
+ if [[ -f "${copy_new}/PKGBUILD" ]]; then
+ warning "%s already exists, will compare with new version." "$pkg"
+
+ # Store our copy of the PKGBUILD dir
+ copy_old=$copy_new
+ copy_new="$(mktemp --tmpdir -d aur-${pkg}.new.XXXX)/$pkg"
+ cd "${copy_new%/*}"
+ fi
+
+ msg2 "Downloading"
+ local url="https://aur.archlinux.org/packages/${pkg:0:2}/$pkg/$pkg.tar.gz"
+ set -o pipefail
+ if ! wget -O- -q "$url" | bsdtar xf -; then
+ ret=$(($ret|2))
+ error "Couldn't get %s" "$pkg"
+ continue
+ fi
+ set +o pipefail
+
+ if [[ -n $copy_old ]]; then
+ msg2 "Diffing files"
+ cd "$copy_new"
+
+ # Diff all files with our difftool
+ local diffed=false
+ for file in *; do
+ if ! cmp -s "${copy_old}/${file}" "${copy_new}/${file}" ; then
+ warning "%s != %s" "${copy_old}/${file}" "${copy_new}/${file}"
+ diffed=true
+ "${DIFFTOOL}" "${copy_old}/${file}" "${copy_new}/${file}"
+ fi
+ done
+ if $diffed; then
+ read -p "Press enter to continue."
+ fi
+
+ # Go back to our copy to continue working
+ cd "$copy_old"
+ rm -rf -- "${copy_new%/*}"
+ else
+ cd "$copy_new"
+ fi
+
+ load_PKGBUILD
+
+ ################################################################
+
+ pkgbuild-check-nonfree -c
+ case $? in
+ 0) :;;
+ 15) warning "This PKGBUILD links to known unfree packages";;
+ *) warning "pkgbuild-check-nonfree failed to run";;
+ esac
+
+ ################################################################
+
+ local s=0
+ pkgbuild-check-licenses || s=$?
+ for i in 1 2 4; do
+ if [[ $i -eq $(($s & $i)) ]]; then
+ case $i in
+ 1) warning "pkgbuild-check-licenses encountered an error";;
+ 2) warning "This PKGBUILD has an uncommon license";;
+ 4) warning "This PKGBUILD has a known nonfree license";;
+ esac
+ fi
+ done
+ unset s
+
+ ################################################################
+
+ local _deps=(
+ # depends
+ "${depends[@]}" "${makedepends[@]}" "${checkdepends[@]}"
+ # mksource depends
+ "${mkdepends[@]}"
+ )
+ local _dep
+ msg2 "Checking dependencies"
+ for _dep in "${_deps[@]}"; do
+ _dep=${_dep/[<>=]*/}
+ if ! is_built $_dep; then
+ if ! pacman -Sddp "$_dep" &>/dev/null ; then
+ plain "%s: will be downloaded from AUR" "$_dep"
+ missing_deps+=($_dep)
+ fi
+ else
+ plain "%s: is on repos" "$_dep"
+ fi
+ done
+ cd "$startdir"
+ done
+
+ if [[ ${#missing_deps[*]} -gt 0 ]]; then
+ msg "Retrieving missing deps: %s" "${missing_deps[*]}"
+ "$0" "${missing_deps[@]}"
+ ret=$(($ret|$?))
+ fi
+ return $ret;
+}
+
+main "$@"
diff --git a/src/chroot-tools/.gitignore b/src/chroot-tools/.gitignore
new file mode 100644
index 0000000..80e1000
--- /dev/null
+++ b/src/chroot-tools/.gitignore
@@ -0,0 +1,5 @@
+makechrootpkg.sh*
+!makechrootpkg.sh.patch
+
+arch-nspawn*
+mkarchroot*
diff --git a/src/chroot-tools/Makefile b/src/chroot-tools/Makefile
new file mode 100644
index 0000000..0540636
--- /dev/null
+++ b/src/chroot-tools/Makefile
@@ -0,0 +1,44 @@
+# These files are coming from devtools
+copy_files = makechrootpkg.sh.in mkarchroot.in arch-nspawn.in
+# These are programs that we will use internally, but shouldn't be in PATH
+libexecs = mkarchroot arch-nspawn distcc-tool chcleanup
+no-progs = $(libexecs)
+# These are the shell libraries we will use
+libs = makechrootpkg.sh $(wildcard hooks-*.sh)
+
+pkglibexecdir = $(libexecdir)/libretools/chroot
+clean_files = makechrootpkg.sh.ugly* *~
+include ../../common.mk
+
+# Usage: $(call indent,FILENAME)
+# Command to auto-indent a file.
+indent = emacs --batch $1 \
+ --eval '(setq sh-basic-offset 8)' \
+ --eval '(indent-region (point-min) (point-max) nil)' \
+ -f save-buffer &>/dev/null
+
+# makechrootpkg.sh is special, we patch it and do fancy stuff
+# The flow is:
+# $(devtoolsdir)/*.in -> *.sh.in + *.sh.patch -> *.sh.ugly -> *.sh
+
+makechrootpkg.sh.in: %.sh.in: $(devtoolsdir)/%.in
+ cp $< $@
+makechrootpkg.sh.ugly: %.ugly: %.in %.patch Makefile
+ cp $*.in $@
+ @echo 'PATCH $@ $*.patch'; patch $@ $*.patch || { rm -f -- '$@'; false; }
+makechrootpkg.sh: %: %.ugly Makefile
+ @echo 'EDIT < $< > $@'; $(edit) <'$<' >'$@' || { rm -f -- '$@'; false; }
+ @echo 'INDENT $@'; $(call indent,$@) || { rm -f -- '$@'; false; }
+
+mkarchroot: mkarchroot.in Makefile
+ @echo '< $< M4_EDIT | SED > $@'
+ @<'$<' $(edit) | sed 's|arch-nspawn|$$(librelib chroot/&)|' >'$@' || { rm -f -- '$@'; false; }
+ @echo 'CHMOD $<'; chmod 755 "$@" || { rm -f -- '$@'; false; }
+
+archroot: %: %.in Makefile
+ @echo "GEN $@"
+ @$(edit) <"$<" >"$@" || { rm -f -- '$@'; false; }
+ @chmod 755 "$@" || { rm -f -- '$@'; false; }
+
+distcc-tool.pot: distcc-tool
+ xgettext --omit-header -i --from-code=UTF-8 -L shell --keyword={error,errusage} -o $@ $<
diff --git a/src/chroot-tools/chcleanup b/src/chroot-tools/chcleanup
new file mode 100755
index 0000000..a43065b
--- /dev/null
+++ b/src/chroot-tools/chcleanup
@@ -0,0 +1,102 @@
+#!/usr/bin/env bash
+set -eE
+# (c) Nicolás Reynolds <fauno@parabola.nu>
+# Released under GPLv3
+#
+# Performs chroot cleanup smartly, it only removes the unneeded packages or
+# leaves you with a cleansystem
+#
+# See: HOOKPREBUILD
+
+DRYRUN=${DRYRUN:-false}
+
+################################################################################
+# Define these here to avoid having dependencies on outside files
+
+if type gettext &>/dev/null; then
+ _() { gettext "$@"; }
+else
+ _() { echo "$@"; }
+fi
+
+plain() {
+ local mesg="$(_ "$1")"; shift
+ printf "${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2
+}
+
+msg() {
+ local mesg="$(_ "$1")"; shift
+ printf "${GREEN}==>${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2
+}
+
+msg2() {
+ local mesg="$(_ "$1")"; shift
+ printf "${BLUE} ->${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2
+}
+
+warning() {
+ local mesg="$(_ "$1")"; shift
+ printf "${YELLOW}==> $(gettext "WARNING:")${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2
+}
+
+error() {
+ local mesg="$(_ "$1")"; shift
+ printf "${RED}==> $(gettext "ERROR:")${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2
+}
+
+################################################################################
+
+if [[ ! -f /.arch-chroot ]] && ! ${DRYRUN}; then
+ error "(chcleanup): Must be run inside of a chroot"
+ exit 1
+fi
+
+source /etc/libretools.d/chroot.conf
+# If we're running makepkg
+if [ -f PKGBUILD ]; then
+ export CARCH="$(. /etc/makepkg.conf; printf '%s' "$CARCH")"
+ source PKGBUILD
+ CHROOTEXTRAPKG+=("${depends[@]}"
+ "${makedepends[@]}"
+ "${checkdepends[@]}")
+fi
+
+msg "Cleaning chroot..."
+msg2 "Fetching updated package lists..."
+pacman -Sy || {
+ warning "There was an error updating package lists, ignoring."
+}
+
+# Setup the temporary directory
+TEMPDIR="$(mktemp --tmpdir -d $(basename $0).XXXXX)"
+trap "rm -rf '$TEMPDIR'" EXIT
+
+cp -a /var/lib/pacman/sync "${TEMPDIR}/"
+pkglist="${TEMPDIR}"/pkglist.txt
+
+# Get the full list of packages needed by dependencies, including the base system
+msg2 "Creating a full list of packages..."
+pacman -b "${TEMPDIR}" \
+ -Sp --print-format "%n" base-devel "${CHROOTEXTRAPKG[@]}" >"$pkglist" || {
+ ret=$?
+ error "Could not create a full list of packages, exiting."
+ plain "This is likely caused by a dependency that could not be found."
+ exit $ret
+}
+
+# Diff installed packages against a clean chroot then remove leftovers
+packages=($(comm -23 <(pacman -Qq | sort -u) \
+ <(sort -u "${pkglist}")))
+
+if [[ ${#packages[@]} = 0 ]]; then
+ msg2 "No packages to remove"
+else
+ msg2 "Removing %d packages" ${#packages[@]}
+
+ if ${DRYRUN}; then
+ echo "${packages[*]}"
+ else
+ # Only remove leftovers, -Rcs removes too much
+ pacman --noconfirm -Rn "${packages[@]}"
+ fi
+fi
diff --git a/src/chroot-tools/chroot.conf b/src/chroot-tools/chroot.conf
new file mode 100644
index 0000000..3b3c445
--- /dev/null
+++ b/src/chroot-tools/chroot.conf
@@ -0,0 +1,13 @@
+# The full path to the chroot is
+# $CHROOTDIR/$CHROOT/$COPY
+# where $COPY is set at runtime.
+# See `librechroot help` for details.
+CHROOTDIR=/var/lib/archbuild
+CHROOT=default
+
+# Extra packages to have installed on the chroot.
+# This is in addition to CHROOTPKG=(base-devel)
+CHROOTEXTRAPKG=()
+#CHROOTEXTRAPKG+=(distcc-nozeroconf socat) # for BUILDENV+=(distcc)
+#CHROOTEXTRAPKG+=(ccache) # for BUILDENV+=(ccache)
+#CHROOTEXTRAPKG+=(libretools) # for running libremakepkg inside the chroot
diff --git a/src/chroot-tools/distcc-tool b/src/chroot-tools/distcc-tool
new file mode 100755
index 0000000..7633029
--- /dev/null
+++ b/src/chroot-tools/distcc-tool
@@ -0,0 +1,244 @@
+#!/usr/bin/env bash
+# -*- tab-width: 4; sh-basic-offset: 4 -*-
+# distcc-tool
+
+# Copyright 2013 Luke Shumaker
+#
+# This file is part of Parabola.
+#
+# Parabola is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Parabola is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Parabola. If not, see <http://www.gnu.org/licenses/>.
+
+# This program has very few dependencies:
+# - bash: I don't know what version, I use fairly modern features
+# - socat
+# - cat: any version
+# - rm: any version
+# - sed: any version
+# On Parabola, this means the packages:
+# bash, coreutils, sed, socat
+
+if ! type gettext &>/dev/null; then
+ gettext() { echo "$@"; }
+fi
+
+panic() {
+ echo "$(gettext 'panic: malformed call to internal function')" >&2
+ exit 1
+}
+
+error() {
+ mesg="$(gettext "$1")"; shift
+ printf "$(gettext 'ERROR:') $mesg\n" "$@" >&2
+ exit 1
+}
+
+print() {
+ local mesg=$1
+ shift
+ printf -- "$(gettext "$mesg")\n" "$@"
+}
+
+usage() {
+ print "Usage: $0 COMMAND [COMMAND-ARGS]"
+ print "Tool for using distcc within a networkless chroot"
+ echo
+ print "Commands:"
+ print ' help print this message'
+ print ' odaemon CHROOTPATH daemon to run outside of the chroot'
+ print ' idaemon DISTCC_HOSTS daemon to run inside of the chroot'
+ print ' rewrite DISTCC_HOSTS prints a rewritten version of DISTCC_HOSTS'
+ print ' client HOST PORT connects stdio to TCP:$HOST:$PORT'
+ print 'Commands: for internal use'
+ print ' server counterpart to client; spawned by odaemon'
+}
+
+errusage() {
+ if [[ $# -gt 0 ]]; then
+ fmt="$(gettext "$1")"; shift
+ printf "$(gettext 'ERROR:') $fmt\n" "$@" >&2
+ fi
+ usage >&2
+ exit 1
+}
+
+main() {
+ local cmd=$1
+ shift
+ case "$cmd" in
+ help)
+ [[ $# -eq 0 ]] || errusage '%s: invalid number of arguments' "$cmd"
+ usage;;
+ odaemon|idaemon|rewrite)
+ [[ $# -eq 1 ]] || errusage '%s: invalid number of arguments' "$cmd"
+ $cmd "$@";;
+ client)
+ [[ $# -eq 2 ]] || errusage '%s: invalid number of arguments' "$cmd"
+ $cmd "$@";;
+ server)
+ [[ $# -eq 0 ]] || errusage '%s: invalid number of arguments' "$cmd"
+ $cmd "$@";;
+ *) errusage 'unknown subcommand: %s' "$cmd";;
+ esac
+}
+
+################################################################################
+# DISTCC_HOSTS parser #
+################################################################################
+
+# usage: parse_DISTCC_HOSTS true|false DISTCC_HOSTS
+# parses DISTCC_HOSTS and:
+# $1==true : It sets up port forwarding for inside the choot, sleep forever
+# $1==false: Prints a modified version of DISTCC_HOSTS that uses the forwarded
+# ports that were set up when $1==true.
+parse_DISTCC_HOSTS() {
+ { [[ $# -eq 2 ]] && { [[ $1 == true ]] || [[ $1 == false ]]; }; } || panic
+ local forward_ports=$1
+ local DISTCC_HOSTS=$2
+
+ local pids=() # child pids
+ local newhosts=()
+ local newport=8000 # next port to be used for port forwarding
+
+ # This is based on the grammar specified in distcc(1)
+ local HOSTSPEC
+ for HOSTSPEC in $(sed 's/#.*//' <<<"$DISTCC_HOSTS"); do
+ case "$HOSTSPEC" in
+ # LOCAL_HOST
+ localhost|localhost/*|--localslots=*|--localslots_cpp=*)
+ # "localhost" runs commands directly, not talking to distccd at
+ # localhost, use an IP or real hostname for that.
+ # So, just pass these through.
+ newhosts+=("$HOSTSPEC")
+ ;;
+ # SSH_HOST
+ *@*)
+ # SSH_HOST doesn't allow custom port numbers, and even if it
+ # did, ssh would complain about MITM. Instead, we'll count on
+ # ssh ProxyCommand being configured to used `client`.
+ newhosts+=("$HOSTSPEC")
+ ;;
+ # GLOBAL_OPTION
+ --*)
+ # pass these through
+ newhosts+=("$HOSTSPEC")
+ ;;
+ # ZEROCONF
+ +zeroconf)
+ error "%s does not support the +zeroconf option" "$0"
+ exit 1
+ ;;
+ # TCP_HOST or OLDSTYLE_TCP_HOST
+ *)
+ declare HOSTID= PORT= LIMIT= OPTIONS=
+ if [[ $HOSTSPEC =~ ^([^:/]+)(:([0-9]+))?(/([0-9]+))?(,.*)?$ ]]; then
+ # TCP_HOST
+ HOSTID=${BASH_REMATCH[1]}
+ PORT=${BASH_REMATCH[3]}
+ LIMIT=${BASH_REMATCH[5]}
+ OPTIONS=${BASH_REMATCH[6]}
+ elif [[ $HOSTSPEC =~ ^([^:/]+)(/([0-9]+))?(:([0-9]+))?(,.*)?$ ]]; then
+ # OLDSTYLE_TCP_HOST
+ HOSTID=${BASH_REMATCH[1]}
+ LIMIT=${BASH_REMATCH[3]}
+ PORT=${BASH_REMATCH[5]}
+ OPTIONS=${BASH_REMATCH[6]}
+ else
+ error "Could not parse HOSTSPEC: %s" "$HOSTSPEC"
+ fi
+
+ # set up port forwaring
+ if $forward_ports; then
+ socat TCP-LISTEN:${newport},fork SYSTEM:"$0 client $HOSTID ${PORT:-3632}" &
+ pids+=($!)
+ fi
+
+ # add the forwarded port
+ local newhost="127.0.0.1:$newport"
+ [[ -z $LIMIT ]] || newhost+="/$LIMIT"
+ [[ -z $OPTIONS ]] || newhost+="$OPTIONS"
+ newhosts+=("$newhost")
+ : $((newport++))
+ ;;
+ esac
+ done
+ if $forward_ports; then
+ if [[ -z "${pids[*]}" ]]; then
+ # listen on port 8000, but immediatly close, just so that we are
+ # listening on something
+ socat TCP-LISTEN:${newport},fork SYSTEM:true &
+ pids+=($!)
+ fi
+ trap "kill -- ${pids[*]}" EXIT
+ wait "${pids[@]}"
+ else
+ printf '%s\n' "${newhosts[*]}"
+ fi
+}
+
+################################################################################
+# Port forwarding primitives #
+################################################################################
+
+# Usage: server
+# Reads "host port" from the first line of stdin, then connects stdio to the
+# specified TCP socket.
+server() {
+ [[ $# -eq 0 ]] || panic
+ while read -r host port; do
+ socat STDIO TCP:"$host:$port"
+ break
+ done
+}
+
+# Usage: client HOST PORT
+# For usage inside of a chroot. It talks through the UNIX-domain socket to an
+# instance of `server` outside, in order to connect stdio to the specified TCP
+# socket.
+client() {
+ [[ $# -eq 2 ]] || panic
+ local file=/socket
+ { printf '%s\n' "$*"; cat; } | socat UNIX-CONNECT:"$file" STDIO
+}
+
+################################################################################
+# High-level routines #
+################################################################################
+
+# Usage: odaemon CHROOTPATH
+# Listens on "$CHROOTPATH/socket" and spawns a `server` for each new connection.
+odaemon() {
+ [[ $# -eq 1 ]] || panic
+ local chrootpath=$1
+
+ umask 111
+ socat UNIX-LISTEN:"$chrootpath/socket",fork SYSTEM:"$0 server" &
+ trap "kill -- $!; rm -f '$chrootpath/socket'" EXIT
+ wait
+}
+
+# Usage: idaemon DISTCC_HOSTS
+# Sets things up inside of the chroot to forward distcc hosts out.
+idaemon() {
+ [[ $# -eq 1 ]] || panic
+ parse_DISTCC_HOSTS true "$1"
+}
+
+# Usage: rewrite DISTCC_HOSTS
+# Prints a modified version of DISTCC_HOSTS for inside the chroot.
+rewrite() {
+ [[ $# -eq 1 ]] || panic
+ parse_DISTCC_HOSTS false "$1"
+}
+
+main "$@"
diff --git a/src/chroot-tools/hooks-chcleanup.sh b/src/chroot-tools/hooks-chcleanup.sh
new file mode 100644
index 0000000..09e6dd9
--- /dev/null
+++ b/src/chroot-tools/hooks-chcleanup.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+set -euE
+
+hooks_pre_build+=("clean_chroot")
+
+clean_chroot() (
+ set +x
+ local copydir=$1
+ if $INCHROOT; then
+ cd /build
+ sudo -u nobody "$(librelib chroot/chcleanup)"
+ else
+ librechroot -l "$copydir" clean-pkgs
+ fi
+ r=$?; echo clean_chroot returning $r; return $r
+)
diff --git a/src/chroot-tools/hooks-check.sh b/src/chroot-tools/hooks-check.sh
new file mode 100644
index 0000000..e8120b8
--- /dev/null
+++ b/src/chroot-tools/hooks-check.sh
@@ -0,0 +1,39 @@
+#!/usr/bin/env bash
+set -euE
+
+hook_check_pkgbuild+=("check_pkgbuild_dependencies")
+check_pkgbuild_dependencies() {
+ local s=0
+ sudo -EH -u "$LIBREUSER" pkgbuild-check-nonfree -f || s=$?
+ case $s in
+ 0) :;;
+ 15) error "This PKGBUILD links to known unfree packages"; return 1;;
+ *) warning "pkgbuild-check-nonfree failed to run";;
+ esac
+}
+
+hook_check_pkgbuild+=("check_pkgbuild_license")
+check_pkgbuild_license() {
+ local s=0
+ sudo -EH -u "$LIBREUSER" pkgbuild-check-licenses -f || s=$?
+ for i in 1 2 4; do
+ if [[ $i -eq $(($s & $i)) ]]; then
+ case $i in
+ 1) warning "pkgbuild-check-licenses encountered an error";;
+ 2) warning "This PKGBUILD has an uncommon license";;
+ 4) error "This PKGBUILD has a known nonfree license"; ret=1;;
+ esac
+ fi
+ done
+}
+
+#hook_check_pkgbuild+=("check_pkgbuild_namcap")
+check_pkgbuild_namcap() {
+ sudo -EH -u "$LIBREUSER" namcap PKGBUILD
+}
+
+#hook_check_pkg+=("check_pkg")
+check_pkg() {
+ # TODO
+ :
+}
diff --git a/src/chroot-tools/hooks-distcc.sh b/src/chroot-tools/hooks-distcc.sh
new file mode 100644
index 0000000..9e42242
--- /dev/null
+++ b/src/chroot-tools/hooks-distcc.sh
@@ -0,0 +1,87 @@
+#!/usr/bin/env bash
+set -euE
+
+hook_pre_build+=("distcc_start")
+hook_post_build+=("distcc_stop")
+
+_distcc_check() {
+ local copydir=$1
+ local home=$2
+
+ local files=(
+ "$copydir/bin/distcc-tool"
+ "$copydir/run/distcc-tool.pid"
+ "$home/.makepkg.conf"
+ "$home/.ssh/config"
+ )
+
+ local file_err=false
+ for files in "${files[@]}"; do
+ if [[ -f $file ]]; then
+ file_err=true
+ error "Auto-generated file already exists, remove it: %s" "$file"
+ fi
+ done
+ if $file_err; then
+ exit 1
+ fi
+}
+
+distcc_start() {
+ local copydir=$1
+
+ # Because /{,usr/}{,s}bin are all symlinked together for
+ # fileystem 2013.05-2 and up, I can take shortcuts when checking for
+ # existance of programs.
+ if $NONET && [[ -f "$copydir/bin/socat" && -f "$copydir/bin/distcc" ]]; then
+ local home
+ if $INCHROOT; then
+ home=$LIBREHOME
+ else
+ home="$copydir/build"
+ fi
+
+ _distcc_check
+
+ local _distcc_tool=$(librelib chroot/distcc-tool)
+ install -m755 "$_distcc_tool" "$copydir/bin/distcc-tool"
+
+ mkdir -p "$home/.ssh"
+
+ printf '%s\n' \
+ '/bin/distcc-tool idaemon "$DISTCC_HOSTS" &' \
+ 'DISTCC_HOSTS="$(/bin/distcc-tool rewrite "$DISTCC_HOSTS")"' \
+ > "$home/.makepkg.conf"
+
+ printf '%s\n' \
+ 'Host *' \
+ ' ProxyCommand /bin/distcc-tool client %h %p' \
+ > "$home/.ssh/config"
+
+ "$_distcc_tool" odaemon "$copydir" &
+ echo $! > "$copydir/run/distcc-tool.pid"
+ fi
+}
+
+distcc_stop() {
+ local copydir=$1
+
+ local home
+ if $INCHROOT; then
+ home=$LIBREHOME
+ else
+ home="$copydir/build"
+ fi
+
+ if [[ -f "$copydir/run/distcc-tool.pid" ]]; then
+
+ odaemon=$(cat "$copydir/distcc-tool.pid")
+ kill -- "$odaemon"
+
+ rm -f -- \
+ "$home/.makepkg.conf" \
+ "$home/.ssh/config" \
+ "$copydir/bin/distcc-tool" \
+ "$copydir/run/distcc-tool.pid"
+ fi
+}
diff --git a/src/chroot-tools/librechroot b/src/chroot-tools/librechroot
new file mode 100755
index 0000000..0b3ad43
--- /dev/null
+++ b/src/chroot-tools/librechroot
@@ -0,0 +1,325 @@
+#!/usr/bin/env bash
+set -euE
+# librechroot
+
+# Copyright 2010 Nicolás Reynolds
+# Copyright 2011 Joshua Haase
+# Copyright 2012-2013 Luke Shumaker
+#
+# This file is part of Parabola.
+#
+# Parabola is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Parabola is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Parabola. If not, see <http://www.gnu.org/licenses/>.
+
+# HACKING: if a command is added or removed, it must be changed in 3 places:
+# - the usage() text
+# - the commands=() array
+# - the case statement in main()
+
+. $(librelib conf)
+load_files chroot
+
+. libremessages
+
+shopt -s nullglob
+umask 0022
+
+readonly _arch_nspawn=$(librelib chroot/arch-nspawn)
+readonly _mkarchroot=$(librelib chroot/mkarchroot)
+readonly _makechrootpkg=$(librelib chroot/makechrootpkg.sh)
+
+# Because the makechrootpkg.sh library functions don't work with -euE
+_makechrootpkg() (
+ set +euE
+ . "$_makechrootpkg"
+ "$@"
+)
+
+# Usage: make_empty_repo $copydir
+make_empty_repo() {
+ local copydir=$1
+ mkdir -p "${copydir}/repo"
+ bsdtar -czf "${copydir}/repo/repo.db.tar.gz" -T /dev/null
+ ln -s "repo.db.tar.gz" "${copydir}/repo/repo.db"
+}
+
+# Usage: chroot_add_to_local_repo $copydir $pkgfiles...
+chroot_add_to_local_repo() {
+ local copydir=$1; shift
+ mkdir -p "$copydir/repo"
+ local pkgfile
+ for pkgfile in "$@"; do
+ cp "$pkgfile" "$copydir/repo"
+ pushd "$copydir/repo" >/dev/null
+ repo-add repo.db.tar.gz "${pkgfile##*/}"
+ popd >/dev/null
+ done
+}
+
+usage() {
+ eval "$(calculate_directories)"
+ print "Usage: %s [OPTIONS] COMMAND [ARGS...]" "${0##*/}"
+ print 'Interacts with an archroot (arch chroot).'
+ echo
+ prose 'This is configured with `chroot.conf`, either in
+ `/etc/libretools.d/`, or `$XDG_CONFIG_HOME/libretools/`.
+ The variables you may set are $CHROOTDIR, $CHROOT, and
+ $CHROOTEXTRAPKG.'
+ echo
+ prose 'There may be multiple chroots; they are stored in $CHROOTDIR.'
+ echo
+ prose 'Each chroot is named; the default is configured with $CHROOT.'
+ echo
+ prose 'Each named chroot has a master clean copy (named `root`), and any
+ number of other named copies; the copy used by default is the
+ current username (or $SUDO_USER, or `copy` if root).'
+ echo
+ prose 'The full path to the chroot copy is "$CHROOTDIR/$CHROOT/$COPY",
+ unless the copy name is manually specified as an absolute path,
+ in which case, that path is used.'
+ echo
+ prose 'The current settings for the above varibles are:'
+ printf ' CHROOTDIR : %s\n' "${CHROOTDIR:-$(_ 'ERROR: NO SETTING')}"
+ printf ' CHROOT : %s\n' "${CHROOT:-$(_ 'ERROR: NO SETTING')}"
+ printf ' COPY : %s\n' "$COPY"
+ printf ' rootdir : %s\n' "${rootdir:-$(_ 'ERROR')}"
+ printf ' copydir : %s\n' "${copydir:-$(_ 'ERROR')}"
+ echo
+ prose 'If the chroot, or copy does not exist, it will be created
+ automatically. A chroot by default contains the packages in the
+ group "base-devel", and any packages named in $CHROOTEXTRAPKG.
+ Unless the `-C` or `-M` flags are used, the configuration files
+ that this program installs are the stock versions supplied in the
+ packages, not the versions from your host system. Other tools
+ (such as libremakepkg) may alter the configuration.'
+ echo
+ prose 'This command will make the following configuration changes in the
+ chroot:'
+ bullet 'overwrite `/etc/libretools.d/chroot.conf`'
+ bullet 'overwrite `/etc/pacman.d/mirrorlist`'
+ bullet 'set `CacheDir` in `/etc/pacman.conf`'
+ prose 'If a new `pacman.conf` is inserted with the `-C` flag, the change
+ is made after the file is copied in; the `-C` flag doesn'\''t
+ stop the change from being effective.'
+ echo
+ prose 'Creating a copy, deleting a copy, or syncing a copy can be fairly
+ slow; but are very fast if $CHROOTDIR is on a btrfs partition.'
+ echo
+ print 'Options:'
+ flag "-n <$(_ CHROOT)>" 'Name of the chroot to use'
+ flag "-l <$(_ COPY)>" 'Name of, or absolute path to, the copy to use'
+ flag '-N' 'Disable networking in the chroot'
+ flag "-C <$(_ FILE)>" 'Copy this file to `$copydir/etc/pacman.conf`'
+ flag "-M <$(_ FILE)>" 'Copy this file to `$copydir/etc/makepkg.conf`'
+ flag "-w <$(_ 'PATH[:PATH]')>" 'Bind mount a file or directory, read/write'
+ flag "-r <$(_ 'PATH[:PATH]')>" 'Bind mount a file or directory, read-only'
+ echo
+ print 'Commands:'
+ print ' Create/copy/delete:'
+ flag 'noop|make' 'Do not do anything, but still creates the chroot
+ copy if it does not exist'
+ flag 'sync' 'Sync the copy with the clean (`root`) copy'
+ flag 'delete' 'Delete the chroot copy'
+ print ' Dealing with packages:'
+ flag "install-file $(_ FILES...)" 'Like `pacman -U FILES...`'
+ flag "install-name $(_ NAMES...)" 'Like `pacman -S NAMES...`'
+ flag 'update' 'Like `pacman -Syu`'
+ flag 'clean-pkgs' 'Remove all packages from the chroot copy that
+ are not in base-devel, $CHROOTEXTRAPKG, or named
+ as a dependency in the file `/build/PKGBUILD` in
+ the chroot copy'
+ print ' Other:'
+ flag "run $(_ CMD...)" 'Run CMD in the chroot copy'
+ flag 'enter' 'Enter an interactive shell in the chroot copy'
+ flag 'clean-repo' 'Clean /repo in the chroot copy'
+ flag 'help' 'Show this message'
+}
+readonly commands=(
+ noop make sync delete
+ install-file install-name update clean-pkgs
+ run enter clean-repo help
+)
+
+# set $rootdir and $copydir; blank them on error
+calculate_directories() {
+ # Don't assume that CHROOTDIR or CHROOT are set,
+ # but assume that COPY is set.
+ local rootdir copydir
+
+ if [[ -n ${CHROOTDIR:-} ]] && [[ -n ${CHROOT:-} ]]; then
+ rootdir="${CHROOTDIR}/${CHROOT}/root"
+ else
+ rootdir=''
+ fi
+
+ if [[ ${COPY:0:1} = / ]]; then
+ copydir=$COPY
+ elif [[ -n ${CHROOTDIR:-} ]] && [[ -n ${CHROOT:-} ]]; then
+ copydir="${CHROOTDIR}/${CHROOT}/${COPY}"
+ else
+ copydir=''
+ fi
+
+ declare -p rootdir
+ declare -p copydir
+}
+
+arch_nspawn_flags=()
+sysd_nspawn_flags=()
+arch-nspawn() {
+ local copydir=$1; shift
+ set +u # if an array is empty, it counts as unbound
+ "$_arch_nspawn" "${arch_nspawn_flags[@]}" "$copydir" "${sysd_nspawn_flags[@]}" -- "$@"
+ set -u
+}
+
+# Globals: $CHROOTDIR, $CHROOT, $COPY, $rootdir and $copydir
+main() {
+ COPY=$LIBREUSER
+ [[ $COPY != root ]] || COPY=copy
+
+ local mode=enter
+ while getopts 'n:l:NC:M:w:r:' opt; do
+ case $opt in
+ n) CHROOT=$OPTARG;;
+ l) COPY=$OPTARG;;
+ N) sysd_nspawn_flags+=(--private-network);;
+ C|M) arch_nspawn_flags+=(-$opt "$OPTARG");;
+ w) sysd_nspawn_flags+=("--bind=$OPTARG");;
+ r) sysd_nspawn_flags+=("--bind-ro=$OPTARG");;
+ *) usage >/dev/stderr; return 1;;
+ esac
+ done
+ shift $(($OPTIND - 1))
+ if [[ $# -lt 1 ]]; then
+ error "Must specify a command"
+ usage >/dev/stderr
+ return 1
+ fi
+ mode=$1
+ if ! in_array "$mode" "${commands[@]}"; then
+ error "Unrecognized command: %s" "$mode"
+ usage >/dev/stderr
+ return 1
+ fi
+ shift
+
+ if [[ $mode == help ]]; then
+ usage
+ return 0
+ fi
+
+ check_vars chroot CHROOTDIR CHROOT
+ eval "$(calculate_directories)"
+
+ readonly LIBREUSER LIBREHOME
+ readonly CHROOTDIR CHROOT COPY
+ readonly rootdir copydir
+ readonly mode
+
+ ########################################################################
+
+ if (( EUID )); then
+ error "This program must be run as root."
+ return 1
+ fi
+
+ umask 0022
+
+ # Keep this lock as long as we are running
+ # Note that '9' is the same FD number as in mkarchroot et al.
+ lock 9 "$copydir.lock" \
+ "Waiting for existing lock on chroot copy to be released: [%s]" "$COPY"
+
+ if [[ ! -d $rootdir ]]; then
+ msg "Creating 'root' copy for chroot [%s]" "$CHROOT"
+ set +u # if an array is empty, it counts as unbound
+ "$_mkarchroot" "${arch_nspawn_flags[@]}" "$rootdir" base-devel
+ set -u
+ make_empty_repo "$rootdir"
+ fi
+
+ if [[ ! -d $copydir ]] || [[ $mode == sync ]]; then
+ msg "Syncing copy [%s] with root copy" "$COPY"
+ _makechrootpkg sync_chroot "$CHROOTDIR/$CHROOT" "$COPY"
+ fi
+
+ mkdir -p "$copydir/etc/libretools.d"
+ {
+ if [[ -n ${CHROOTEXTRAPKG[*]:-} ]]; then
+ declare -p CHROOTEXTRAPKG | sed -r 's/declare( -.)* //'
+ else
+ printf 'CHROOTEXTRAPKG=()\n'
+ fi
+ } > "$copydir"/etc/libretools.d/chroot.conf
+
+ if [[ $mode != delete ]]; then
+ # "touch" the chroot first
+ # this will
+ # - overwrite \`/etc/pacman.d/mirrorlist'"
+ # - set \`CacheDir' in \`/etc/pacman.conf'"
+ # - apply -C or -M flags
+ arch-nspawn "$copydir" true
+ arch_nspawn_flags=() # XXX dirty hack, don't apply -C or -M again
+ fi
+
+ ########################################################################
+
+ case "$mode" in
+ # Creat/copy/delete
+ noop|make|sync) :;;
+ delete)
+ if [[ -d $copydir ]]; then
+ _makechrootpkg delete_chroot "$copydir" "$COPY"
+ fi
+ ;;
+
+ # Dealing with packages
+ install-file)
+ _makechrootpkg install_packages "$copydir" "$@"
+ chroot_add_to_local_repo "$copydir" "$@"
+ ;;
+ install-name)
+ arch-nspawn "$copydir" pacman -Sy "$@"
+ ;;
+ update)
+ arch-nspawn "$copydir" pacman -Syu --noconfirm
+ ;;
+ clean-pkgs)
+ trap "rm -f '$copydir'/bin/chcleanup '$copydir'/chrootexec" EXIT
+ install -m755 "$(librelib chroot/chcleanup)" "$copydir/bin/chcleanup"
+ printf '%s\n' \
+ '#!/bin/bash' \
+ 'mkdir -p /build' \
+ 'cd /build' \
+ '/bin/chcleanup' \
+ > "$copydir/chrootexec"
+ chmod 755 "$copydir/chrootexec"
+ arch-nspawn "$copydir" /chrootexec
+ ;;
+
+ # Other
+ run)
+ arch-nspawn "$copydir" "$@"
+ ;;
+ enter)
+ arch-nspawn "$copydir" bash
+ ;;
+ clean-repo)
+ rm -rf "${copydir}"/repo/*
+ make_empty_repo "$copydir"
+ ;;
+ esac
+}
+
+main "$@"
diff --git a/src/chroot-tools/libremakepkg b/src/chroot-tools/libremakepkg
new file mode 100755
index 0000000..a59315b
--- /dev/null
+++ b/src/chroot-tools/libremakepkg
@@ -0,0 +1,249 @@
+#!/usr/bin/env bash
+set -euE
+# libremakepkg
+
+# Copyright 2010-2011 Nicolás Reynolds
+# Copyright 2011 Joshua Ismael Haase Hernández
+# Copyright 2012-2013 Luke Shumaker
+#
+# This file is part of Parabola.
+#
+# Parabola is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Parabola is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Parabola. If not, see <http://www.gnu.org/licenses/>.
+
+. $(librelib conf)
+. $(librelib messages)
+. $(librelib chroot/makechrootpkg.sh)
+
+shopt -s nullglob
+umask 0022
+
+# Global variables:
+readonly INCHROOT=$([[ -f /.arch-chroot ]] && echo true || echo false)
+NONET=true # can be changed with the -N flag
+# {SRC,LOG,PKG}DEST set at runtime by makepkg.conf
+# MAKEFLAGS, PACKAGER set at runtime by makepkg.conf
+# LIBREUSER, LIBREHOME are set by conf.sh
+
+# Hooks ########################################################################
+
+hook_pre_build=(:)
+hook_post_build=(:)
+hook_check_pkgbuild=(:)
+hook_check_pkg=(:)
+. $(librelib chroot/hooks-chcleanup.sh)
+. $(librelib chroot/hooks-check.sh)
+. $(librelib chroot/hooks-distcc.sh)
+
+# Boring/mundane functions #####################################################
+
+# Usage: exit_copy $copydir $src_owner
+# End immediately, but copy log files out
+exit_copy() {
+ local copydir=$1
+ local src_owner=$2
+ if ! $INCHROOT; then
+ msg "Copying log and package files out of the chroot..."
+ move_products "$copydir" "$src_owner"
+ fi
+}
+
+# Usage; run_hook $hookname $args...
+run_hook() {
+ local hookname=$1; shift
+ local hookvar="hook_${hookname}[@]"
+ local fails=()
+ msg "Running hook: %s" "$hookname"
+ for hook in "${!hookvar}"; do
+ msg2 'hook: %s' "$hook"
+ "$hook" "$@" || { error "result: %s" $?; fails+=("$hook"); }
+ done
+ if [[ ${#fails[@]} -gt 0 ]]; then
+ error "Failure(s) in %s: %s" "$hookname" "${fails[*]}"
+ return 1
+ fi
+ return 0
+}
+
+# Usage: add_to_local_repo $copydir $pkgfiles...
+add_to_local_repo() {
+ local copydir=$1; shift
+ mkdir -p "$copydir/repo"
+ local pkgfile
+ for pkgfile in "$@"; do
+ cp "$pkgfile" "$copydir/repo"
+ pushd "$copydir/repo" >/dev/null
+ repo-add repo.db.tar.gz "${pkgfile##*/}"
+ popd >/dev/null
+ done
+}
+
+build() (
+ local copydir=$1; shift
+ local cmd=(/chrootbuild "$@")
+
+ run_hook pre_build "$copydir"
+ trap "run_hook post_build '$copydir'" EXIT
+
+ local netflag=''
+ if $INCHROOT; then
+ ! $NONET || netflag='-n'
+ unshare $netflag -- "${cmd[@]}"
+ else
+ ! $NONET || netflag='-N'
+ librechroot $netflag \
+ -r "$PWD:/startdir_host" \
+ -r "$SRCDEST:/srcdest_host" \
+ -l "$copydir" \
+ run "${cmd[@]}"
+ fi
+)
+
+# The main program #############################################################
+
+usage() {
+ print "Usage: %s [options] [-- makepkg args]" "${0##*/}"
+ print 'This program will build your package.'
+ echo
+ prose 'If run from outside of a chroot, command will make the following
+ configuration changes in the chroot:'
+ bullet 'whatever changes `librechroot` makes.'
+ bullet 'set `PKGDEST` and `SRCDEST` in `/etc/makepkg.conf`'
+ bullet 'set `PACKAGER` in `/etc/makepkg.conf` to reflect the value
+ outside of the chroot.'
+ bullet '(maybe) delete `/build/.makepkg.conf`'
+ bullet '(maybe) delete `/build/.ssh/config`'
+ prose 'If run from inside of a chroot, this command will:'
+ bullet '(maybe) delete `~/.makepkg.conf`'
+ bullet '(maybe) delete `~/.ssh/config`'
+ prose 'The above "maybe"s happen as part of the workarounds to make
+ distcc work in a network-less environment. They will happen if
+ both `socat` and `distcc` are installed in the chroot.'
+ echo
+ prose 'The `-n` and `-l` options behave identically to librechroot, see
+ the documentation there.'
+ echo
+ print 'Options:'
+ flag "-n <$(_ CHROOT)>" 'Name of the chroot to use'
+ flag "-l <$(_ COPY)>" 'Name of, or absolute path to, the chroot copy to use'
+ flag '-N' "Don't disable networking during build() and
+ package(). PLEASE don't use this unless you
+ have a special reason, its use is a violation
+ of Parabola policy."
+ flag '-R' 'Repackage contents of the package without rebuilding'
+ flag '-h' 'Show this message'
+}
+
+# Convenience method for use in option parsing
+err_chflag() {
+ local flag=$1
+ error 'The -%s flag does not make sense inside of a chroot' "$flag"
+ return 1
+}
+
+main() {
+ # Initial variable values ##############################################
+ local copy=$([[ $LIBREUSER == root ]] && echo copy || echo "$LIBREUSER")
+ local makepkg_args=(-s --noconfirm -L)
+ local repack=false
+ local chroot=''
+
+ # Parse command line options ###########################################
+ while getopts 'n:l:NRh' flag ; do
+ case "${flag}" in
+ n) if $INCHROOT; then err_chflag "$flag"; else chroot=$OPTARG; fi;;
+ l) if $INCHROOT; then err_chflag "$flag"; else copy=$OPTARG; fi;;
+ N) NONET=false;;
+ R) repack=true; makepkg_args+=(-R);;
+ h) usage; return 0;;
+ *) usage >&2; return 1;;
+ esac
+ done
+ shift $(($OPTIND - 1))
+ # Pass all arguments after -- right to makepkg
+ makepkg_args+=("$@")
+
+ # Resolve the chroot path ##############################################
+ local copydir
+ if $INCHROOT; then
+ copydir='/'
+ else
+ load_files chroot
+ check_vars chroot CHROOTDIR CHROOT
+ [[ -z ${chroot} ]] || CHROOT=$chroot
+ if [[ ${copy:0:1} = / ]]; then
+ copydir=$copy
+ else
+ copydir="${CHROOTDIR}/${CHROOT}/${copy}"
+ fi
+ unset CHROOTDIR CHROOTEXTRAPKG
+ fi
+ unset chroot
+
+ # Quick sanity check ###################################################
+
+ if (( EUID )); then
+ error "This program must be run as root"
+ exit 1
+ fi
+
+ if [[ ! -f PKGBUILD ]]; then
+ # This is the message used by makepkg
+ error "PKGBUILD does not exist."
+ exit 1
+ fi
+
+ # Load makepkg configuration ###########################################
+ # Note that all of these are globals
+ SRCDEST="$(get_conf_makepkg SRCDEST "$PWD")"
+ PKGDEST="$(get_conf_makepkg PKGDEST "$PWD")"
+ LOGDEST="$(get_conf_makepkg LOGDEST "$PWD")"
+ mkdir -p "$SRCDEST" "$PKGDEST" "$LOGDEST"
+ MAKEFLAGS="$(get_conf_makepkg MAKEFLAGS '')"
+ PACKAGER="$(get_conf_makepkg PACKAGER '')"
+
+ # OK, we are starting now ##############################################
+
+ if $INCHROOT; then
+ lock 9 "/build/.lock" \
+ "Waiting for existing lock on build directory to be released"
+ else
+ # Obtain a lock on the chroot
+ lock 9 "$copydir.lock" \
+ "Waiting for existing lock on chroot copy to be released: [%s]" "$copy"
+ # Create the chroot if it does not exist
+ librechroot -n "$CHROOT" -l "$copy" make
+ fi
+
+ # Set target CARCH
+ # note that we waited until after locking/creating the chroot to do this
+ export CARCH="$(MAKEPKG_CONF=$copydir/etc/makepkg.conf get_conf_makepkg CARCH)"
+
+ # Pre-build
+ run_hook check_pkgbuild
+ download_sources "$copydir" "$LIBREUSER"
+ prepare_chroot "$copydir" "$LIBREHOME" "$repack" false
+ clean_chroot "$copydir"
+
+ # Build
+ trap "exit_copy '$copydir' '$LIBREUSER'" EXIT
+ warning 'Entering build...'
+ build "$copydir" "${makepkg_args[@]}"
+ # Post-build
+ warning 'Entering hook check_pkg...'
+ run_hook check_pkg
+ warning 'Entering add_to_local_repo ...'
+ add_to_local_repo "$copydir" "$copydir"/pkgdest/*.pkg.tar*
+}
+
+main "$@"
diff --git a/src/chroot-tools/makechrootpkg.sh.patch b/src/chroot-tools/makechrootpkg.sh.patch
new file mode 100644
index 0000000..f5b8ed7
--- /dev/null
+++ b/src/chroot-tools/makechrootpkg.sh.patch
@@ -0,0 +1,303 @@
+--- makechrootpkg.sh.in 2013-09-08 23:01:20.000000000 -0400
++++ makechrootpkg.sh.ugly 2013-09-09 15:43:06.000000000 -0400
+@@ -12,6 +12,7 @@
+
+ shopt -s nullglob
+
++init_variables() {
+ _makepkg_args=(-s --noconfirm -L --holdver)
+ makepkg_args=("${_makepkg_args[@]}")
+ repack=false
+@@ -26,9 +27,10 @@
+ declare -i ret=0
+
+ copy=$USER
+-[[ -n $SUDO_USER ]] && copy=$SUDO_USER
++[[ -n ${SUDO_USER:-} ]] && copy=$SUDO_USER
+ [[ -z "$copy" || $copy = root ]] && copy=copy
+ src_owner=${SUDO_USER:-$USER}
++}
+
+ usage() {
+ echo "Usage: ${0##*/} [options] -r <chrootdir> [--] [makepkg args]"
+@@ -62,6 +64,7 @@
+ exit 1
+ }
+
++parse_options_init() {
+ while getopts 'hcur:I:l:nT' arg; do
+ case "$arg" in
+ h) usage ;;
+@@ -86,9 +89,6 @@
+ [[ ! -d $chrootdir ]] && die "No chroot dir defined, or invalid path '%s'" "$passeddir"
+ [[ ! -d $chrootdir/root ]] && die "Missing chroot dir root directory. Try using: mkarchroot %s/root base-devel" "$chrootdir"
+
+-# Detect chrootdir filesystem type
+-chroottype=$(stat -f -c %T "$chrootdir")
+-
+ if [[ ${copy:0:1} = / ]]; then
+ copydir=$copy
+ else
+@@ -103,30 +103,47 @@
+ repack=true
+ fi
+
+-if [[ -n $SUDO_USER ]]; then
++if [[ -n ${SUDO_USER:-} ]]; then
+ USER_HOME=$(eval echo ~$SUDO_USER)
+ else
+ USER_HOME=$HOME
+ fi
++}
+
+ # {{{ functions
++# Usage: load_vars $makepkg_conf
++# Globals:
++# - SRCDEST
++# - LOGDEST
++# - PKGDEST
++# - MAKEFLAGS
++# - PACKAGER
+ load_vars() {
+ local makepkg_conf="$1" var
+
+ [[ -f $makepkg_conf ]] || return 1
+
+ for var in {SRC,PKG,LOG}DEST MAKEFLAGS PACKAGER; do
+- [[ -z ${!var} ]] && eval $(grep "^${var}=" "$makepkg_conf")
++ [[ -z ${!var:-} ]] && eval $(grep "^${var}=" "$makepkg_conf")
+ done
+
+ return 0
+ }
+
+-create_chroot() {
+- # Lock the chroot we want to use. We'll keep this lock until we exit.
+- lock 9 "$copydir.lock" "Locking chroot copy [%s]" "$copy"
++# Usage: sync_chroot $CHROOTDIR/$CHROOT <$CHROOTCOPY|$copydir>
++sync_chroot() {
++ local chrootdir=$1
++ local copy=$2
++ local copydir=''
++ if [[ ${copy:0:1} = / ]]; then
++ copydir=$copy
++ else
++ copydir="$chrootdir/$copy"
++ fi
++
++ # Detect chrootdir filesystem type
++ local chroottype=$(stat -f -c %T "$chrootdir")
+
+- if [[ ! -d $copydir ]] || $clean_first; then
+ # Get a read lock on the root chroot to make
+ # sure we don't clone a half-updated chroot
+ slock 8 "$chrootdir/root.lock" "Locking clean chroot"
+@@ -147,10 +164,15 @@
+
+ # Drop the read lock again
+ lock_close 8
+- fi
+ }
+
+-clean_temporary() {
++# Usage: delete_chroot $copydir [$copy]
++delete_chroot() {
++ local copydir=$1
++ local copy=${2:-$copydir}
++ # Detect chrootdir filesystem type
++ local chroottype=$(stat -f -c %T "$copydir")
++
+ stat_busy "Removing temporary copy [%s]" "$copy"
+ if [[ "$chroottype" == btrfs ]]; then
+ btrfs subvolume delete "$copydir" >/dev/null ||
+@@ -166,9 +188,14 @@
+ stat_done
+ }
+
++# Usage: install_packages $copydir $pkgs...
+ install_packages() {
++ local copydir=$1
++ local install_pkgs=("${@:2}")
++ declare -i ret=0
+ local pkgname
+
++ local install_pkg
+ for install_pkg in "${install_pkgs[@]}"; do
+ pkgname="${install_pkg##*/}"
+ cp "$install_pkg" "$copydir/$pkgname"
+@@ -179,11 +206,19 @@
+ rm "$copydir/$pkgname"
+ done
+
+- # If there is no PKGBUILD we are done
+- [[ -f PKGBUILD ]] || exit $ret
++ return $ret
+ }
+
++# Usage: prepare_chroot $copydir $HOME $repack $run_namcap
++# Globals:
++# - MAKEFLAGS
++# - PACKAGER
+ prepare_chroot() {
++ local copydir=$1
++ local USER_HOME=$2
++ local repack=$3
++ local run_namcap=$4
++
+ $repack || rm -rf "$copydir/build"
+
+ mkdir -p "$copydir/build"
+@@ -217,12 +252,12 @@
+
+ chown -R nobody "$copydir"/{build,pkgdest,logdest,srcdest,startdir}
+
+- if [[ -n $MAKEFLAGS ]]; then
++ if [[ -n ${MAKEFLAGS:-} ]]; then
+ sed -i '/^MAKEFLAGS=/d' "$copydir/etc/makepkg.conf"
+ echo "MAKEFLAGS='${MAKEFLAGS}'" >> "$copydir/etc/makepkg.conf"
+ fi
+
+- if [[ -n $PACKAGER ]]; then
++ if [[ -n ${PACKAGER:-} ]]; then
+ sed -i '/^PACKAGER=/d' "$copydir/etc/makepkg.conf"
+ echo "PACKAGER='${PACKAGER}'" >> "$copydir/etc/makepkg.conf"
+ fi
+@@ -235,6 +270,14 @@
+ chmod 440 "$copydir/etc/sudoers.d/nobody-pacman"
+ fi
+
++ if ! grep -q '^\[repo\]' "$copydir/etc/pacman.conf"; then
++ cat >> "$copydir/etc/pacman.conf" <<EOF
++[repo]
++SigLevel = Optional TrustAll
++Server = file:///repo
++EOF
++ fi
++
+ # This is a little gross, but this way the script is recreated every time in the
+ # working copy
+ printf $'#!/bin/bash\n%s\n_chrootbuild %q "$@"' "$(declare -f _chrootbuild)" \
+@@ -242,13 +285,19 @@
+ chmod +x "$copydir/chrootbuild"
+ }
+
++# Usage: download_sources $copydir $src_owner
++# Globals:
++# - SRCDEST
+ download_sources() {
++ local copydir=$1
++ local src_owner=$2
++
+ local builddir="$(mktemp -d)"
+ chmod 1777 "$builddir"
+
+ # Ensure sources are downloaded
+- if [[ -n $SUDO_USER ]]; then
+- sudo -u $SUDO_USER env SRCDEST="$SRCDEST" BUILDDIR="$builddir" \
++ if [[ $USER != $src_owner ]]; then
++ sudo -u $src_owner env SRCDEST="$SRCDEST" BUILDDIR="$builddir" \
+ makepkg --config="$copydir/etc/makepkg.conf" --verifysource -o
+ else
+ ( export SRCDEST BUILDDIR="$builddir"
+@@ -258,7 +307,7 @@
+ (( $? != 0 )) && die "Could not download sources."
+
+ # Clean up garbage from verifysource
+- rm -rf $builddir
++ rm -rf "$builddir"
+ }
+
+ _chrootbuild() {
+@@ -295,6 +344,7 @@
+
+ # Safety check
+ if [[ ! -w PKGBUILD ]]; then
++ # XXX: internationalize this message
+ echo "Can't write to PKGBUILD!"
+ exit 1
+ fi
+@@ -312,12 +362,24 @@
+ exit 0
+ }
+
++# Usage: move_products $copydir $owner
++# Globals:
++# - PKGDEST
++# - LOGDEST
+ move_products() {
++ local copydir=$1
++ local src_owner=$2
++
++ local pkgfile
+ for pkgfile in "$copydir"/pkgdest/*; do
+ chown "$src_owner" "$pkgfile"
+ mv "$pkgfile" "$PKGDEST"
++ if [[ $PKGDEST != $PWD ]]; then
++ ln -sf "$PKGDEST/${pkgfile##*/}" .
++ fi
+ done
+
++ local l
+ for l in "$copydir"/logdest/*; do
+ chown "$src_owner" "$l"
+ mv "$l" "$LOGDEST"
+@@ -325,6 +387,10 @@
+ }
+ # }}}
+
++main() {
++init_variables
++parse_options_init
++
+ umask 0022
+
+ load_vars /etc/makepkg.conf
+@@ -335,27 +401,37 @@
+ [[ -d $SRCDEST ]] || SRCDEST=$PWD
+ [[ -d $LOGDEST ]] || LOGDEST=$PWD
+
+-create_chroot
++# Lock the chroot we want to use. We'll keep this lock until we exit.
++lock 9 "$copydir.lock" "Locking chroot copy [%s]" "$copy"
++
++if [[ ! -d $copydir ]] || $clean_first; then
++ sync_chroot "$chrootdir" "$copy"
++fi
+
+ $update_first && arch-nspawn "$copydir" pacman -Syu --noconfirm
+
+-[[ -n ${install_pkgs[*]} ]] && install_packages
++if [[ -n ${install_pkgs[*]:-} ]]; then
++ install_packages "$copydir" "${install_pkgs[@]}"
++ ret=$?
++ # If there is no PKGBUILD we have done
++ [[ -f PKGBUILD ]] || exit $ret
++fi
+
+-prepare_chroot
++prepare_chroot "$copydir" "$USER_HOME" "$repack"
+
+-download_sources
++download_sources "$copydir" "$src_owner"
+
+ if arch-nspawn "$copydir" \
+ --bind-ro="$PWD:/startdir_host" \
+ --bind-ro="$SRCDEST:/srcdest_host" \
+ /chrootbuild "${makepkg_args[@]}"
+ then
+- move_products
++ move_products "$copydir" "$src_owner"
+ else
+ (( ret += 1 ))
+ fi
+
+-$temp_chroot && clean_temporary
++$temp_chroot && delete_chroot "$copydir" "$copy"
+
+ if (( ret != 0 )); then
+ if $temp_chroot; then
+@@ -366,3 +442,4 @@
+ else
+ true
+ fi
++}
diff --git a/src/devtools/.gitignore b/src/devtools/.gitignore
new file mode 100644
index 0000000..097fcde
--- /dev/null
+++ b/src/devtools/.gitignore
@@ -0,0 +1,3 @@
+*
+!Makefile
+!.gitignore
diff --git a/src/devtools/Makefile b/src/devtools/Makefile
new file mode 100644
index 0000000..3fc5d70
--- /dev/null
+++ b/src/devtools/Makefile
@@ -0,0 +1,8 @@
+progs = checkpkg find-libdeps finddeps lddd
+copy_files = $(addsuffix .in,$(progs))
+install_files = $(DESTDIR)$(bindir)/find-libprovides
+include ../../common.mk
+
+$(DESTDIR)$(bindir)/find-libprovides:
+ install -d $(@D)
+ ln -sf find-libdeps $@
diff --git a/src/fullpkg/Makefile b/src/fullpkg/Makefile
new file mode 100644
index 0000000..2c76089
--- /dev/null
+++ b/src/fullpkg/Makefile
@@ -0,0 +1 @@
+include ../../common.mk
diff --git a/src/fullpkg/fullpkg b/src/fullpkg/fullpkg
new file mode 100755
index 0000000..1d4388c
--- /dev/null
+++ b/src/fullpkg/fullpkg
@@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+# set -x # uncomment for debug
+# Builds packages from ABS recursively. It tries to find dependencies that
+# aren't built or need update and then makepkg them in order.
+
+usage() {
+
+ echo "cd to a dir containing a PKGBUILD and run:"
+ echo "$0 [build_dir]"
+ echo ""
+ echo "This script will check dependencies, build them if possible "
+ echo "and stage the packages on it's repo."
+ echo ""
+ echo "OPTIONS:"
+ echo " -h : this message."
+ echo ""
+ echo "Wrapper for \`fullpkg-find' and \`fullpkg-build'"
+ echo ""
+ exit 1
+
+}
+
+while getopts 'h' arg; do
+ case "$arg" in
+ h) usage ;;
+ esac
+done
+
+shift $(( OPTIND - 1 ))
+
+build_dir="${1:-$(mktemp -d /tmp/fullpkg.XXXXXX)}"
+fullpkg-find "$build_dir" && fullpkg-build -N "$build_dir"
+
+exit 0
diff --git a/src/fullpkg/fullpkg-build b/src/fullpkg/fullpkg-build
new file mode 100755
index 0000000..1771d83
--- /dev/null
+++ b/src/fullpkg/fullpkg-build
@@ -0,0 +1,193 @@
+#!/usr/bin/env bash
+# set -x # uncomment for debug
+# Builds packages from ABS recursively. It tries to find dependencies that
+# aren't built or need update and then makepkg them in order.
+
+# TODO move __build to chroot
+
+. libremessages
+. $(librelib conf.sh)
+load_files makepkg
+load_files libretools
+check_vars libretools FULLBUILDCMD || exit 1
+# The following variables are actually optional
+#check_vars libretools HOOKPKGBUILDMOD HOOKLOCALRELEASE || exit 1
+
+## List packages on log that are on status
+## usage: list_pkgs <status> <message>
+#
+## status: nonfree, built, failed, unstaged
+list_pkgs() {
+ msg="$2"
+ local pkgs=($(grep "$1:" $build_dir/log)) && {
+ msg "$2"
+ echo ${pkgs[@]} | tr " " "\n" | cut -d: -f2
+ }
+}
+
+## Check all build_dir, fails if one PKGBUILD is nonfree
+check_nonfree() {
+ find "$build_dir" -name PKGBUILD \
+ -exec pkgbuild-check-nonfree {} +
+ if [ "$?" -eq 15 ]; then
+ error "Some PKGBUILD have nonfree problems"
+ exit 15
+ fi
+
+}
+
+# Removes a package from the buildorder
+# $1 package name
+# $2 buildorder file
+remove_buildorder() {
+ grep -Evw "${1}" ${2} > ${2}2
+ mv -f ${2}2 ${2}
+
+ return $?
+}
+
+succesfull_build() {
+
+ if [ "$RUN" != "$FULLBUILDCMD" ]; then
+ return 0 # Custom command or download sources
+ fi
+
+ if source .INFO && [ -n "$repo" ]; then
+
+ if [ ! -z "$HOOKLOCALRELEASE" ]; then
+ "$HOOKLOCALRELEASE" "$repo"
+ fi
+
+ msg "Updating pacman db and packages"
+ sudo pacman -Sy || true
+
+ fi
+
+ echo "built:$(basename $PWD)" >>$build_dir/log
+}
+
+build_description() {
+ list_pkgs "nonfree" "Those packages contain nonfree deps:"
+ list_pkgs "built" "Those packages were built and staged:"
+ list_pkgs "failed" "Those packages failed to build:"
+ list_pkgs "unstaged" "Those packages couldn't be staged (missing reponame):"
+}
+
+__build() {
+ pushd ${build_dir} >/dev/null
+
+ build_packages=($(sort -gr $buildorder | cut -d: -f2)) # greater levels must be built first
+
+ while [ ${#build_packages[@]} -ge 1 ]; do
+
+ pushd "$build_dir/${build_packages[0]}" >/dev/null
+
+ if [ -n "${HOOKPKGBUILDMOD}" ]; then
+ ${HOOKPKGBUILDMOD} || true
+ fi
+
+ eval "$RUN"; r=$?
+
+ case $r in
+
+ 0) succesfull_build ;;
+
+ *) error "There were errors while trying to build the package."
+ echo "failed:$(basename $PWD)" >>$build_dir/log
+ ;;
+ esac
+
+ remove_buildorder "${build_packages[0]}" $buildorder || true
+
+# which is next package?
+ build_packages=($(sort -gr $buildorder | cut -d: -f2))
+ popd > /dev/null
+ done
+
+ popd >/dev/null
+}
+
+# End inmediately but print a useful message
+trap_exit() {
+ error "$@"
+ warning "Leftover files left on $build_dir"
+ mv .BUILDORDER BUILDORDER
+ exit 1
+}
+
+# Trap signals from makepkg
+set -E
+trap 'trap_exit "(fullpkg-build) TERM signal caught. Exiting..."' TERM HUP QUIT
+trap 'trap_exit "(fullpkg-build) Aborted by user! Exiting..."' INT
+trap 'trap_exit "(fullpkg-build) An unknown error has occurred. Exiting..."' ERR
+
+CLEANUP="false"
+CHECKNONFREE="true"
+RUN="$FULLBUILDCMD"
+MESSAGE="Building packages"
+
+usage() {
+
+ echo ""
+ echo "$(basename $0) [options] <build_dir>"
+ echo ""
+ echo "Builds packages from build_dir, create a build_dir using:"
+ echo "'fullpkg-find <build_dir>'"
+ echo ""
+ echo "If no <build_dir> is specified, it uses the current directory."
+ echo ""
+ echo "OPTIONS:"
+ echo " -h : this message."
+ echo " -c : clean <build_dir> on succesfull build"
+ echo " -N : don't check for freedom issues." #Also made by fullpkg-find
+ echo " -r \"command\" : use this instead of \"$FULLBUILDCMD\"."
+ echo " -g : get sources for building packages on build_dir."
+ echo ""
+ exit 1
+
+}
+
+while getopts 'hNr:g' arg; do
+ case $arg in
+ h) usage ;;
+ c) CLEAN ;;
+ N) CHECKNONFREE="false" ;;
+ r) RUN="$OPTARG"
+ MESSAGE="Executing custom action";;
+ g) RUN='makepkg -g > /dev/null'
+ MESSAGE="Downloading packages";;
+ esac
+done
+
+shift $(( OPTIND - 1 ))
+build_dir="${1:-`pwd`}"
+buildorder="${build_dir}/BUILDORDER"
+
+if [ ! -e "$buildorder" ]; then
+ error "This is not a build_dir. Make one using fullpkg."
+ usage
+else
+# backup BUILDORDER
+ cp "$buildorder" "$build_dir/.BUILDORDER"
+fi
+
+if "$CHECKNONFREE"; then
+ check_nonfree
+fi
+
+msg "$MESSAGE"
+__build
+
+if [ "$RUN" != "$FULLBUILDCMD" ]; then
+ # Used for downloading or custom command
+ mv "$build_dir/.BUILDORDER" "$buildorder"
+ exit 0
+elif "$CLEANUP"; then
+ find "$build_dir" -mindepth 1 -delete
+fi
+
+build_description
+
+plain "Test packages on and if they work fine librerelease."
+
+exit 0
diff --git a/src/fullpkg/fullpkg-find b/src/fullpkg/fullpkg-find
new file mode 100755
index 0000000..a927782
--- /dev/null
+++ b/src/fullpkg/fullpkg-find
@@ -0,0 +1,197 @@
+#!/usr/bin/env bash
+# set -x # uncomment for debug
+# Builds packages from ABS recursively. It tries to find dependencies that
+# aren't built or need update and then makepkg them in order.
+
+# TODO: fullpkg-find should find packages wich depend on the
+# package to be build, so we can avoid "missing $name.so errors"
+
+# Get repo name. Asumes ${ABSROOT}/repo/package/PKGBUILD
+guess_repo() {
+ basename $(dirname $(pwd))
+}
+
+# This function is stolen from makechrootpkg.
+# That probably has some copyright/licensing implications.
+copy_files() {
+
+ local copydir="$build_dir/${pkgbase:-${pkgname[0]}}"
+ mkdir -p "$copydir"
+
+ # Copy PKGBUILD and sources
+ cp PKGBUILD "$copydir"
+ (
+ load_PKGBUILD
+ for file in "${source[@]}"; do
+ file="${file%%::*}"
+ file="${file##*://*/}"
+ if [[ -f $file ]]; then
+ cp "$file" "$copydir/"
+ elif [[ -f $SRCDEST/$file ]]; then
+ cp "$SRCDEST/$file" "$copydir/"
+ fi
+ done
+
+ # Find all changelog and install files, even inside functions
+ for i in 'changelog' 'install'; do
+ while read -r file; do
+ # evaluate any bash variables used
+ eval file=\"$(sed 's/^\(['\''"]\)\(.*\)\1$/\2/' <<< "$file")\"
+ [[ -f $file ]] && cp "$file" "$copydir"
+ done < <(sed -n "s/^[[:space:]]*$i=//p" PKGBUILD)
+ done
+ )
+}
+
+# Checks ABSROOT and look for target pkg deps. Adds them if not built or outdated.
+find_deps() {
+# Check this level
+ load_PKGBUILD
+
+ local repo="${repo:-$(guess_repo)}"
+ local pkgbase="${pkgbase:-${pkgname[0]}}"
+
+ if ! pkgbuild-check-nonfree > /dev/null 2> /dev/null; then
+ if [ "$?" -eq 15 ]; then
+ error "pkgbase" has nonfree issues
+ return 15
+ fi
+ fi
+
+ # Checking any package built, since otherwise e.g. kdebase would
+ # be always considered outdated: there is no package built named kdebase.
+ # TODO: maybe check for the package requested in case of recursive calls,
+ # instead of the first one listed?
+ if is_built "${pkgname[0]}" "$(get_full_version "${pkgname[0]}")"; then
+ exit 0 # pkg is built and updated
+ fi
+
+# greater levels are built first
+ echo "${LEVEL}:${pkgbase}" >>"$build_dir/BUILDORDER"
+# PKGBUILD is already there
+ if [ -d "${build_dir}/${pkgbase}" ]; then
+ exit 0
+# Copy dir to build_dir
+ else
+ copy_files
+
+# to identify repo later
+ echo "repo=$repo" > "${build_dir}/${pkgbase}/.INFO"
+ fi
+
+# current package plus a space for every level
+ msg2 "%${LEVEL}s${pkgbase}-$(get_full_version)"
+
+## Check next levels
+ declare -i next_level=$LEVEL+1
+
+# All deps in separate line, only once, without version.
+ deps=($(echo "${depends[@]} ${makedepends[@]}" | \
+ sed "s/[=<>]\+[^ ]\+//g" | \
+ tr ' ' "\n" | \
+ sort -u))
+
+ for _dep in ${deps[@]}; do
+
+ local found=false
+ # May fail, e.g. since abslibre-mips64el doesn't include
+ # arch=any packages.
+ local pkgdir=$(toru -p ${_dep}) || true
+
+ if [ -n "$pkgdir" -a -d "${pkgdir}" ]; then
+ found=true
+
+ pushd "${pkgdir}" > /dev/null
+# runs itself on dep's PKGBUILD dir
+ $0 -l ${next_level} ${build_dir} || return $?
+ popd > /dev/null
+ fi
+
+ if ! (( found )); then
+ echo "dep_not_found:$_dep" >>$build_dir/log
+ fi
+
+ done
+
+## End variable block
+
+ unset next_level dir
+}
+
+. libremessages
+. $(librelib conf.sh)
+load_files makepkg
+
+LEVEL=0
+MAXLEVEL=20
+CLEANFIRST='false'
+UPDATEDB='true'
+
+usage() {
+
+ echo ""
+ echo "cd to a dir containing a PKGBUILD and run:"
+ echo "$(basename $0) [options] <build_dir>"
+ echo ""
+ echo "This script will create a build_dir for recursive building"
+ echo "it tries to find dependencies that aren't built or need update."
+ echo ""
+ echo "If no <build_dir> is specified, the script works on a tempdir"
+ echo ""
+ echo "OPTIONS:"
+ echo " -h : this message."
+ echo " -A <absroot> : use this ABSROOT."
+ echo " -c : clean <build_dir> before working."
+ echo " -m <max_level> : check deps until this level"
+ echo " -n : don't update pacman db."
+ echo ""
+ exit 1
+
+}
+
+while getopts 'hA:l:cmn' arg; do
+ case "$arg" in
+ h) usage ;;
+ A) ABSROOT="$OPTARG" ;;
+ l) LEVEL="$OPTARG" ;; # hidden option to know dep level.
+ c) CLEANFIRST='true' ;;
+ m) MAXLEVEL="$OPTARG" ;;
+ n) UPDATEDB='false' ;;
+ esac
+done
+
+if [ ! -r PKGBUILD ]; then
+ error "This directory doesnt contain a PKGBUILD"
+ usage
+fi
+
+shift $(( OPTIND - 1 ))
+build_dir="${1}"
+
+if [ "$LEVEL" -eq 0 ]; then
+
+ build_dir="${1:-$(mktemp -d /tmp/fullpkg.XXXXXX)}"
+
+ if [ ! -d "$build_dir" ]; then
+ mkdir -p "$build_dir"
+ elif "$CLEANFIRST"; then
+ # Erase files already in dir
+ msg "Cleaning up files in dir"
+ find "$build_dir" -mindepth 1 -delete
+ fi
+
+ if "$UPDATEDB"; then
+ msg "Updating pacman db"
+ sudo pacman -Sy --noconfirm || true
+ fi
+
+# make files for log and buildorder
+ touch "${build_dir}"/{log,BUILDORDER}
+ buildorder="${build_dir}/BUILDORDER"
+
+ msg "Checking dependencies"
+fi
+
+find_deps
+
+exit 0
diff --git a/src/is_built b/src/is_built
new file mode 100755
index 0000000..80d0719
--- /dev/null
+++ b/src/is_built
@@ -0,0 +1,46 @@
+#!/usr/bin/env bash
+
+cmd=${0##*/}
+usage() {
+ echo "Usage: $cmd [-h] pkgname [pkgver]"
+ echo
+ echo "Detect if a given package version is already in repos"
+ echo "Assuming you want greater or equal."
+ echo
+ echo "Example usage: $cmd 'pcre' '20'"
+ echo
+ echo "Exit status:"
+ echo " 0: The package is built"
+ echo " 1: The package has not built"
+ echo " >1: There was an error"
+}
+
+while getopts 'h' arg; do
+ case $arg in
+ h) usage; exit 0 ;;
+ *) usage >&2; exit 2 ;;
+ esac
+done
+if [[ $# -ne 1 ]] && [[ $# -ne 2 ]]; then
+ usage >&2
+ exit 2
+fi
+
+pkg=${1}
+ver=${2:-0}
+pver=$(LC_ALL=C pacman -Sddp --print-format '%v' "${pkg}" 2>/dev/null)
+
+# if pacman fails or returns nothing
+r=$?
+
+result=$(vercmp "${pver}" "${ver}")
+# result:
+# -1 : pver < ver
+# 0 : pver = ver
+# 1 : pver > ver
+
+if [[ $result -ge 0 ]] && [[ $r -eq 0 ]]; then
+ exit 0
+else
+ exit 1
+fi
diff --git a/src/lib/.gitignore b/src/lib/.gitignore
new file mode 100644
index 0000000..9a0c402
--- /dev/null
+++ b/src/lib/.gitignore
@@ -0,0 +1,3 @@
+common.sh
+common.sh.in
+common.sh.top
diff --git a/src/lib/Makefile b/src/lib/Makefile
new file mode 100644
index 0000000..45fd330
--- /dev/null
+++ b/src/lib/Makefile
@@ -0,0 +1,30 @@
+copy_files = common.sh.in
+libexecs = $(filter-out librelib,$(wildcard libre*))
+# include common.sh in libs explicitly, because it might not exist yet
+# when the wildcard is performed
+libs = $(sort $(wildcard *.sh) common.sh)
+include ../../common.mk
+
+# Build ##############################################################
+
+common.sh: %: %.in %.top Makefile
+ @echo "GEN $@"
+ @{ \
+ cat '$*.top' && \
+ echo && \
+ sed -r -e '/encoding problem/d;/LANG=/d' -e 's/mesg=\$$(.)/mesg="$$(_ "$$\1")"/' '$*.in' && \
+ echo && \
+ cat '$*.bottom' && \
+ :; } > '$@'
+
+# Translate ##########################################################
+
+pot: libreblacklist.pot common.sh.pot librelib.pot
+
+libreblacklist.pot: libreblacklist
+ { \
+ sed -n '/^# Usage:/,/()/{ /^#/ { =; p; } }' $< | sed -r -e 's/^# (.*)/msgid "\1"/' -e 's/^[0-9]*$$/#. embedded usage text\n#: $<:&/'; \
+ sed -rn '/print /{ =; s/\s*print "([^"]*)".*/msgid "\1"/p; }' $< | sed 's/^[0-9]*$$/#. print\n#: $<:&/' ; \
+ } | sed 's/^msgid .*/&\nmsgstr ""\n/' > $@
+common.sh.pot: common.sh
+ xgettext --omit-header -i --from-code=UTF-8 -L shell -o $@ $<
diff --git a/src/lib/common.sh.bottom b/src/lib/common.sh.bottom
new file mode 100644
index 0000000..e133fad
--- /dev/null
+++ b/src/lib/common.sh.bottom
@@ -0,0 +1 @@
+fi
diff --git a/src/lib/common.sh.top b/src/lib/common.sh.top
new file mode 100644
index 0000000..054301b
--- /dev/null
+++ b/src/lib/common.sh.top
@@ -0,0 +1,26 @@
+#!/bin/bash # non-executable, but put this there as a hint to text editors
+# This may be included with or without `set -euE`
+
+# This file is included by libremessages.
+# You should probably use libremessages instead of this.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+if [[ -z ${_INCLUDE_COMMON_SH:-} ]]; then
+_INCLUDE_COMMON_SH=true
+
+export TEXTDOMAIN='libretools'
+export TEXTDOMAINDIR='/usr/share/locale'
+
+if type gettext &>/dev/null; then
+ _() { gettext "$@"; }
+else
+ _() { echo "$@"; }
+fi
diff --git a/src/lib/conf.sh b/src/lib/conf.sh
new file mode 100644
index 0000000..f96af26
--- /dev/null
+++ b/src/lib/conf.sh
@@ -0,0 +1,190 @@
+#!/bin/bash # non-executable, but put this there as a hint to text editors
+# This may be included with or without `set -euE`
+
+# Copyright (c) 2012-2013 by Luke Shumaker <lukeshu@sbcglobal.net>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+LIBREUSER="${SUDO_USER:-$USER}"
+if [[ $LIBREUSER == $USER ]]; then
+ LIBREHOME=$HOME
+else
+ LIBREHOME="$(eval echo ~$LIBREUSER)"
+fi
+if [[ -z ${XDG_CONFIG_HOME:-} ]]; then
+ export XDG_CONFIG_HOME="${LIBREHOME}/.config"
+fi
+if [[ -z ${XDG_CACHE_HOME:-} ]]; then
+ export XDG_CACHE_HOME="${LIBREHOME}/.cache"
+fi
+
+# Generic functions ############################################################
+
+# Usage: list_files $slug
+# Lists the configuration files to be considered for $slug.
+# Later files should take precedence over earlier files.
+list_files() {
+ local slug=$1
+ case $slug in
+ abs)
+ echo /etc/$slug.conf
+ echo "$LIBREHOME/.$slug.conf"
+ ;;
+ makepkg)
+ if [[ ${MAKEPKG_CONF:-} != /etc/$slug.conf && -r ${MAKEPKG_CONF:-} ]]; then
+ echo "$MAKEPKG_CONF"
+ else
+ echo /etc/$slug.conf
+ echo "$LIBREHOME/.$slug.conf"
+ fi
+ ;;
+ libretools)
+ echo /etc/$slug.conf
+ echo "$XDG_CONFIG_HOME/libretools/$slug.conf"
+ ;;
+ *)
+ echo /etc/libretools.d/$slug.conf
+ echo "$XDG_CONFIG_HOME/libretools/$slug.conf"
+ ;;
+ esac
+}
+
+# Usage: list_envvars $slug
+# Lists the environmental variables that take precidence over the configuration
+# files for $slug.
+list_envvars() {
+ local slug=$1
+ case $slug in
+ makepkg)
+ printf '%s\n' \
+ PKGDEST SRCDEST SRCPKGDEST LOGDEST \
+ BUILDDIR \
+ PKGEXT SRCEXT \
+ GPGKEY PACKAGER
+ ;;
+ *) :;;
+ esac
+}
+
+# Usage: load_files $slug
+# Loads the configuration files for $slug in the proper order.
+load_files() {
+ local slug=$1
+ local var
+ local file
+
+ # Save the existing versions at _VARNAME
+ for var in $(list_envvars $slug); do
+ [[ -n ${!var:-} ]] && eval "_$var=\${$var}"
+ done
+
+ # Load the files
+ for file in $(list_files $slug); do
+ if [[ -r $file ]]; then
+ . "$file" || return 1
+ fi
+ done
+
+ # Restore the _SAVED versions
+ for var in $(list_envvars $slug); do
+ eval "$var=\${_$var:-\${$var:-}}"
+ done
+}
+
+# Usage: check_vars $slug VAR1 VAR2...
+# Check whether the variables listed are properly set.
+# If not, it prints a message saying to set them in the configuration file(s)
+# for $slug.
+check_vars() {
+ local slug=$1; shift
+
+ local ret=0
+
+ local VAR
+ for VAR in "$@"; do
+ if [[ -z ${!VAR:-} ]]; then
+ type print &>/dev/null || . libremessages
+ if [[ $(list_files $slug|wc -l) -gt 1 ]]; then
+ print "Configure '%s' in one of:" "$VAR"
+ list_files $slug | sed 's/./ -> &/'
+ else
+ print "Configure '%s' in '%s'" "$VAR" "$(list_files $slug)"
+ fi
+ ret=1
+ fi
+ done >&2
+
+ if [[ $ret != 0 ]]; then
+ return 1
+ fi
+}
+
+# makepkg configuration ########################################################
+
+# Usage: get_conf_makepkg <var_name> <default_value>
+get_conf_makepkg() (
+ set +euE
+ local setting=$1
+ local default=$2
+ load_files makepkg
+ printf '%s\n' "${!setting:-${default}}"
+)
+
+set_conf_makepkg() {
+ local key=$1
+ local val=$2
+ local file
+ for file in $(list_files makepkg|tac); do
+ if [[ -w $file ]]; then
+ sed -i "/^\s*$key=/d" "$file"
+ printf '%s=%q\n' "$key" "$val" >> "$file"
+ return 0
+ fi
+ done
+ return 1
+}
+
+# PKGBUILD (not configuration, per se) #########################################
+
+unset_PKGBUILD() {
+ # This routine is based primarily off of the PKGBUILD(5) man-page,
+ # version 4.1.2, dated 2013-06-18.
+
+ # From the "OPTIONS AND DIRECTIVES" section (in order of mention)
+ unset -v pkgname pkgver
+ unset -f pkgver
+ unset -v pkgrel pkgdesc epoch url license install changelog source
+ unset -v noextract md5sums sha{1,256,384,512}sums groups arch backup
+ unset -v depends makedepends checkdepends optdepends conflicts provides
+ unset -v replaces options
+
+ # From the "PACKAGING FUNCTIONS" section (in order of mention)
+ unset -f package prepare build check
+
+ # From the "PACKAGE SPLITTING" section
+ unset -f $(declare -f|sed -n 's/^\(package_\S*\) ()\s*$/\1/p')
+ unset -v pkgbase
+
+ # These are used by the `librefetch` program
+ unset -v mksource mknoextract mkmd5sums mksha{1,256,384,512}sums
+ unset -v mkdepends
+ unset -f mksource
+}
+
+load_PKGBUILD() {
+ local file=${1:-./PKGBUILD}
+ unset_PKGBUILD
+ CARCH="$(get_conf_makepkg CARCH "`uname -m`")"
+ . "$file"
+}
diff --git a/src/lib/libreblacklist b/src/lib/libreblacklist
new file mode 100755
index 0000000..5db1a3f
--- /dev/null
+++ b/src/lib/libreblacklist
@@ -0,0 +1,148 @@
+#!/usr/bin/env bash
+# This may be included with or without `set -euE`
+# When run directly, it does `set -euE`
+
+# Copyright (c) 2013 by Luke Shumaker <lukeshu@sbcglobal.net>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# make sure XDG_CACHE_HOME is set
+. $(librelib conf)
+
+# Usage: blacklist-normalize <$file
+# Normalizes the syntax of the blacklist on stdin.
+blacklist-normalize() {
+ sed -e 's/^[^:]*$/&::/' -e 's/^[^:]*:[^:]*$/&:/'
+}
+
+# Usage: blacklist-cat
+# Prints the blacklist.
+# Uses the cache, but downloads it if it doesn't exist. Also normalizes the blacklist for easier parsing.
+blacklist-cat() {
+ local file="$XDG_CACHE_HOME/libretools/blacklist.txt"
+ if ! [[ -e $file ]]; then
+ # exit on failure, whether set -e or not
+ blacklist-update || return $?
+ fi
+ blacklist-normalize < "$file"
+}
+
+# Usage: blacklist-update
+# Updates (or creates) the cached copy of the blacklist.
+blacklist-update() (
+ . libremessages
+ load_files libretools || return 1
+ check_vars libretools BLACKLIST || return 1
+
+ local remote_blacklist="$BLACKLIST"
+ local local_blacklist="$XDG_CACHE_HOME/libretools/blacklist.txt"
+
+ stat_busy "Downloading blacklist of proprietary software packages"
+
+ mkdir -p "${local_blacklist%/*}"
+ if wget -N -q -O "${local_blacklist}.part" "$remote_blacklist" 2>/dev/null; then
+ stat_done
+ mv -f "${local_blacklist}.part" "$local_blacklist"
+ else
+ stat_done
+ rm "${local_blacklist}.part"
+ if [[ -e "$local_blacklist" ]]; then
+ warning "Using local copy of blacklist"
+ else
+ error "Download failed, exiting"
+ return 1
+ fi
+
+ fi
+)
+
+# Usage: blacklist-cat | blacklist-lookup $pkgname
+# Filters to obtain the line for $pkgname from the blacklist on stdin.
+# Exits successfully whether a line is found or not.
+blacklist-lookup() {
+ local pkg=$1
+ # we accept that $pkg contains no regex-nes
+ blacklist-normalize | grep "^$pkg:" || true
+}
+
+# Usage: blacklist-cat | blacklist-get-pkg
+# Prints only the package name field of the blacklist line(s) on stdin.
+blacklist-get-pkg() {
+ blacklist-normalize | cut -d: -f1
+}
+
+# Usage: blacklist-cat | blacklist-get-rep
+# Prints only the replacement package field of the blacklist line(s) on stdin.
+blacklist-get-rep() {
+ blacklist-normalize | cut -d: -f2
+}
+
+# Usage: blacklist-cat | blacklist-get-reason
+# Prints only the reason field of the blacklist line(s) on stdin.
+blacklist-get-reason() {
+ blacklist-normalize | cut -d: -f3-
+}
+
+if [[ "${0##*/}" == libreblacklist ]]; then
+ set -euE
+ usage-outside() {
+ sed -n '/^# Usage:/,/()/p' "$0" |
+ tr '\n' '\r' | sed 's/\s*()\s*[{(]/\n/g'
+ }
+ # The output format of this is:
+ # - The first line is "Usage:"
+ # - The second line is a brief description
+ # - The last line is the command name (prefixed with "blacklist-")
+ # - The in-between lines are the extended description.
+ usage-inside() {
+ sed 's/\r/\n/g'<<<"$1"|sed -e '/^$/d' -e 's/^# //'
+ }
+ usage() {
+ . $(librelib messages)
+ if [[ $# -eq 0 ]]; then
+ print "Usage: %s [-h] COMMAND [ARGUMENTS]" "${0##*/}"
+ print "Tool for working with the nonfree software blacklist"
+ echo
+ print "Commands:"
+ usage-outside | while read -r sec; do sec="$(usage-inside "$sec")"
+ cmd=$(<<<"$sec" sed -n '$s/^blacklist-//p')
+ desc="$(_ "$(sed -n 2p <<<"$sec")")"
+ flag "$cmd" "${desc//blacklist-/${0##*/} }"
+ done
+ else
+ usage-outside | while read -r sec; do sec="$(usage-inside "$sec")"
+ cmd=$(<<<"$sec" sed -n '$s/^blacklist-//p')
+ if [[ "$cmd" == "$1" ]]; then
+ <<<"$sec" sed '$d' |
+ while read -r line; do print "$line"; done |
+ sed "s/blacklist-/${0##*/} /g" |
+ fmt -us
+ return 0
+ fi
+ done
+ fi
+ }
+
+ if [[ $# -eq 0 ]]; then
+ usage >/dev/stderr
+ exit 1
+ fi
+ _blacklist_cmd=$1
+ shift
+ if [[ $_blacklist_cmd == -h ]]; then
+ usage "$@"
+ else
+ "blacklist-$_blacklist_cmd" "$@"
+ fi
+fi
diff --git a/src/lib/librelib b/src/lib/librelib
new file mode 100755
index 0000000..2dc9314
--- /dev/null
+++ b/src/lib/librelib
@@ -0,0 +1,79 @@
+#!/usr/bin/env bash
+# Copyright (c) 2013 by Luke Shumaker <lukeshu@sbcglobal.net>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+default_libdir=/usr/lib/libretools
+
+if ! type gettext &>/dev/null; then
+ gettext() { echo "$@"; }
+fi
+
+print() {
+ mesg=$1
+ shift
+ printf -- "$(gettext "$mesg")\n" "$@"
+}
+
+prose() {
+ print "$@" | fmt -su
+}
+
+cmd=${0##*/}
+usage() {
+ . libremessages
+ print 'Usage: . $(%s LIBRARY)' "$cmd"
+ print "Finds a shell library file"
+ echo
+ prose "While some libraries can be sourced just by their name because
+ they are installed in PATH (like libremessages), some are not
+ installed there (like conf.sh), so a path must be given.
+ Hardcoding that path is the way of the dark side."
+ echo
+ prose 'By default, it looks for the files in `%s`, but this can be
+ changed with the environmental variable LIBRETOOLS_LIBDIR.' "$default_libdir"
+ echo
+ print "Example usage:"
+ printf ' . $(%s conf.sh)\n' "$cmd"
+}
+
+main() {
+ if [[ $# != 1 ]]; then
+ usage >&2
+ return 2
+ fi
+ if [[ $1 == '-h' ]]; then
+ usage
+ return 0;
+ fi
+
+ if [[ -z $LIBRETOOLS_LIBDIR ]]; then
+ export LIBRETOOLS_LIBDIR=$default_libdir
+ fi
+
+ lib=$1
+ lib=${lib#libre}
+ lib=${lib%.sh}
+
+ for file in ${lib} libre${lib} ${lib}.sh libre${lib}.sh; do
+ if [[ -f "$LIBRETOOLS_LIBDIR/$file" ]]; then
+ printf '%s\n' "$LIBRETOOLS_LIBDIR/$file"
+ return 0;
+ fi
+ done
+ print '%s: could not find library: %s' "$cmd" "$lib" >> /dev/stderr
+ return 1
+}
+
+main "$@"
diff --git a/src/lib/libremessages b/src/lib/libremessages
new file mode 100755
index 0000000..c6d08e2
--- /dev/null
+++ b/src/lib/libremessages
@@ -0,0 +1,131 @@
+#!/usr/bin/env bash
+# This may be included with or without `set -euE`
+# When run directly, it does `set -euE`
+
+# Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
+# Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
+# Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
+# Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu>
+# Copyright (c) 2006 by Alex Smith <alex@alex-smith.me.uk>
+# Copyright (c) 2006 by Andras Voroskoi <voroskoi@frugalware.org>
+# Copyright (c) 2006 by Miklos Vajna <vmiklos@frugalware.org>
+# Copyright (c) 2011 by Joshua Haase <hahj87@gmail.com>
+# Copyright (c) 2012-2013 by Luke Shumaker <lukeshu@sbcglobal.net>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+################################################################################
+# Inherit most functions from devtools #
+################################################################################
+
+. $(librelib common.sh)
+
+################################################################################
+# Own functions #
+################################################################################
+
+panic() {
+ echo "$(_ 'panic: malformed call to internal function')" >&2
+ exit 1
+}
+
+# Usage: print MESG ARG1 ARG2...
+# Like printf, but gettext-aware, and prints a trailing newline
+print() {
+ [[ $# -ge 1 ]] || panic
+ local mesg="$(_ "$1")"
+ shift
+ printf -- "$mesg\n" "$@"
+}
+
+# Do HTML-style whitespace collapsing on standard IO. It considers newline,
+# tab, and space to be whitespace.
+_html_whitespace_collapse() {
+ [[ $# == 0 ]] || panic
+ tr '\n' ' ' | sed -r -e 's/\t/ /g' -e 's/ +/ /g'
+}
+
+
+# Usage: prose MESG
+# Do HTML-style whitespace collapsing on the first argument, translate it
+# (gettext), then word-wrap it to 75 columns.
+# This is useful for printing a paragraph of prose in --help text.
+prose() {
+ [[ $# -ge 1 ]] || panic
+ local mesg="$(_ "$(_html_whitespace_collapse <<<"$1")")"; shift
+ printf -- "$mesg" "$@" | fmt -u
+}
+
+# Usage: bullet MESG
+# Like prose, but print a bullet "-" before the first line, and indent the
+# remaining lines.
+bullet() {
+ [[ $# -ge 1 ]] || panic
+ local mesg="$(_ "$(_html_whitespace_collapse <<<"$1")")"; shift
+ # Wrap the text to 71 columns; 75 (the default) minus a 4 column indent
+ printf -- "$mesg" "$@" | fmt -u -w 71 | sed -e '1s/^/ - /' -e '2,$s/^/ /'
+}
+
+# Usage: flag FLAG DESCRIPTION
+# Print a flag and description formatted for --help text.
+# ex: flag '-C <FILE>' 'Use this file instead of pacman.conf'
+# The description is fed through gettext, the flag is not, so if part of the
+# flag needs to be translated, you must do that yourself:
+# ex: flag "-C <$(_ FILE)>" 'Use this file instead of pacman.conf'
+# If you want to line-break the description in the source, so it isn't
+# crazy-long, feel free, it is reflowed/wrapped the same way as prose and
+# bullet.
+flag() {
+ [[ $# == 2 ]] || panic
+ local n='
+'
+ local flag=$1
+ local desc="$(_ "$(_html_whitespace_collapse <<<"$2")")"
+
+ declare -i indent=13
+ while [[ $indent -le ${#flag} ]]; do
+ indent=$((indent+8))
+ done
+
+ local lines
+ IFS=$n lines=($(fmt -u -w $((73-indent)) <<<"$desc"))
+ local line
+ for line in "${lines[@]}"; do
+ printf " %-${indent}s %s\n" "$flag" "$line"
+ flag=''
+ done
+}
+
+# Usage: term_title This will be the term title
+# Sets the terminal title
+term_title() {
+ [[ $# -ge 1 ]] || panic
+ local fmt=''
+ case "$TERM" in
+ screen|tmux) fmt='\ek%s\e\\';;
+ xterm*|rxvt*) fmt='\e]0;%s\a';;
+ esac
+ printf "$fmt" "$*"
+}
+
+################################################################################
+# Run one of the defined functions if invoked directly #
+################################################################################
+
+if [[ "${0##*/}" == libremessages ]]; then
+ set -euE
+ _libremessages_cmd=$1
+ shift
+ "$_libremessages_cmd" "$@"
+fi
diff --git a/src/librefetch/Makefile b/src/librefetch/Makefile
new file mode 100644
index 0000000..2c76089
--- /dev/null
+++ b/src/librefetch/Makefile
@@ -0,0 +1 @@
+include ../../common.mk
diff --git a/src/librefetch/librefetch b/src/librefetch/librefetch
new file mode 100755
index 0000000..086a5e9
--- /dev/null
+++ b/src/librefetch/librefetch
@@ -0,0 +1,331 @@
+#!/usr/bin/env bash
+# librefetch
+#
+# Copyright 2013 Luke Shumaker <lukeshu@sbcglobal.net>
+#
+# This file is part of Parabola.
+#
+# Parabola is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Parabola is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Parabola. If not, see <http://www.gnu.org/licenses/>.
+
+. $(librelib conf.sh)
+. libremessages
+
+declare -r tempdir="$(mktemp -d --tmpdir ${0##*/}.XXXXXXXXXXX)"
+cleanup() { rm -rf -- "$tempdir"; }
+trap cleanup EXIT
+
+cmd=${0##*/}
+usage() {
+ print "Usage: %s [options] <source-url> [<output-file>]" "$cmd"
+ print "Usage: %s -[g|P|V|h]" "$cmd"
+ print "Downloads or creates a liberated source tarball."
+ echo
+ print "The default mode is to create <output-file>, first by trying download"
+ print "mode, then create mode."
+ echo
+ print "If <output-file> isn't specified, it defaults to the non-directory"
+ print "part of <source-url>, in the current directory."
+ echo
+ print "In download mode, the glob '*://' is stripped from the beginning of"
+ print "<source-url>, and the resulting path is attempted to be downloaded"
+ print "from the configured mirror."
+ echo
+ print "In create mode, it looks at a build script, and uses that to create"
+ print "the source tarball. <source-url> is ignored, except that it is used"
+ print "to set the default value of <output-file>."
+ echo
+ print "The default build script is 'PKGBUILD', or 'SRCBUILD' if it exists."
+ echo
+ print "Unrecognized options are passed straight to makepkg."
+ echo
+ print "Example usage:"
+ print ' $ %s libre://mypackage-1.0.tar.gz' "$cmd"
+ echo
+ print "Options:"
+ print " Settings:"
+ print " -C Force create mode (don't download)"
+ print " -D Force download mode (don't create)"
+ print " -p <file> Use an alternate build script (instead of 'PKGBUILD')"
+ print " If an SRCBUILD exists in the same directory, it is used"
+ print " instead"
+ print " Alternate modes:"
+ print " -g, --geninteg Generage integrity checks for source files"
+ print " -P, --print Print the effective build script (SRCBUILD)"
+ print " -V, --version Show version information"
+ print " -h, --help Show this message"
+}
+
+version() {
+ print "librefetch (libretools) beta 4"
+ echo
+ print "Copyright (C) 2013 Luke Shumaksr <lukeshu@sbcglobal.net>"
+ print "This is free software; see the source for copying conditions."
+ print "There is NO WARRANTY, to the extent permitted by law."
+}
+
+main() {
+ BUILDFILE="$(readlink -m PKGBUILD)"
+ makepkg_opts=()
+ extra_opts=()
+ mode=download-create
+ parse_options "$@"
+
+ # Mode: version, help ##################################################
+
+ if [[ $mode =~ version ]]; then
+ version
+ return 0
+ fi
+ if [[ $mode =~ help ]]; then
+ usage
+ return 0
+ fi
+
+ ########################################################################
+
+ local BUILDFILEDIR="${BUILDFILE%/*}"
+ if [[ -f "${BUILDFILEDIR}/SRCBUILD" ]]; then
+ BUILDFILE="${BUILDFILEDIR}/SRCBUILD"
+ srcbuild="$(modified_srcbuild "$BUILDFILE")"
+ else
+ srcbuild="$(modified_pkgbuild "$BUILDFILE")"
+ fi
+ makepkg="$(modified_makepkg "$(which makepkg)")"
+
+ # Mode: checksums ######################################################
+
+ if [[ $mode =~ checksums ]]; then
+ if [[ ${#extra_opts[@]} != 0 ]]; then
+ print "%s: found extra non-flag arguments: %s" "$cmd" "${extra_opts[*]}" >> /dev/stderr
+ usage >> /dev/stderr
+ return 1
+ fi
+ "$makepkg" "${makepkg_opts[@]}" -g -p "$srcbuild" |
+ case ${BUILDFILE##*/} in
+ PKGBUILD) sed -e 's/^[a-z]/mk&/' -e 's/^\s/ &/';;
+ SRCBUILD) cat;;
+ esac
+ return 0
+ fi
+
+ # Mode: print ##########################################################
+
+ if [[ $mode =~ print ]]; then
+ if [[ ${#extra_opts[@]} != 0 ]]; then
+ print "%s: found extra non-flag arguments: %s" "$cmd" "${extra_opts[*]}" >> /dev/stderr
+ usage >> /dev/stderr
+ return 1
+ fi
+ cat "$srcbuild"
+ return 0
+ fi
+
+ ########################################################################
+
+ local src dst
+ case ${#extra_opts[@]} in
+ 1)
+ src="${extra_opts[0]#*://}"
+ dst="$(readlink -m -- "${src##*/}")"
+ ;;
+ 2)
+ src="${extra_opts[0]#*://}"
+ dst="$(readlink -m -- "${extra_opts[1]}")"
+ ;;
+ *)
+ print "%s: %d non-flag arguments found, expected 1 or 2: %s" "$cmd" ${#extra_opts[@]} >> /dev/stderr
+ usage >> /dev/stderr
+ return 1
+ esac
+
+ # Mode: download #######################################################
+
+ if [[ $mode =~ download ]]; then
+ load_files librefetch
+ check_vars librefetch MIRROR DOWNLOADER || return 1
+
+ local url="${MIRROR}/${src}"
+
+ local dlcmd="${DOWNLOADER}"
+ dlcmd="${dlcmd//\%o/\"$dst\"}"
+ dlcmd="${dlcmd//\%u/\"$url\"}"
+ { eval "$dlcmd"; } >> /dev/stderr && return 0
+ fi
+
+ # Mode: create #########################################################
+
+ if [[ $mode =~ create ]]; then
+ PKGEXT=${dst##*/}
+ export PKGEXT=${PKGEXT%.part}
+ export PKGDEST=${dst%/*}
+ export pkg_file=$dst
+
+ cd "$BUILDFILEDIR"
+ "$makepkg" "${makepkg_opts[@]}" -p "$srcbuild" >> /dev/stderr || return $?
+ fi
+}
+
+# sets the variables BUILDFILE, makepkg_opts, extra_opts, mode
+parse_options() {
+ # Detect makepkg options that take a second argument
+ local makepkg_orig="$(which "${MAKEPKG:-makepkg}")"
+ local makepkg_opt2long=($("${makepkg_orig}" -h | sed -rn 's/\s*(--\S*) <.*/\1/p'))
+ local makepkg_opt2short=($("${makepkg_orig}" -h | sed -rn 's/\s*(-.) <.*/\1/p'))
+
+ local opt
+ local have_opt
+ while [[ $# -gt 0 ]]; do
+ arg=$1
+ have_opt=false
+ if in_array "${arg%%=*}" "${makepkg_opt2long[@]}"; then
+ opt="${arg#*=}"
+ arg="${arg%%=*}"
+ have_opt=true
+ fi
+ if in_array "${arg}" "${makepkg_opt2short[@]}"; then
+ shift
+ opt=$1
+ have_opt=true
+ fi
+ case "$arg" in
+ -C) mode=create;;
+ -D) mode=download;;
+ -g|--geninteg) mode=checksums;;
+ -P|--print) mode=print;;
+ -p) BUILDFILE="$(readlink -m -- "$opt")";;
+ -V|--version) mode=version;;
+ -h|--help) mode=help;;
+ -*)
+ makepkg_opts+=("$arg")
+ $have_opt && makepkg_opts+=("$opt")
+ ;;
+ --) shift; break;;
+ *) extra_opts+=("$arg");;
+ esac
+ shift
+ done
+ extra_opts+=("$@")
+}
+
+# Modify makepkg ###############################################################
+
+# an ERE
+makepkg_modify='
+/create_package\(\) \{/,/^\}$/ {
+ /pkg_file=/d # allow us to set pkg_file
+ s/"?\$\{comp_files\[@\]\}"?// # do not include .{PKGINFO,INSTALL,CHANGELOG}
+ s/bsdtar /&--format=ustar / # ustar, not pax
+ s/create_signature .*/&; return $?/ # do not procede to create symlinks
+}
+
+/tidy_install\(\) \{/,/^\}$/ {
+ /for .*PURGE_TARGETS/itidy_install_purge
+ /for .*PURGE_TARGETS/,/done/d
+ /^\}$/ifind . -exec touch --date="1990-01-01 0:0:0 +0" {} +
+}
+
+s|srcdir=.*|&-libre|
+s|pkgdirbase=.*|&-libre|
+s|check_build_status$|:|
+'
+
+tidy_install_purge() {
+ local pt
+ for pt in "${PURGE_TARGETS[@]}"; do
+ if [[ ${pt} = "${pt%/}" ]]; then
+ if [[ ${pt} = "${pt//\/}" ]]; then
+ find . ! -type d -name "${pt}" -exec rm -f -- '{}' +
+ else
+ rm -f "${pt}"
+ fi
+ else
+ if [[ ${pt%/} = "${pt//\/}" ]]; then
+ find . -type d -name "${pt%/}" -exec rm -rf -- '{}' +
+ else
+ rm -rf "${pt}"
+ fi
+ fi
+ done
+}
+
+modified_makepkg() {
+ local makepkg_orig=$1
+ local makepkg_mine="$tempdir/makepkg"
+ {
+ echo '#!/bin/bash'
+ declare -f tidy_install_purge
+ sed -r "$makepkg_modify" < "$makepkg_orig"
+ } > "$makepkg_mine"
+ chmod 755 "$makepkg_mine"
+ printf "%s\n" "$makepkg_mine"
+}
+
+# Modify PKGBUILD ##############################################################
+
+# a string to be appended
+pkgbuild_append='
+# do not do split packages
+if [[ ${#pkgname[@]} -gt 1 ]]; then
+ if [[ -n $pkgbase ]]; then
+ pkgname=("$pkgbase")
+ else
+ pkgname=("$pkgname")
+ fi
+fi
+
+# copy source variables
+source=("${mksource[@]}")
+noextract=("${mknoextract[@]}")
+md5sums=("${mkmd5sums[@]}")
+sha1sums=("${mksha1sums[@]}")
+sha256sums=("${mksha256sums[@]}")
+sha384sums=("${mksha384sums[@]}")
+sha512sums=("${mksha512sums[@]}")
+
+depends=()
+checkdepends=()
+makedepends=("${mkdepends[@]}")
+
+####
+options+=(!strip docs libtool emptydirs !zipman purge !upx)
+PURGE_TARGETS+=(.bzr/ .cvs/ .git/ .hg/ .svn/ .makepkg/)
+
+####
+if ! declare -f mksource >/dev/null; then
+ mksource() { :; }
+fi
+prepare() { :; }
+build() { mksource; }
+check() { :; }
+package() { cp -a "$srcdir"/*/ "$pkgdir/"; }
+'
+
+modified_pkgbuild() {
+ local pkgbuild=$1
+ local srcbuild="$tempdir/SRCBUILD"
+ printf '%s' "$pkgbuild_append" | cat "$pkgbuild" - > "$srcbuild"
+ printf '%s\n' "$srcbuild"
+}
+
+
+# Modify SRCBUILD ##############################################################
+
+modified_srcbuild() {
+ local orig=$1
+ local new="$tempdir/SRCBUILD"
+ sed -e '/PKGDEST=/d' -e '/PKGEXT=/d' < "$orig" > "$new"
+ printf '%s\n' "$new"
+}
+
+main "$@"
diff --git a/src/librefetch/librefetch.8.ronn b/src/librefetch/librefetch.8.ronn
new file mode 100644
index 0000000..7fa15d4
--- /dev/null
+++ b/src/librefetch/librefetch.8.ronn
@@ -0,0 +1,162 @@
+librefetch(8) -- downloads or creates a liberated source tarball
+================================================================
+
+## SYNOPSIS
+
+`librefetch` [options] <source-url> [<output-file>]<br>
+`librefetch` -[g|V|h]
+
+## DESCRIPTION
+
+`librefetch` is a program to streamline creation of custom source
+tarballs for `PKGBUILD(5)` files.
+
+To automatically use `librefetch` to download or create a source
+tarball, you can add `libre://FILENAME.tar.gz` to the source array in
+your `PKGBUILD`. This works because a post-install script for the
+package adds `librefetch` as a download agent for `libre://` to
+`makepkg.conf`. Because of this, it is almost never necessary to call
+`librefetch` manually.
+
+There are 7 modes:
+
+ * `download-create`: The default mode. First try `download` mode,
+ then `create` mode.
+ * `download`: Download the tarball from the configured mirror.
+ * `create`: Create the tarball from a `PKGBUILD`/`SRCBUILD`.
+ * `checksums`: Generate integrity checks for source files.
+ * `print`: Print the effective build script.
+ * `version`: Print `librefetch` version information.
+ * `help`: Print `librefetch` usage information.
+
+## OPTIONS
+
+ * `-C`: Force `create` mode (don't download)
+ * `-D`: Force `download` mode (don't create)
+ * `-p` <file>: Use an alternate build script for `create` mode
+ (instead of `PKGBUILD`). If an `SRCBUILD` file exists in the same
+ directory, it is used instead.
+ * `-g` | `--geninteg`: Use `checksums` mode: Generate integrity
+ checks for source files.
+ * `-P` | `--print`: Use `print` mode: print the effective build script.
+ * `-V` | `--version`: Use `version` mode: Show version information.
+ * `-h` | `--help`: Use `help` mode: Show useage information.
+
+## CREATE MODE
+
+The principle of `create` mode is that a special `PKGBUILD(5)`, called
+a `SRCBUILD(5)`, installs source files to `$pkgdir`, and the resulting
+"package" is then used as a source tarball. The `SRCBUILD` exists in
+the same directory as the `PKGBUILD`. It can be created manually, or
+generated on-the-fly from the `PKGBUILD`. Extra steps are taken to
+ensure that as long as the same directory contents go in, an identical
+tarball will come out--the checksum of the file should not change
+based on when it is built or who builds it.
+
+The `SRCBUILD` is either created, or sanitized if it already exists,
+then fed to a modified version of `makepkg(8)`.
+
+The purpose of the modified `makepkg` is so that the resulting tarball
+doesn't contain package metadata, doesn't end with a .pkg file
+extension, and always produces an identicle tarball.
+
+When this documentation speaks of a file being modified, it is a
+temporary copy of the file that is modified, your original file will
+remain intact.
+
+## SRCBUILD GENERATION
+
+As explained in the `CREATE MODE` section, in `create` mode, this
+program generates an `SRCBUILD` file. For debugging purposes, this
+file can be printed instead of executed with `print` mode.
+
+### PRE-EXISTING SRCBUILD
+
+The use of `SRCBUILD` files pre-dates `librefetch`. By convention,
+they set `PKGDEST` and `PKGEXT` in `package()` in order to modify the
+behavior of `makepkg`. Because a modified version of `makepkg` is
+used, this interferes with the correct behavior. To compensate for
+this, lines containing "`PKGDEST=`" or "`PKGEXT=`" are deleted from
+the `SRCBUILD`.
+
+The general idea is that `build()` makes any modifications to the
+source, then `package()` copies it from `$srcdir` to `$pkgdir`.
+
+### SRCBUILD FROM PKGBUILD
+
+Possibly more elegant than having a separate `SRCBUILD` file is having
+an `mksource()` function in the main `PKGBUILD`. This results in less
+boilerplate and fewer files to edit.
+
+Note that this only happens if a file named `SRCBUILD` doesn't already
+exist; when migrating a package from a manually created `SRCBUILD` to
+this method, the `SRCBUILD` must be deleted (or renamed) for this to
+work.
+
+The dynamically created `SRCBUILD` is created by copying `PKGBUILD` to
+a temorary file, then re-setting variables and re-defining functions.
+Following is a table of the translations.
+
+ Variables
+ source = mksource
+ noextract = mknoextract
+ *sums = mk*sums (md5, sha1, sha256, sha384, sha512)
+ depends = <empty>
+ checkdepends = <empty>
+ makedepends = mkdepends
+ Functions
+ prepare() { :; }
+ build() { mksource; }
+ check() { :; }
+ package() { cp -a "$srcdir"/*/ "$pkgdir/"; }
+
+The `mksource()` function does not need to be defined. If it isn't
+defined, then no transformations will be made to the source between it
+being extracted to `$srcdir` and copied to `$pkgdir`.
+
+In summary:
+
+ * Set `mksource=()` and `mkmd5sums=(`) to act as `source=(`) and
+ `md5sums=()`
+ * Declare a `mksource()` function to make modifications to the
+ source, if nescessary.
+
+Other changes:
+
+ * `pkgname` is set to `pkgbase`, or the first element of the
+ `pkgname` array.
+ * `options=()` is set have `makepkg` avoid making changes to
+ `$pkgdir`. The exact change is:
+
+ options+=(!strip docs libtool emptydirs !zipman purge !upx)
+
+ * `PURGE_TARGETS=()` has vcs directories added to it:
+
+ PURGE_TARGETS+=(.bzr/ .cvs/ .git/ .hg/ .svn/ .makepkg/)
+
+### MAKEPKG MODIFICATIONS
+
+The following modifications are made to makepkg:
+
+ * Allow us to manipulate the output file (`$pkg_file`)
+ * Do not include metadata in the output file (`${comp_files[@]}`)
+ * Force 'ustar' tar format, don't allow it to upgrade to 'pax' to
+ store extended file attributes.
+ * Don't symlink the resulting file into the current directory.
+ * `PURGE_TARGETS` interprets an item as a directory if it ends with a
+ slash ("/").
+ * Timestamps in `$pkgdir` are reset to "1990-01-01 0:0:0 +0", so that
+ the resulting tarball will be the same, regardless of when it was
+ created.
+ * append `-libre` to `$srcdir`
+ * append `-libre` to `$pkgbasedir` (which becomes `$pkgdir`)
+ * Don't check if the package has already been built.
+
+## CONFIGURATION
+
+See `librefetch.conf(5)` for details on configuring librefetch using
+the `librefetch.conf` file.
+
+## SEE ALSO
+
+librefetch.conf(5), makepkg(8), PKGBUILD(5), SRCBUILD(5)
diff --git a/src/librefetch/librefetch.conf b/src/librefetch/librefetch.conf
new file mode 100644
index 0000000..40d2078
--- /dev/null
+++ b/src/librefetch/librefetch.conf
@@ -0,0 +1,2 @@
+MIRROR='https://repo.parabolagnulinux.org/sources/'
+DOWNLOADER='/usr/bin/curl -fLC - --retry 3 --retry-delay 3 -o %o %u'
diff --git a/src/librefetch/librefetch.conf.5.ronn b/src/librefetch/librefetch.conf.5.ronn
new file mode 100644
index 0000000..3d80ab5
--- /dev/null
+++ b/src/librefetch/librefetch.conf.5.ronn
@@ -0,0 +1,36 @@
+librefetch.conf(5) -- librefetch configuration file
+===================================================
+
+## SYNOPSIS
+
+`/etc/libretools.d/librefetch.conf`, `~/.config/libretools/librefetch.conf`
+
+## DESCRIPTION
+
+Configuration for librefetch is stored in `librefetch.conf`. The
+several places it looks for the file are:
+
+ * `/etc/libretools.d/librefetch.conf`
+ * `$XDG_CONFIG_HOME/libretools/librefetch.conf`
+
+The later files take precidence over earlier files, but earlier files
+are loaded, so that later files only need to set the values they want
+to override.
+
+If `$XDG_CONFIG_HOME` is not set, a default value is set:
+
+ * if `$SUDO_USER` is set: `$(eval echo ~$SUDO_USER)/.config`
+ * else: `$HOME/.config`
+
+## OPTIONS
+
+ * `MIRROR='https://repo.parabolagnulinux.org/sources/'`:
+ The location to download pre-built source tarball in download
+ mode.
+ * `DOWNLOADER='/usr/bin/curl -fLC - --retry 3 --retry-delay 3 -o %o %u'`:
+ The HTTP client to use when downloading pre-built source tarballs
+ in download mode.
+
+## SEE ALSO
+
+librefetch(8)
diff --git a/src/libregit/Makefile b/src/libregit/Makefile
new file mode 100644
index 0000000..2c76089
--- /dev/null
+++ b/src/libregit/Makefile
@@ -0,0 +1 @@
+include ../../common.mk
diff --git a/src/libregit/libregit b/src/libregit/libregit
new file mode 100755
index 0000000..8687d2f
--- /dev/null
+++ b/src/libregit/libregit
@@ -0,0 +1,74 @@
+#!/usr/bin/env bash
+
+# Copyright (c) 2012-2013 Pacman Development Team <pacman-dev@archlinux.org>
+# Copyright (c) 2012-2013 Luke Shumaker <lukeshu@sbcglobal.net>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+. libremessages
+
+cd_safe() {
+ if ! cd "$1"; then
+ error "Failed to change to directory %s" "$1"
+ plain "Aborting..."
+ exit 1
+ fi
+}
+
+download_git() {
+ if [[ ! -d "$dir/.git" ]] ; then
+ msg2 "Cloning %s %s repo..." "${repo}" "git"
+ if ! git clone "$repo" "$dir"; then
+ error "Failure while downloading %s %s repo" "${repo}" "git"
+ plain "Aborting..."
+ exit 1
+ fi
+ else
+ cd_safe "$dir"
+ # Make sure we are fetching the right repo
+ if [[ "$repo" != "$(git config --get remote.origin.url)" ]] ; then
+ error "%s is not a clone of %s" "$dir" "$repo"
+ plain "Aborting..."
+ exit 1
+ fi
+ msg2 "Updating %s %s repo..." "${repo}" "git"
+ if ! git pull origin "$ref"; then
+ # only warn on failure to allow offline builds
+ warning "Failure while updating %s %s repo" "${repo}" "git"
+ fi
+ fi
+}
+
+usage() {
+ print 'Usage: %s repo ref dir' "${0##*/}"
+ echo
+ print "Clones or pulls from the git URL 'repo', and checks out the git ref"
+ print "'ref' to the directory 'dir'."
+ echo
+ print "It does safety checks, figures out whether to clone or pull, and other"
+ print "helpful things. This exists because the same 'download_git' function"
+ print "from makepkg was being copied again and again."
+}
+
+main() {
+ [[ $# == 3 ]] || { usage >&2; return 1; }
+ repo=$1
+ ref=$2
+ dir=$3
+
+ [[ -d "${dir%/*}" ]] || mkdir -p "${dir%/*}"
+ download_git
+}
+
+main "$@"
diff --git a/src/libretools.conf b/src/libretools.conf
new file mode 100644
index 0000000..593aed6
--- /dev/null
+++ b/src/libretools.conf
@@ -0,0 +1,83 @@
+#!/bin/bash # non-executable, but put this there as a hint to text editors
+
+################################################################################
+# misc #
+################################################################################
+
+# The dir where you work on
+WORKDIR=/home/$LIBREUSER/packages
+
+## Blacklist URL
+BLACKLIST=https://repo.parabolagnulinux.org/docs/blacklist.txt
+
+## Diff tool (vimdiff, gvimdiff, meld, etc)
+## Used by `aur`, `diff-unfree`
+DIFFTOOL=`which kdiff3 meld gvimdiff vimdiff colordiff diff 2>/dev/null|sed 's/\s.*//;1q'`
+
+## The repos you'll be packaging for
+## Used by `toru`, `createworkdir`
+# Tip: As early repos take precedence on $REPOS loops, you can use this as
+# inverted order of precedence. Put testing repos first so fullpkg find new
+# PKGBUILDs first, for instance. Toru-path uses reverse order to enforce repo
+# precedence on the path cache (the last path added replaces the rest)
+REPOS=('core' 'libre' 'extra' 'community' 'libre-testing' 'social' 'sugar' 'pcr' 'java')
+
+## The architectures you'll be packaging for
+## Used by `librestage`
+ARCHES=('x86_64' 'i686' 'mips64el')
+
+## ABSLibre
+#ABSLIBREGIT=http://projects.parabolagnulinux.org/abslibre.git
+ABSLIBREGIT=ssh://git@projects.parabolagnulinux.org:1863/srv/git/abslibre.git
+
+################################################################################
+# librerelease #
+################################################################################
+
+## Where to upload packages to
+# Don't change unless you know what you're doing and you won't screw
+# anything ;)
+REPODEST=repo@repo:/srv/http/repo/public
+## Assumes something similar in your .ssh/config:
+# Host repo
+# Port 1863
+# HostName repo.parabolagnulinux.org
+
+## These are run before and after uploading packages
+HOOKPRERELEASE="ssh -fN ${REPODEST%%:*}"
+HOOKPOSTRELEASE="sudo librechroot clean-repo"
+
+################################################################################
+# fullpkg/treepkg #
+################################################################################
+
+# Note: fullpkg accepts HOOK* settings not being set, treepkg requires them to
+# be set.
+
+# NOTE: fullpkg ONLY
+#HOOKPKGBUILDMOD="mips-add"
+
+# Run a command before running FULLBUILDCMD, usually to cleanup uneeded packages
+# Note: Recent versions of libremakepkg run chcleanup for you.
+# NOTE: treepkg ONLY
+HOOKPREBUILD=":"
+#HOOKPREBUILD="chcleanup"
+
+## Uncomment one of those or make one of your choice
+# Normal
+FULLBUILDCMD="sudo libremakepkg"
+# Cross compiling
+#FULLBUILDCMD="sudo libremakepkg -n cross-compile-chroot"
+# Don't use a chroot
+#FULLBUILDCMD="makepkg -sL --noconfirm"
+
+# Locally release the package or any other action after running FULLBUILDCMD
+# succesfully. When run, it is given a repository name as a single argument.
+HOOKLOCALRELEASE="librestage"
+#HOOKLOCALRELEASE="mipsrelease"
+
+################################################################################
+# toru #
+################################################################################
+
+TORUPATH=/var/lib/libretools/toru
diff --git a/src/mips64el-tools/Makefile b/src/mips64el-tools/Makefile
new file mode 100644
index 0000000..2c76089
--- /dev/null
+++ b/src/mips64el-tools/Makefile
@@ -0,0 +1 @@
+include ../../common.mk
diff --git a/src/mips64el-tools/add-mips64el b/src/mips64el-tools/add-mips64el
new file mode 100755
index 0000000..17b167b
--- /dev/null
+++ b/src/mips64el-tools/add-mips64el
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+# Change all arch array that aren't any or mips64el already
+
+find -name 'PKGBUILD' -exec sed -i "s/^\(arch=([^)anym]\+\))/\1 'mips64el')/" '{}' \;
+
+exit $?
diff --git a/src/mips64el-tools/librebasebuilder b/src/mips64el-tools/librebasebuilder
new file mode 100755
index 0000000..6b8c8bb
--- /dev/null
+++ b/src/mips64el-tools/librebasebuilder
@@ -0,0 +1,84 @@
+#!/usr/bin/env bash
+# -*- coding: utf-8 -*-
+# Copyright (C) 2012 Michał Masłowski <mtjm@mtjm.eu>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+set -e
+
+# TODO:
+
+# - make it more configurable
+
+# - compare the result with previous base images
+
+for arg in "$@" ; do
+ case "$arg" in
+ -h|--h|--he|--hel|--help|-\?)
+ echo 'Usage: librebasebuilder
+
+Make a base tarball named parabola-mips64el-DATE.tar.bz2.
+
+This script must be run as root.' >&2
+ exit 0
+ ;;
+ esac
+done
+
+[[ "$UID" != "0" ]] && {
+ echo "This script must be run as root." >&2
+ exit 1
+}
+
+tempdir=/home/chroot/base
+outdir=$(pwd)
+
+archroot -n $tempdir mkinitcpio base sudo parted nano zile vi ed openssh
+
+cd $tempdir
+
+# Don't list mtjm's DNS servers.
+cat > etc/resolv.conf <<EOF
+#
+# /etc/resolv.conf
+#
+
+#search <yourdomain.tld>
+#nameserver <ip>
+
+# End of file
+EOF
+
+# From pacman-mirrorlist-libre-20120307-1. Remember to escape dollars.
+cat > etc/pacman.d/mirrorlist <<EOF
+# Parabola GNU/Linux - Last Updated: Wed Mar 7 17:33:36 GMT 2012
+
+# Atlanta, GA, USA
+# Responsible: belos
+Server = http://parabola.techno-geeks.org/\$repo/os/\$arch
+
+# Nuremberg, Germany
+# Responsible: johkra
+Server = http://parabolaweb.eu/\$repo/os/\$arch
+
+# UK
+# Responsible: Parabola Project
+Server = http://repo.parabolagnulinux.org/\$repo/os/\$arch
+
+EOF
+
+rm .arch-chroot
+
+tar cjf $outdir/parabola-mips64el-$(LC_ALL=C date -u +%Y%m%d).tar.bz2 .
diff --git a/src/mips64el-tools/mips-add b/src/mips64el-tools/mips-add
new file mode 100755
index 0000000..402036e
--- /dev/null
+++ b/src/mips64el-tools/mips-add
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+. libremessages
+if ! grep mips64el PKGBUILD >/dev/null; then # Add mips64el in ${arch} array if it isn't 'any'
+ warning "Adding mips64el arch"
+ sed -i "s/^\(arch=([^)anym]\+\))/\1 'mips64el')/" "PKGBUILD"
+ git add PKGBUILD
+ git commit
+fi
diff --git a/src/mips64el-tools/mipsrelease b/src/mips64el-tools/mipsrelease
new file mode 100755
index 0000000..a8c2db6
--- /dev/null
+++ b/src/mips64el-tools/mipsrelease
@@ -0,0 +1,61 @@
+#!/usr/bin/env bash
+# Lic: GPLv3+
+# Author: Nicolas Reynolds <fauno@kiwwwi.com.ar>
+# Local release of mips64el packages + clean ABS sync
+# Called by HOOKLOCALRELEASE
+
+# $1 repo
+# $2+ packages
+
+. libremessages
+. $(librelib conf.sh)
+load_files makepkg
+check_vars makepkg CARCH PKGDEST PKGEXT || exit 1
+load_files libretools
+check_vars libretools WORKDIR || exit 1
+
+usage() {
+ echo "$0 repo"
+ echo
+ echo " release packages locally on \${PKGDEST}/stage3."
+ echo " and make a clean ABS sync "
+}
+
+main() {
+ if [[ $# != 1 ]]; then
+ usage
+ exit 1
+ fi
+
+ repo=$1
+
+ if [ -z "${repo}" ]; then
+ error "Empty repo"
+ exit 1
+ fi
+
+ # Get all needed sources
+ load_PKGBUILD
+ pkgs=()
+ makepkg --source -f --skippgpcheck
+
+ msg "Adding packages to [stage3]..."
+ for name in "${pkgname[@]}"; do
+ msg2 "${name} $(get_full_version $name)"
+ pkgs+=(${PKGDEST}/${name}-$(get_full_version $name)-*.pkg.tar.*)
+ done
+
+ repo-add ${PKGDEST}/stage3.db.tar.gz "${pkgs[@]}"
+
+ librestage ${repo}
+
+ mkdir -p ${WORKDIR}/abs/${CARCH}/${repo} >/dev/null
+
+ pushd ${WORKDIR}/abs/${CARCH}/${repo} >/dev/null
+ tar xvf $SRCPKGDEST/${pkgbase:-${pkgname[0]}}-$(get_full_version)${SRCEXT}
+ popd >/dev/null
+
+ exit $?
+}
+
+main "$@"
diff --git a/src/pkgbuild-check-licenses b/src/pkgbuild-check-licenses
new file mode 100755
index 0000000..85ca2c3
--- /dev/null
+++ b/src/pkgbuild-check-licenses
@@ -0,0 +1,126 @@
+#!/usr/bin/env bash
+# pkgbuild-check-licenses
+
+# Copyright 2010 Haase Hernández
+# Copyright 2010 Joseph Graham
+# Copyright 2010 Joshua Ismael
+# Copyright 2010 Nicolás Reynolds
+# Copyright 2012-2013 Luke Shumaker
+#
+# This file is part of Parabola.
+#
+# Parabola is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Parabola is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Parabola. If not, see <http://www.gnu.org/licenses/>.
+
+. libremessages
+. $(librelib conf)
+
+# Usage: check_deps $pkgbuild
+# Check whether a PKGBUILD package depends on non-free packages
+check_licenses() (
+ # Note that we use () instead of {} for this function; so that variables
+ # from the PKBUILD don't bubble up
+ local pkgbuild=$1
+ load_PKGBUILD "$pkgbuild"
+ if [[ -z $pkgname ]]; then
+ return $_E_ERROR # not a PKGBUILD
+ fi
+ if [[ -z "${license[*]}" ]]; then
+ error "license array of %s %s is not set" "${pkgbase:-${pkgname[0]}}" "$(get_full_version)"
+ return $_E_ERROR
+ fi
+
+ msg2 "Looking at license array of %s %s" "${pkgbase:-${pkgname[0]}}" "$(get_full_version)"
+
+ local ret=$_E_OK
+ for _license in "${license[@]}"; do
+ if [[ ! -e "/usr/share/licenses/common/$_license" ]]; then
+ local s=$_E_OK
+ case "${_license#custom:}" in
+ WTFPL)
+ # accept as common, I think it should be in the licenses package
+ :;;
+ BSD1|BSD2|BSD3|MIT|X11)
+ # accept these as common; they can't be included in the
+ # 'licenses' package because some text must be customized
+ :;;
+ BSD4)
+ warning "The 4-clause BSD license is free but has practical problems.";;
+ BSD)
+ warning "License 'BSD' is ambiguous, use 'BSD{1..4}' to specify the number of clauses."
+ s=$_E_UNCOMMON
+ ;;
+ JSON)
+ error "License '%s' is a known non-free license." "$_license"
+ s=$_E_NONFREE
+ ;;
+ *)
+ warning "License '%s' is not a common license." "$_license"
+ s=$_E_UNCOMMON
+ ;;
+ esac
+ ret=$(($ret|$s))
+ fi
+ done
+ return $ret
+)
+
+usage() {
+ print "Usage: %s [OPTIONS] [PKGBUILD1 PKGBUILD2 ...]" "${0##*/}"
+ echo
+ prose 'If no PKGBUILD is specified, `./PKGBUILD` is implied.'
+ echo
+ print "Exit status (add them for combinations):"
+ print " 0: Everything OK, no freedom issues"
+ print " 1: Ran with error"
+ print " 2: Uses uncommon licenses, check them"
+ print " 4: Uses known unacceptable licenses"
+ echo
+ print "Options:"
+ flag '-f' 'Allow running as root user'
+ flag '-h' 'Show this message'
+}
+_E_OK=0
+_E_ERROR=1
+_E_UNCOMMON=2
+_E_NONFREE=4
+
+main() {
+ local asroot=false
+ while getopts 'fh' arg; do
+ case "$arg" in
+ f) asroot=true;;
+ h) usage; return $_E_OK;;
+ *) usage; return $_E_ERROR;;
+ esac
+ done
+ shift $(($OPTIND - 1))
+ if [[ $# -lt 1 ]]; then
+ pkgbuilds=("`pwd`/PKGBUILD")
+ else
+ pkgbuilds=("$@")
+ fi
+
+ if [[ -w / ]] && ! $asroot; then
+ error "Run as normal user, or use the -f option to run as root."
+ return 1
+ fi
+
+ local ret=0
+ for pkgbuild in "${pkgbuilds[@]}"; do
+ check_licenses "$pkgbuild" || ret=$(($ret|$?))
+ done
+ return $ret
+}
+
+main "$@"
diff --git a/src/pkgbuild-check-nonfree b/src/pkgbuild-check-nonfree
new file mode 100755
index 0000000..1cc0d9b
--- /dev/null
+++ b/src/pkgbuild-check-nonfree
@@ -0,0 +1,121 @@
+#!/usr/bin/env bash
+# pkgbuild-check-nonfree
+
+# Copyright 2010 Haase Hernández
+# Copyright 2010 Joseph Graham
+# Copyright 2010 Joshua Ismael
+# Copyright 2012-2013 Luke Shumaker
+#
+# This file is part of Parabola.
+#
+# Parabola is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Parabola is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Parabola. If not, see <http://www.gnu.org/licenses/>.
+
+. libremessages
+. libreblacklist
+. $(librelib conf)
+
+# Usage: check_deps $pkgbuild
+# Check whether a PKGBUILD package depends on non-free packages
+check_deps() (
+ # Note that we use () instead of {} for this function; so that variables
+ # from the PKBUILD don't bubble up
+ local pkgbuild=$1
+ load_PKGBUILD "$pkgbuild"
+ if [[ -z "$pkgname" ]]; then
+ exit 1 # not a PKGBUILD
+ fi
+
+ msg2 'Looking for unfree dependencies of %s %s' "${pkgbase:-${pkgname[0]}}" "$(get_full_version)"
+
+ local pkgs=(
+ # packages being built
+ "${pkgname[@]}"
+ # depends
+ "${depends[@]}" "${makedepends[@]}" "${checkdepends[@]}" "${optdepends[@]%%:*}"
+ # mksource depends
+ "${mkdepends[@]}"
+ )
+ local ret=0
+ for pkg in "${pkgs[@]}"; do
+ local line="$(blacklist-cat|blacklist-lookup "$pkg")"
+ local rep="$(blacklist-get-rep <<<"$line")"
+ if [[ -z $line ]]; then
+ # not mentioned in blacklist; free
+ plain '%s: not blacklisted' "$pkg"
+ continue
+ elif [[ -z $rep ]]; then
+ # non-free with no replacement
+ plain '%s: blacklisted' "$pkg"
+ ret=1
+ else
+ # non-free with free replacement
+ if [[ "$rep" == "$pkg" ]]; then
+ plain '%s: repackaged with the same name' "$pkg"
+ else
+ plain '%s: replaced by %s' "$pkg" "$rep"
+ fi
+ fi
+ done
+ return $ret
+)
+
+usage() {
+ print "Usage: %s [OPTIONS] [PKGBUILD1 PKGBUILD2 ...]" "${0##*/}"
+ echo
+ prose 'If no PKGBUILD is specified, `./PKGBUILD` is implied.'
+ echo
+ print "Exit status:"
+ print " 0: Everything OK, no freedom issues"
+ print " 1: Ran with error"
+ print " 15: Depends on non-free packages"
+ echo
+ print "Options:"
+ flag '-c' 'Use the cached blacklist, do not try downloading.'
+ flag '-f' 'Allow running as root user'
+ flag '-h' 'Show this message'
+}
+
+main() {
+ local asroot=false
+ local cache=false
+ while getopts 'cfh' arg; do
+ case "$arg" in
+ c) cache=true;;
+ f) asroot=true;;
+ h) usage; return 0;;
+ *) usage; return 1;;
+ esac
+ done
+ shift $(($OPTIND - 1))
+ if [[ $# -lt 1 ]]; then
+ pkgbuilds=("`pwd`/PKGBUILD")
+ else
+ pkgbuilds=("$@")
+ fi
+
+ if [[ -w / ]] && ! $asroot; then
+ error "Run as normal user, or use the -f option to run as root."
+ return 1
+ fi
+
+ $cache || blacklist-update || return 1
+
+ local ret=0
+ for pkgbuild in "${pkgbuilds[@]}"; do
+ check_deps "$pkgbuild" || ret=15
+ done
+ return $ret
+}
+
+main "$@"
diff --git a/src/toru/Makefile b/src/toru/Makefile
new file mode 100644
index 0000000..2c76089
--- /dev/null
+++ b/src/toru/Makefile
@@ -0,0 +1 @@
+include ../../common.mk
diff --git a/src/toru/toru b/src/toru/toru
new file mode 100755
index 0000000..3c45efd
--- /dev/null
+++ b/src/toru/toru
@@ -0,0 +1,301 @@
+#!/usr/bin/env 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 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 $?
+}
+
+# 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 $_pkg))
+ 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..d73d2ad
--- /dev/null
+++ b/src/toru/toru-info
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+# Prints info about a given pkgname
+. libremessages
+. $(librelib conf)
+
+for _pkg in $@; do
+ _pkgbuild="$(toru-where $_pkg)"
+
+ if [ -f "$_pkgbuild/PKGBUILD" ]; then
+ load_PKGBUILD "$_pkgbuild/PKGBUILD" 2>/dev/null || {
+ warning "Errors on %s" $_pkg
+ continue
+ }
+
+ deps="${depends[@]} ${makedepends[@]} ${checkdepends[@]}"
+ repo="$(basename $(dirname "$_pkgbuild"))"
+
+ msg "%s/%s %s-%s" $repo $_pkg $pkgver $pkgrel
+ msg2 "$pkgdesc"
+ msg2 "$url"
+ msg2 "Depends: ${deps}"
+ else
+ warning "%s doesn't exist" $_pkg
+ fi
+done
diff --git a/src/toru/toru-path b/src/toru/toru-path
new file mode 100755
index 0000000..6c86e88
--- /dev/null
+++ b/src/toru/toru-path
@@ -0,0 +1,48 @@
+#!/usr/bin/env bash
+
+source 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]}
+
+ [ -d "${ABSROOT}${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"
+ load_PKGBUILD "${_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
+done
+
+lastsync ${LASTSYNCFILE}
diff --git a/src/toru/toru-utils b/src/toru/toru-utils
new file mode 100755
index 0000000..96aa35e
--- /dev/null
+++ b/src/toru/toru-utils
@@ -0,0 +1,64 @@
+#!/usr/bin/env bash
+
+. libremessages
+. $(librelib conf.sh)
+load_files libretools
+check_vars libretools TORUPATH || exit 1
+
+LASTSYNCFILE=${TORUPATH}/lastsync
+FORCE=false
+QUIET=false
+DEBUG=false
+
+# 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..4b3ff1b
--- /dev/null
+++ b/src/toru/toru-where
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+# Locates a PKGBUILD dir on toru's path cache
+. $(librelib conf.sh)
+load_files libretools
+check_vars libretools TORUPATH || exit 1
+
+PATHFILE=${TORUPATH}/paths.tch
+
+tcamgr get ${PATHFILE} $1 2>/dev/null || echo ""
diff --git a/src/treepkg b/src/treepkg
new file mode 100755
index 0000000..8219ce6
--- /dev/null
+++ b/src/treepkg
@@ -0,0 +1,224 @@
+#!/usr/bin/env bash
+#set -x
+# (c) 2012 Nicolás Reynolds <fauno@parabola.nu>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+source libremessages
+source $(librelib conf.sh)
+
+load_files libretools
+check_vars libretools HOOKPREBUILD FULLBUILDCMD HOOKLOCALRELEASE
+load_files makepkg
+
+term_title "$(basename $0)"
+
+# End inmediately but print an useful message
+trap_exit() {
+ term_title "error!"
+ error "($(basename $0)) $@ (leftovers on ${BUILDDIR})"
+ 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
+
+# Add line to build order cache in CSV format
+# *must* be run from the PKGBUILD path
+# status;depth;pkgbase;[epoch:]pkgver-pkgrel;path;repo
+# $1 status
+# $2 pkgname
+add_order() {
+ echo "${1};${DEPTH};${2:-${pkgbase}};$(get_full_version ${2});${PWD};$(guess_repo "$PWD")" >> "${BUILDORDER}"
+ ${VERBOSE} && msg2 "%${DEPTH}s${2:-${pkgbase}} [${1}]" || true
+}
+
+# Bury a package deeper in the tree
+# $1 pkgbase
+# $2 nextdepth
+bury() {
+ # Bury only if we are going to build the dep
+ # Get it's current depth and dir name
+ local current_depth=$(grep "build;[0-9]\+;${1};" "${BUILDORDER}" | cut -d ';' -f 2)
+ local current_name="$(printf "%03d" ${current_depth})_${1}"
+
+ # If there's a depth or the package is not the root of the build tree (which
+ # can lead to funny chicken-and-egg problems), update the depth to the current
+ # package next-depth and rename the dir too
+ if [ -z "${current_depth}" ]; then return; fi
+ if [ -z "${current_name}" ]; then return; fi
+ if [ ${current_depth} -eq 0 ]; then return; fi
+ if [ ${current_depth} -ge $2 ]; then return; fi
+
+ ${VERBOSE} && msg "Burying ${1} from ${current_depth} to ${2}"
+
+ {
+ sed -i "s|^\(build;\)\([0-9]\+\)\(;${1};.*\)$|\1${2}\3|" "${BUILDORDER}" && \
+ mv "${BUILDDIR}/${current_name}" "${BUILDDIR}/$(printf "%03d" ${2})_${1}"
+ } || return 1
+}
+
+# Guess the repo from the pkgbase path
+# $1 path, pwd or toru-where
+guess_repo() {
+ basename "$(dirname "${1}")"
+}
+
+if [ ! -f PKGBUILD ]; then
+ error "Missing PKGBUILD ($PWD)"
+ exit 1
+fi
+
+if ! load_PKGBUILD ; then
+ error "Can't source PKGBUILD"
+ exit 1
+fi
+
+# Save resources
+unset pkgdesc arch license groups backup install md5sums sha1sums \
+ sha256sums source options >/dev/null 2>&1
+
+unset build package >/dev/null 2>&1
+
+for _pkg in "${pkgname[@]}"; do
+ unset package_${_pkg} >/dev/null 2>&1 || true
+done
+##
+
+# Get useful values
+pkgbase="${pkgbase:-${pkgname[0]}}"
+
+# Get or set the work dir
+BUILDDIR="${1:-$(mktemp -d /tmp/${pkgbase}-treepkg-XXXx)}"
+BUILDORDER="${BUILDDIR}/BUILDORDER"
+DEPTH=${2:-0}
+NEXTDEPTH=$((${DEPTH} + 1))
+# This can be set as env vars (ie: $ V=false B=false treepkg)
+# TODO Turn into flags?
+VERBOSE=${V:-true}
+BUILD=${B:-true}
+CLEANUP=${C:-true}
+# Skip BUILDORDER creation and build anything on BUILDDIR
+BUILDNOW=${N:-false}
+
+if [[ ! -z $1 ]] && [[ $DEPTH -eq 0 ]]; then
+ BUILDNOW=true
+fi
+
+if ! ${BUILDNOW}; then
+ # ensure it exists
+ touch "${BUILDORDER}"
+
+ # If this package is already built quit silently
+ for _pkg in "${pkgname[@]}"; do
+ if is_built "${_pkg}" "$(get_full_version ${_pkg})"; then
+ add_order "ignore"
+ exit 0
+ fi
+ done
+
+ # Ignore if already in build order
+ egrep -q ";${pkgbase};" "${BUILDORDER}" && exit 0
+
+ # Add pkgbase to build order
+ add_order "build"
+
+ # Copy the directory to the build dir
+ # TODO run makepkg --source to avoid moving garbage around?
+ cp -r "${PWD}" "${BUILDDIR}/$(printf "%03d" ${DEPTH})_${pkgbase}"
+
+ # Cleanup dep versioning
+ deps=($(echo "${depends[@]} ${makedepends[@]}" | \
+ sed "s/[=<>]\+[^ ]\+//g" | \
+ tr ' ' "\n" | \
+ sort -u))
+
+ # NOTE: getting depends from package() is a PITA
+ for _dep in "${deps[@]}"; do
+ # Move deps deeper in the tree if
+ # pkgbase - dep1
+ # \ dep2 - dep1
+ # dep1 should be depth + 1
+ egrep -q ";${_dep};" "${BUILDORDER}" && bury "${_dep}" ${NEXTDEPTH}
+
+ # Ask toru where's a PKGBUILD
+ depdir="$(toru-where ${_dep})"
+
+ if [[ -z ${depdir} ]] || [[ ! -d ${depdir} ]]; then
+ # We specify the pkgname because we can't source the dep PKGBUILD
+ # Normally 'any' packages are missing from our work ABS
+ add_order "missing" "${_dep}"
+ continue
+ fi
+
+ pushd "${depdir}" >/dev/null
+
+ # Run itself over dependencies
+ $0 "${BUILDDIR}" ${NEXTDEPTH}
+
+ done
+ # End BUILD now
+fi
+
+# Only build at the end
+if [ ${DEPTH} -eq 0 ]; then
+ ${VERBOSE} && msg "Starting build" || true
+
+ if ${BUILD}; then
+ ${VERBOSE} && msg "Build tree stored in ${BUILDORDER}" || true
+
+ # Build everything sorting the build dir
+ # The reverse order ensures we start by the deepest packages
+ for _pkg in $(ls -r "${BUILDDIR}"); do
+ # Ignore if there's no PKGBUILD
+ if [ ! -f "${BUILDDIR}/${_pkg}/PKGBUILD" ]; then continue; fi
+ # Skip if already built (faster than calling is_build again)
+ if [ -f "${BUILDDIR}/${_pkg}/built_ok" ]; then continue; fi
+
+ ${VERBOSE} && msg "Building ${_pkg/_/ }" || true
+
+ # Remove leading zeros and space if any
+ term_title "$(echo ${_pkg/_/ } | sed "s/^0\+ \?//")"
+
+ # Run build command
+ pushd "${BUILDDIR}/${_pkg}" >/dev/null
+ sudo -E pacman -Syu --noconfirm
+
+ ${HOOKPREBUILD}
+
+ ${FULLBUILDCMD}
+ # Run local release hook with $1 = $repo
+ ${HOOKLOCALRELEASE} $(egrep ";${_pkg#*_};" "${BUILDORDER}" | cut -d';' -f6)
+
+ touch built_ok
+ popd >/dev/null
+ done
+
+ else
+ # Just print the working dir
+ ${VERBOSE} || echo "${BUILDORDER}" || true
+ fi
+
+ if ${CLEANUP} ; then
+ msg2 "Removing ${BUILDDIR}"
+ rm -rf "${BUILDDIR}"
+ fi
+
+fi
+
+term_title "done"
+exit $?