diff options
Diffstat (limited to 'src')
53 files changed, 4415 insertions, 0 deletions
diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..ff8d399 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,3 @@ +libre_execdir=$(bindir) +libre_datadir=$(sysconfdir) +include ../common.mk diff --git a/src/abslibre-tools/Makefile b/src/abslibre-tools/Makefile new file mode 100644 index 0000000..f2cec54 --- /dev/null +++ b/src/abslibre-tools/Makefile @@ -0,0 +1,3 @@ +libre_execdir=$(bindir) +libre_datadir=$(sysconfdir)/libretools.d +include ../../common.mk diff --git a/src/abslibre-tools/createworkdir b/src/abslibre-tools/createworkdir new file mode 100755 index 0000000..b443c08 --- /dev/null +++ b/src/abslibre-tools/createworkdir @@ -0,0 +1,63 @@ +#!/bin/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/>. + +source /etc/libretools.conf +custom_config=$XDG_CONFIG_HOME/libretools/libretools.conf +[[ -e $custom_config ]] && source $custom_config + +[[ ! -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/libreaddiff b/src/abslibre-tools/libreaddiff new file mode 100755 index 0000000..98646a2 --- /dev/null +++ b/src/abslibre-tools/libreaddiff @@ -0,0 +1,97 @@ +#!/bin/bash +# -*- 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/>. + + +set -e + +. /etc/libretools.conf +custom_config=$XDG_CONFIG_HOME/libretools/libretools.conf +[ -e $custom_config ] && . $custom_config + +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 + unset pkgname + unset epoch + unset pkgver + unset pkgrel + unset arch + . $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..efb698e --- /dev/null +++ b/src/abslibre-tools/librerelease @@ -0,0 +1,155 @@ +#!/bin/bash +# Librerelease +# Uploads packages into [staging] + +# 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/>. + +source /etc/libretools.conf +custom_config=$XDG_CONFIG_HOME/libretools/libretools.conf + +function usage { + echo "$(gettext "Usage: $0")" + echo + echo "$(gettext "This script uploads packages on $WORKDIR/stagging")" + echo "$(gettext "to parabola server.")" + echo + echo "$(gettext "OPTIONS:")" + echo "$(gettext " -h this message.")" + echo "$(gettext " -l only list packages but not upload them.")" + echo "$(gettext " -c clean packages on $WORKDIR/staging.")" + echo "$(gettext " -n dry-run")" +} + +function list_packages { + repos=($(find "$WORKDIR/staging/" -mindepth 1 -type d \! -empty -printf '%f ' 2>/dev/null)) + for _repo in ${repos[@]}; do + msg2 "$_repo" + find ${WORKDIR}/staging/${_repo} -type f -printf "%f\n" + done + unset repos +} + +function sign_packages { + if [ -z "${SIGEXT}" ]; then + SIGEXT=.sig + warning "Empty SIGEXT var, using default .sig" + fi + + if [ -z "${GPG_AGENT_INFO}" ]; then + warning "It's better to use gpg-agent to sign packages in batches" + fi + + packages=($(find "${WORKDIR}/staging/" -type f -iname '*.pkg.tar.?z')) + for package in ${packages[@]}; do + if [ -f "${package}${SIGEXT}" ]; then + + warning "Package signature found, verifying..." + +# Verify that the signature is correct, else remove for re-signing + if ! gpg --quiet --verify "${package}${SIGEXT}" >/dev/null 2>&1; then + error "Failed! Resigning..." + rm -f "${package}${SIGEXT}" + fi + fi + + msg2 "Signing ${package}..." + gpg --default-key "${SIGID}" --output "${package}${SIGEXT}" \ + --detach-sig "${package}" || { + error "Signing failed" + exit 2 + } + + 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 { + [ -z ${dryrun} ] && \ + rm -f $@ +} + +if [ -w / ]; then + error "Run $0 as normal user" + exit 1 +fi + +while getopts 'hlcn' arg; do + case $arg in + h) usage; exit 0 ;; + l) list_packages; exit 0 ;; + c) clean; exit $? ;; + n) dryrun="--dry-run" ;; + esac +done + +[[ -e $custom_config ]] && source $custom_config + +[[ ! -z ${HOOKPRERELEASE} ]] && bash -c "${HOOKPRERELEASE}" + +clean_non_packages +if [ ! -z "${SIGID}" ]; then + sign_packages +else + error "Package signing is *required*, please set SIGID on your libretools.conf" + exit 1 +fi + +# 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 {} \; + +# Get the synced files +SYNCED_FILES=($(find ${WORKDIR}/staging -type f)) + +msg "%s to upload" $(du -h -d 0 ${WORKDIR}/staging | tr "\t" " " | cut -d" " -f1) +msg "Uploading packages..." +rsync --recursive \ + ${dryrun} \ + --no-group \ + --no-perms \ + --copy-links \ + --hard-links \ + --partial \ + --prune-empty-dirs \ + --human-readable \ + --progress \ + -e "ssh " \ + ${WORKDIR}/staging \ + ${PARABOLAHOST}:${LIBREDESTDIR}/ || { + error "Sync failed, try again" + exit 1 + } + +msg "Removing ${#SYNCED_FILES[@]} files from local [staging]" +clean ${SYNCED_FILES[@]} + +msg "Running db-update on repos" +ssh ${PARABOLAHOST} dbscripts/db-update + +exit 0 diff --git a/src/abslibre-tools/librestage b/src/abslibre-tools/librestage new file mode 100755 index 0000000..ae66cce --- /dev/null +++ b/src/abslibre-tools/librestage @@ -0,0 +1,137 @@ +#!/bin/bash +# LibreStage +# Prepares packages for upload into [staging] + +# 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/>. + + +source /etc/libretools.conf +custom_config=$XDG_CONFIG_HOME/libretools/libretools.conf +[[ -e $custom_config ]] && source $custom_config + +if [ -w / ]; then + error "This script should be run as regular user" + exit 1 +fi + + +# End Config + +usage() { + cat <<EOU +LibreStage Copyright (C) 2011 Nicolás Reynolds +This program comes with ABSOLUTELY NO WARRANTY. +This is free software, and you are welcome to redistribute it +under the terms of the GNU General Public License version 3 or later. + + +Usage: $(basename $0) <repo> [<repo2> ... ] + +LibreRelease will stage for upload the package(s) built by the PKGBUILD on +the current directory to the specified repo(s). +EOU +} + +repos=$@ + +while getopts 'h' arg; do + case $arg in + h) usage; exit 0 ;; + esac +done + +if [ ${#repos} -eq 0 ]; then + usage + exit 1; +fi + +[[ ! -e ./PKGBUILD ]] && { + error "PKGBUILD not found" + exit 1 +} + +# Source the needed files +source /etc/makepkg.conf +[[ -e ~/.makepkg.conf ]] && source ~/.makepkg.conf +source ./PKGBUILD +[[ -e ./rePKGBUILD ]] && source ./rePKGBUILD + +# Default package location +PKGDEST=${PKGDEST:-.} +SRCPKGDEST=${SRCPKGDEST:-.} + +PKGEXT=".pkg.tar.?z" + +staged=false +# Copies the packages to the specified repos inside staging +for _arch in ${ARCHES[@]}; do + for pkg in ${pkgname[@]}; do + + pkgpath=$(find ${PKGDEST}/ -type f \ + -name "${pkg}-$(get_full_version "${pkg}")-${_arch}${PKGEXT}") + + [[ -z ${pkgpath} ]] && continue + + pkgfile=$(basename ${pkgpath}) + +# TODO refactor this + if [ -e "${pkgpath}" ]; then + msg "Found ${pkgfile}" + + canonical="" + for _repo in ${repos[@]}; do + + if [ ! -d "${WORKDIR}/staging/${_repo}" ]; then + warning "[${_repo}] didn't exist, creating..." + mkdir -p "${WORKDIR}/staging/${_repo}" + fi + + if [ -z "$canonical" ]; then + canonical="${WORKDIR}/staging/${_repo}/${pkgfile}" + + cp "${pkgpath}" "${WORKDIR}/staging/${_repo}/" || { + error "Can't put ${pkgfile} on [staging]" + exit 1 + } && { + msg2 "${pkg} staged on [${_repo}]" + staged=true + } + + else + ln "${canonical}" "${WORKDIR}/staging/${_repo}/${pkgfile}" || { + error "Can't put ${pkgfile} on [staging]" + exit 1 + } && { + msg2 "${pkg} staged on [${_repo}]" + staged=true + } + + fi + done + fi + done +done + +if ! $staged ; then + error "No package was staged" + exit 1 +fi + +exit 0 @@ -0,0 +1,133 @@ +#!/bin/bash +# Copyright 2010 Nicolás Reynolds, Joshua Ismael + +# ---------- 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/>. + +. /etc/libretools.conf +. /etc/abs.conf + +cmd=${0##*/} + +usage() { + echo "Usage: $cmd pkgname-from-aur1 [pkgname-from-aur2 ...]" + echo + echo "This script will download packages from aur to the current dir" + echo "and check their license for nonfree issues." +} + +main() { + while getopts 'h' arg; do + case $arg in + h) usage; exit 0;; + *) usage; exit 1;; + esac + done + + local missing_deps=() + for _pkg in "$@"; do + + # Remove the version + _pkg="${_pkg%%[<>=]*}" + + if [[ -f "${_pkg}/PKGBUILD" ]]; then + warning "${_pkg} already existed." + + # Check if we want to diff + if [[ -z "${DIFFTOOL}" ]]; then + continue + else + # Store our copy of the PKGBUILD dir + _diff="${PWD}/${_pkg}" + stdnull "pushd $(mktemp --tmpdir -d ${_pkg}.XXXX)" + msg2 "Downloading PKGBUILD into ${PWD} for diff" + fi + fi + + msg "Downloading $_pkg..." + local url=https://aur.archlinux.org/packages/${_pkg:0:2}/${_pkg}/$_pkg.tar.gz + wget -O - -q "$url" | tar xzf - >/dev/null 2>&1 + + if [[ $? -ne 0 ]]; then + error "Couldn't get $_pkg" + continue + fi + + stdnull "pushd $_pkg" + + if [[ ! -z "$_diff" ]]; then + msg2 "Diffing files" + # Diff all files with our difftool + for file in *; do + "${DIFFTOOL}" "${_diff}/${file}" "${file}" + done + + # Go back to our copy to continue working + stdnull "pushd ${_diff}" + fi + + . PKGBUILD + + ################################################################ + + if ! pkgbuild-check-nonfree; then + if [[ $? = 15 ]]; then + warning "This PKGBUILD links to known unfree packages" + fi + fi + + ################################################################ + + msg2 "Checking license..." + local free=0 + for _license in ${license[@]}; do + if [[ ! -d /usr/share/licenses/common/$_license ]]; then + warning "License $_license is not a common license" + free=1 + fi + done + + if [[ $free -eq 1 ]]; then + plain "Please check that the license is included in the package and *specially* that it respects your freedom." + fi + + ################################################################ + + for _dep in "${depends[@]}" "${makedepends[@]}"; do + _dep=${_dep/[<>=]*/} + if ! is_built $_dep; then + if ! find ${ABSROOT} -maxdepth 2 -type d -name "$_dep" | egrep "*" >/dev/null ; then + msg2 "$_dep will be get from AUR" + missing_deps+=($_dep) + fi + else + msg2 "$_dep is on repos" + fi + done + + stdnull popd + done + + [[ ${#missing_deps[*]} -gt 0 ]] && { + msg2 "Retrieving missing deps: ${missing_deps[@]}" + $0 ${missing_deps[@]} + } + + exit 0 +} + +main "$@" diff --git a/src/chroot-tools/Makefile b/src/chroot-tools/Makefile new file mode 100644 index 0000000..3ae95ea --- /dev/null +++ b/src/chroot-tools/Makefile @@ -0,0 +1,3 @@ +libre_execdir=$(sbindir) +libre_datadir=$(sysconfdir)/libretools.d +include ../../common.mk diff --git a/src/chroot-tools/chcleanup b/src/chroot-tools/chcleanup new file mode 100755 index 0000000..821c572 --- /dev/null +++ b/src/chroot-tools/chcleanup @@ -0,0 +1,57 @@ +#!/bin/bash -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} +source "$(which libremessages)" + +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 + source PKGBUILD + CHROOTEXTRAPKG+=("${depends[@]}" + "${makedepends[@]}" + "${checkdepends[@]}") +fi + +msg "Cleaning chroot..." + +TEMPDIR="$(mktemp --tmpdir -d $(basename $0).XXXXX)" +cp -a /var/lib/pacman/sync "${TEMPDIR}/" +cleanup_log="${TEMPDIR}"/libretools-cleanup.log + +# Get the full list of packages needed by dependencies, including the base system +pacman -b "${TEMPDIR}" \ + -Sp --print-format "%n" \ + base base-devel sudo "${CHROOTEXTRAPKG[@]}" \ + >"${cleanup_log}" + +# Diff installed packages against a clean chroot then remove leftovers +packages=($(comm -23 <(pacman -Qq | sort -u) \ + <(sort -u "${cleanup_log}"))) + +RET=0 +if [[ ${#packages[@]} != 0 ]]; then + msg2 "Removing %d packages" ${#packages[@]} + + if ${DRYRUN}; then + echo "${packages[@]}" + else + # Only remove leftovers, -Rcs removes too much + pacman --noconfirm -Rn "${packages[@]}" || RET=$? + fi +fi +# Cleanup +rm -rf "${TEMPDIR}" + +exit $RET diff --git a/src/chroot-tools/chroot.conf b/src/chroot-tools/chroot.conf new file mode 100644 index 0000000..d84e8b4 --- /dev/null +++ b/src/chroot-tools/chroot.conf @@ -0,0 +1,13 @@ +# The full path to the chroot is +# $CHROOTDIR/$CHROOT/$CHROOTCOPY +# where $CHROOTCOPY is set at runtime, either +# - based on the username +# - set with the `-l COPY` flag +# The purpose of having a $CHROOT setting is that multiple clones of the same +# base $CHROOT can quickly and easily be created. +CHROOTDIR=/var/lib/archbuild +CHROOT=default + +# Extra packages to have installed on the chroot. +# This is in addition to CHROOTPKG=(base base-devel sudo) +CHROOTEXTRAPKG=(distcc ccache tsocks libretools) diff --git a/src/chroot-tools/librechroot b/src/chroot-tools/librechroot new file mode 100755 index 0000000..7f113f5 --- /dev/null +++ b/src/chroot-tools/librechroot @@ -0,0 +1,164 @@ +#!/bin/bash -euE +# librechroot + +# Copyright 2010 Nicolás Reynolds +# Copyright 2011 Joshua Haase +# Copyright 2012 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/>. + +. /usr/share/libretools/conf.sh +load_conf_libretools_chroot + +. "$(which libremessages)" +. /usr/share/devtools/makechrootpkg.sh + +cleanup=(':'); +cleanup() { + for cmd in "${cleanup[@]}"; do + $cmd + done +} + +cmd=${0##*/} +usage() { + echo "Usage: $cmd [OPTIONS] " + echo 'Interacts with a chroot.' + echo '' + echo 'This command will make the following configuration changes in' + echo 'the chroot:' + echo " - overwrite \`/etc/libretools.d/chroot.conf'" + echo " - overwrite \`/etc/pacman.d/mirrorlist'" + echo " - set \`CacheDir' in \`/etc/pacman.conf'" + echo '' + echo 'Options:' + echo ' Settings:' + echo " -n <CHROOT> Use this chroot instead of \`$CHROOT'" + echo " -l <COPY> Use this chroot copy instead \`$CHROOTCOPY'" + echo ' -N Disable networking in the chroot' + echo '' + echo ' Modes: (the last mode given will be used)' + echo ' -C Clean /repo in the chroot' + echo ' -c Clean the packages installed in the chroot' + echo ' -I <FILE> Install the package FILE into the chroot' + echo ' -i <PKG> Install the package PKG from repos into the chroot' + echo ' -m Make sure the chroot exists; do nothing else' + echo ' -r <CMD> Run CMD in the chroot' + echo " -s Sync the copy with the \`root' copy" + echo ' -u Update the chroot' + echo ' -h Show this message' +} + +main() { + CHROOTCOPY=$LIBREUSER + [[ $CHROOTCOPY != root ]] || CHROOTCOPY=copy + + local mode=enter + local archroot_args=(-f) + local ARG='' + while getopts 'n:l:NCcI:i:mr:suh' arg; do + case $arg in + n) CHROOT=$OPTARG;; + l) CHROOTCOPY=$OPTARG;; + N) archroot_args+=(-N);; + + C) mode=clean_repo;; + c) mode=clean_pacman;; + I) mode=install_file; ARG=$OPTARG;; + i) mode=install_pkg; ARG=$OPTARG;; + m) mode=noop;; + r) mode=run; ARG=$OPTARG;; + s) mode=sync;; + u) mode=update;; + + h) usage; exit 0;; + *) usage; exit 1;; + esac + done + shift $(($OPTIND - 1)) + if [[ $# > 0 ]]; then + usage + exit 1 + fi + + # not local + rootdir="${CHROOTDIR}/${CHROOT}/root" + copydir="${CHROOTDIR}/${CHROOT}/${CHROOTCOPY}" + + ######################################################################## + + if (( EUID )); then + error "This script must be run as root." + exit 1 + fi + + # Keep this lock as long as we are running + # Note that '9' is the same FD number as in (mk)archroot + lock_open_write 9 "$copydir" \ + "Waiting for existing lock on \`$copydir' to be released" + + if [[ ! -d $rootdir ]]; then + libremkchroot "$CHROOT" + fi + + if [[ ! -d $copydir ]] && [[ $mode != sync ]]; then + chroot_sync + fi + + mkdir -p $copydir/etc/libretools.d + { + if [[ -n ${CHROOTEXTRAPKG[@]:-} ]]; then + printf 'CHROOTEXTRAPKG=(' + printf "'%s' " "${CHROOTEXTRAPKG[@]}" + printf ')\n' + else + printf 'CHROOTEXTRAPKG=()\n' + fi + } > $copydir/etc/libretools.d/chroot.conf + + ######################################################################## + + trap cleanup EXIT + case "$mode" in + clean_repo) + rm -rf "${copydir}/repo/*" + bsdtar -czf "${copydir}/repo/repo.db.tar.gz" -T /dev/null + ln -s "repo.db.tar.gz" "${copydir}/repo/repo.db" + ;; + clean_pacman) + cleanup+=("rm -f $copydir/clean $copydir/chrootexec") + cp -a "$(which chcleanup)" "${copydir}/clean" + echo '#!/bin/bash' > "${copydir}/chrootexec" + echo 'mkdir /build' >> "${copydir}/chrootexec" + echo 'cd /build; /clean' >> "${copydir}/chrootexec" + chmod 755 "${copydir}/chrootexec" + archroot "${archroot_args[@]}" "${copydir}" -r /chrootexec + ;; + install_file) + cleanup+=("rm $copydir/${ARG##*/}") + cp "$ARG" "$copydir/${ARG##*/}" + archroot "${archroot_args[@]}" "${copydir}" -r "pacman -U /${ARG##*/} --noconfirm" + ;; + install_pkg) archroot "${archroot_args[@]}" "${copydir}" -i $ARG ;; + noop) :;; + run) archroot "${archroot_args[@]}" "${copydir}" -r "$ARG" ;; + sync) chroot_sync;; + update) archroot "${archroot_args[@]}" "${copydir}" -u ;; + enter) archroot "${archroot_args[@]}" "${copydir}" -r bash ;; + esac +} + +main "$@" diff --git a/src/chroot-tools/libremakepkg b/src/chroot-tools/libremakepkg new file mode 100755 index 0000000..a9e1fb7 --- /dev/null +++ b/src/chroot-tools/libremakepkg @@ -0,0 +1,187 @@ +#!/bin/bash -euE +# libremakepkg + +# Copyright 2010 - 2011 Nicolás Reynolds +# Copyright 2011 Joshua Ismael Haase Hernández +# Copyright 2012 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/>. + +. /usr/share/libretools/conf.sh +load_conf_libretools_chroot + +. "$(which libremessages)" +. /usr/share/devtools/makechrootpkg.sh + +shopt -s nullglob + +# Boring functions ############################################################# + +## +# End inmediately but print a useful message +## +trap_exit() { + copy_logs + error "$*" + exit 1 +} + +extract() { + local user=$LIBREUSER + $INCHROOT || user=nobody + + local clean + if $INCHROOT; then + clean=chcleanup + else + cp -a "$(which chcleanup)" "${copydir}/clean" + clean=/clean + fi + + chroot_exec "${clean} && sudo -u ${user} ${MAKEPKG} ${makepkg_args} -o" +} + +build() { + local user=$LIBREUSER + $INCHROOT || user=nobody + + chroot_exec -N "sudo -u ${user} ${MAKEPKG} ${makepkg_args} -e" +} + +# Functions that check for issues with the build ############################### + +check_pkgbuild() { + msg "Checking PKGBUILD for issues" + # TODO + if ! pkgbuild-check-nonfree -f; then + if [[ $? -eq 15 ]]; then + # other errors mean fail, not nonfree + error "PKGBUILD contains non-free issues" + exit 15 + else + warning "PKGBUILD couldn't be check aganist non-free issues" + fi + fi +} + +check_src() { + msg "Checking src directory for issues" + # TODO +} + +check_pkg() { + msg "Checking final package for issues" + # TODO +} + + +# The main program ############################################################# + +cmd=${0##*/} +usage() { + echo "Usage: $cmd [options] [-- makepkg args]" + echo 'This program will build your package.' + echo '' + echo 'If run from outside of a chroot, this will set PKGDEST and' + echo "SRCDEST in the chroot's \`/etc/makepkg.conf', as well as making" + echo "whataver alterations to the chroot \`librechroot' makes." + echo '' + echo 'Options:' + echo " -n <CHROOT> Use this chroot instead of \`$CHROOT'" + echo " -l <COPY> Use this chroot copy instead \`$CHROOTCOPY'" + echo " -m <MAKEPKG> Use the command MAKEPKG instead of \'makepkg'" + echo ' -h Show this message' +} + +main() { + # Parse command line ################################################### + + CHROOTCOPY=$LIBREUSER + [[ $CHROOTCOPY != root ]] || CHROOTCOPY=copy + + makepkg_args='-s --noconfirm -L ' + MAKEPKG=makepkg + + INCHROOT=false + if [[ -f /.arch-chroot ]]; then + INCHROOT=true + fi + + while getopts 'n:l:m:Rh' arg ; do + case "${arg}" in + n) CHROOT=$OPTARG;; + l) CHROOTCOPY=$OPTARG;; + m) MAKEPKG=$OPTARG;; + h) usage; exit 0;; + *) usage; exit 1;; + esac + done + shift $(($OPTIND - 1)) + # Pass all arguments after -- right to makepkg + makepkg_args+=" $*" + + if $INCHROOT; then + copydir='' + else + copydir="${CHROOTDIR}/${CHROOT}/${CHROOTCOPY}" + fi + + # Init ################################################################# + + if (( EUID )); then + error "This script 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 + + # Trap signals from makepkg + trap 'trap_exit "(libremakepkg): TERM signal caught. Exiting..."' TERM HUP QUIT + trap 'trap_exit "(libremakepkg): Aborted by user! Exiting..."' INT + trap 'trap_exit "(libremakepkg): An unknown error has occurred. Exiting..."' ERR + + SRCDEST="$(get_conf_makepkg SRCDEST .)" + PKGDEST="$(get_conf_makepkg PKGDEST .)" + + # OK, we're starting now ############################################### + + lock_open_write 9 "$copydir" \ + "Waiting for existing lock on \`$copydir' to be released" + + # Set target CARCH as it might be used within the PKGBUILD to select + # correct sources + MAKEPKG_CONF=$copydir/etc/makepkg.conf + export CARCH="$(get_conf_makepkg CARCH)" + unset MAKEPKG_CONF + + $INCHROOT || chroot_init + + check_pkgbuild + $INCHROOT || chroot_copy_in + extract + check_src + build + check_pkg + + add_to_local_repo + $INCHROOT || chroot_copy_out +} + +main "$@" diff --git a/src/chroot-tools/libremkchroot b/src/chroot-tools/libremkchroot new file mode 100755 index 0000000..6a13792 --- /dev/null +++ b/src/chroot-tools/libremkchroot @@ -0,0 +1,68 @@ +#!/bin/bash -euE +# libremkchroot + +# Copyright 2011, 2012 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/>. + +. /usr/share/libretools/conf.sh +load_conf_libretools_chroot + +. "$(which libremessages)" + +cmd=${0##*/} + +usage() { + echo "Usage: $cmd [OPTIONS] [CHROOT]" + echo 'This script will create a chroot to build packages in.' + echo "Use \`librechroot' to interact with the chroot after it is created." + echo '' + echo "The default CHROOT is \`${CHROOT}'." + echo '' + echo 'Options:' + echo ' -h Show this message' + echo '' + echo ' -C <file> Location of pacman config file.' + echo ' -M <file> Location of makepkg config file.' +} + +main() { + archroot_args=(-f); + while getopts 'hC:M:' arg; do + case "$arg" in + C|M) archroot_args+=("-$arg" "$OPTARG");; + + h) usage; exit 0;; + *) usage; exit 1;; + esac + done + shift $(($OPTIND - 1)) + case $# in + 0) :;; + 1) CHROOT="$1";; + *) usage; exit 1;; + esac + + if (( EUID )); then + error "This script must be run as root" + exit 1 + fi + + mkdir -p "${CHROOTDIR}/${CHROOT}" + archroot "${archroot_args[@]}" "${CHROOTDIR}/${CHROOT}/root" -i base base-devel sudo "${CHROOTEXTRAPKG[@]}" +} + +main "$@" diff --git a/src/devtools/.gitignore b/src/devtools/.gitignore new file mode 100644 index 0000000..e5e29ed --- /dev/null +++ b/src/devtools/.gitignore @@ -0,0 +1,17 @@ +*~ +devtools-*.tar.gz* +archbuild +archco +archrelease +archrm +bash_completion +checkpkg +commitpkg +finddeps +lddd +makechrootpkg +mkarchroot +rebuildpkgs +zsh_completion +find-libdeps +crossrepomove diff --git a/src/devtools/Makefile b/src/devtools/Makefile new file mode 100644 index 0000000..8b94f80 --- /dev/null +++ b/src/devtools/Makefile @@ -0,0 +1,55 @@ +V=20121128.6 + +PREFIX = /usr/local +pkgdatadir=$(PREFIX)/share/devtools + +BINPROGS = \ + checkpkg \ + find-libdeps \ + finddeps \ + lddd + +SBINPROGS = \ + mkarchroot + +all: $(BINPROGS) $(SBINPROGS) bash_completion zsh_completion + +edit = sed -e "s|@pkgdatadir[@]|$(pkgdatadir)|g" + +%: %.in Makefile + @echo "GEN $@" + @$(RM) "$@" + @m4 -P $@.in | $(edit) >$@ + @chmod a-w "$@" + @chmod +x "$@" + +clean: + rm -f $(BINPROGS) $(SBINPROGS) bash_completion zsh_completion + +install: all + install -dm0755 $(DESTDIR)$(PREFIX)/bin + install -dm0755 $(DESTDIR)$(PREFIX)/sbin + install -dm0755 $(DESTDIR)$(pkgdatadir) + + install -m0755 ${BINPROGS} $(DESTDIR)$(PREFIX)/bin +# install -m0755 ${SBINPROGS} $(DESTDIR)$(PREFIX)/sbin + install -m0755 mkarchroot $(DESTDIR)$(PREFIX)/sbin/archroot + + ln -sf find-libdeps $(DESTDIR)$(PREFIX)/bin/find-libprovides + + install -m0644 lib/common.sh $(DESTDIR)$(pkgdatadir)/common.sh + install -m0644 makechrootpkg.in $(DESTDIR)$(pkgdatadir)/makechrootpkg.sh + install -Dm0644 bash_completion $(DESTDIR)$(PREFIX)/share/bash-completion/completions/devtools + install -Dm0644 zsh_completion $(DESTDIR)$(PREFIX)/share/zsh/site-functions/_devtools + +uninstall: + for f in ${BINPROGS} ; do rm -f $(DESTDIR)$(PREFIX)/bin/$$f; done +# for f in ${SBINPROGS} ; do rm -f $(DESTDIR)$(PREFIX)/sbin/$$f; done + rm -f $(DESTDIR)$(PREFIX)/sbin/archroot + + rm -f $(DESTDIR)$(PREFIX)/bin/find-libprovides + + rm -f $(DESTDIR)$(PREFIX)/share/bash-completion/completions/devtools + rm -f $(DESTDIR)$(PREFIX)/share/zsh/site-functions/_devtools + +.PHONY: all clean install uninstall diff --git a/src/devtools/README b/src/devtools/README new file mode 100644 index 0000000..e10394f --- /dev/null +++ b/src/devtools/README @@ -0,0 +1,12 @@ +This is a minimal fork of Arch's `devtools'. + +It is a fork in that bugs are fixed and features added. + This happens on the "complete" branch. Most development should happen here, + and it should be able to be merged back into devtools. +It is minimal in that it doesn't include most of what is in devtools. + This happens on the "master" branch. + +A sample .git/config file is included to make it easy to merge from devtools. + +Tags in the format "%YYYY%MM%DD" are devtools. +Tags in the format "v%YYYY%MM%DD" are chroottools. diff --git a/src/devtools/bash_completion.in b/src/devtools/bash_completion.in new file mode 100644 index 0000000..5e4fe66 --- /dev/null +++ b/src/devtools/bash_completion.in @@ -0,0 +1,23 @@ +#!/bin/bash + +_mkarchroot() { + local cur + COMPREPLY=() + _get_comp_words_by_ref cur + + case $cur in + -*) + COMPREPLY=( $( compgen -W '-C -M -c -f -h -n -r -u' -- "$cur" ) ) + ;; + *) + _filedir + return 0 + ;; + esac + + true +} && +complete -F _mkarchroot archroot + + +# ex:et ts=2 sw=2 ft=sh diff --git a/src/devtools/checkpkg.in b/src/devtools/checkpkg.in new file mode 100644 index 0000000..a761df7 --- /dev/null +++ b/src/devtools/checkpkg.in @@ -0,0 +1,83 @@ +#!/bin/bash + +source @pkgdatadir@/common.sh + +# Source makepkg.conf; fail if it is not found +if [[ -r '/etc/makepkg.conf' ]]; then + source '/etc/makepkg.conf' +else + die '/etc/makepkg.conf not found!' +fi + +# Source user-specific makepkg.conf overrides +if [[ -r ~/.makepkg.conf ]]; then + source ~/.makepkg.conf +fi + +if [[ ! -f PKGBUILD ]]; then + die 'This must be run in the directory of a built package.' +fi + +. PKGBUILD +if [[ $arch == 'any' ]]; then + CARCH='any' +fi + +STARTDIR=$(pwd) +TEMPDIR=$(mktemp -d --tmpdir checkpkg-script.XXXX) +cd "$TEMPDIR" + +for _pkgname in "${pkgname[@]}"; do + pkgfile=${_pkgname}-$(get_full_version $_pkgname)-${CARCH}${PKGEXT} + + if [[ -f "$STARTDIR/$pkgfile" ]]; then + ln -s "$STARTDIR/$pkgfile" "$pkgfile" + elif [[ -f "$PKGDEST/$pkgfile" ]]; then + ln -s "$PKGDEST/$pkgfile" "$pkgfile" + else + die "File \"$pkgfile\" doesn't exist" + fi + + pkgurl=$(pacman -Spdd --print-format '%l' --noconfirm "$_pkgname") + + if [[ $? -ne 0 ]]; then + die "Couldn't download previous package for $_pkgname." + fi + + oldpkg=${pkgurl##*://*/} + + if [[ ${oldpkg##*/} = ${pkgfile##*/} ]]; then + die "The built package ($_pkgname) is the one in the repo right now!" + fi + + if [[ ! -f $oldpkg ]]; then + if [[ $pkgurl = file://* ]]; then + ln -s "${pkgurl#file://}" "${pkgurl##file://*/}" + elif [[ -f "$PKGDEST/$oldpkg" ]]; then + ln -s "$PKGDEST/$oldpkg" "$oldpkg" + elif [[ -f "$STARTDIR/$oldpkg" ]]; then + ln -s "$STARTDIR/$oldpkg" "$oldpkg" + else + curl -fsLC - --retry 3 --retry-delay 3 -o "$oldpkg" "$pkgurl" + fi + fi + + bsdtar tf "$oldpkg" | sort > "filelist-$_pkgname-old" + bsdtar tf "$pkgfile" | sort > "filelist-$_pkgname" + + sdiff -s "filelist-$_pkgname-old" "filelist-$_pkgname" + + if diff "filelist-$_pkgname-old" "filelist-$_pkgname" | grep '\.so' > /dev/null 2>&1; then + mkdir -p pkg + cd pkg + bsdtar xf ../"$pkgfile" > /dev/null + diff "../filelist-$_pkgname-old" "../filelist-$_pkgname" | awk '/>.*\.so/{$1 = ""; print $0}' | while read i; do + echo "${i}: " "$(objdump -p "$i" | grep SONAME)" + done + cd .. + else + msg "No soname differences for $_pkgname." + fi +done + +msg "Files saved to $TEMPDIR" diff --git a/src/devtools/find-libdeps.in b/src/devtools/find-libdeps.in new file mode 100644 index 0000000..7618850 --- /dev/null +++ b/src/devtools/find-libdeps.in @@ -0,0 +1,87 @@ +#!/bin/bash + +source @pkgdatadir@/common.sh + +set -e +shopt -s extglob + +IGNORE_INTERNAL=0 + +if [[ $1 = "--ignore-internal" ]]; then + IGNORE_INTERNAL=1 + shift +fi + +script_mode=${0##*/find-lib} + +case $script_mode in + deps|provides) true;; + *) die "Unknown mode $script_mode" ;; +esac + +if [[ -z $1 ]]; then + echo "${0##*/} [options] <package file|extracted package dir>" + echo "Options:" + echo " --ignore-internal ignore internal libraries" + exit 1 +fi + +if [[ -d $1 ]]; then + pushd $1 >/dev/null +else + setup_workdir + + case ${script_mode} in + deps) bsdtar -C $WORKDIR -xf "$1";; + provides) bsdtar -C $WORKDIR -xf "$1" --include="*.so*";; + esac + + pushd $WORKDIR >/dev/null +fi + +process_sofile() { + # extract the library name: libfoo.so + soname="${sofile%.so?(+(.+([0-9])))}".so + # extract the major version: 1 + soversion="${sofile##*\.so\.}" + if [[ "$soversion" = "$sofile" ]] && (($IGNORE_INTERNAL)); then + continue + fi + if ! in_array "${soname}=${soversion}-${soarch}" ${soobjects[@]}; then + # libfoo.so=1-64 + echo "${soname}=${soversion}-${soarch}" + soobjects=(${soobjects[@]} "${soname}=${soversion}-${soarch}") + fi +} + +case $script_mode in + deps) find_args="-perm -u+x";; + provides) find_args="-name *.so*";; +esac + +find . -type f $find_args | while read filename; do + if [[ $script_mode = "provides" ]]; then + # ignore if we don't have a shared object + if ! LC_ALL=C readelf -h "$filename" 2>/dev/null | grep -q '.*Type:.*DYN (Shared object file).*'; then + continue + fi + fi + + # get architecture of the file; if soarch is empty it's not an ELF binary + soarch=$(LC_ALL=C readelf -h "$filename" 2>/dev/null | sed -n 's/.*Class.*ELF\(32\|64\)/\1/p') + [[ -n $soarch ]] || continue + + if [[ $script_mode = "provides" ]]; then + # get the string binaries link to: libfoo.so.1.2 -> libfoo.so.1 + sofile=$(LC_ALL=C readelf -d "$filename" 2>/dev/null | sed -n 's/.*Library soname: \[\(.*\)\].*/\1/p') + [[ -z $sofile ]] && sofile="${filename##*/}" + process_sofile + elif [[ $script_mode = "deps" ]]; then + # process all libraries needed by the binary + for sofile in $(LC_ALL=C readelf -d "$filename" 2>/dev/null | sed -nr 's/.*Shared library: \[(.*)\].*/\1/p'); do + process_sofile + done + fi +done + +popd >/dev/null diff --git a/src/devtools/finddeps.in b/src/devtools/finddeps.in new file mode 100644 index 0000000..656fe5a --- /dev/null +++ b/src/devtools/finddeps.in @@ -0,0 +1,39 @@ +#!/bin/bash +# +# finddeps - find packages that depend on a given depname +# + +source @pkgdatadir@/common.sh + +match=$1 + +if [[ -z $match ]]; then + echo 'Usage: finddeps <depname>' + echo '' + echo 'Find packages that depend on a given depname.' + echo 'Run this script from the top-level directory of your ABS tree.' + echo '' + exit 1 +fi + +find . -type d | while read d; do + if [[ -f "$d/PKGBUILD" ]]; then + unset pkgname depends makedepends optdepends + . "$d/PKGBUILD" + for dep in "${depends[@]}"; do + # lose the version comparator, if any + depname=${dep%%[<>=]*} + [[ $depname = $match ]] && echo "$d (depends)" + done + for dep in "${makedepends[@]}"; do + # lose the version comparator, if any + depname=${dep%%[<>=]*} + [[ $depname = $match ]] && echo "$d (makedepends)" + done + for dep in "${optdepends[@]/:*}"; do + # lose the version comaparator, if any + depname=${dep%%[<>=]*} + [[ $depname = $match ]] && echo "$d (optdepends)" + done + fi +done diff --git a/src/devtools/gitconfig b/src/devtools/gitconfig new file mode 100644 index 0000000..890a5d0 --- /dev/null +++ b/src/devtools/gitconfig @@ -0,0 +1,17 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true +[remote "origin"] + url = ssh://git@parabolagnulinux.org:1863/srv/git/packages/chroottools.git + fetch = +refs/heads/*:refs/remotes/origin/* +[remote "devtools"] + url = git://projects.archlinux.org/devtools.git + fetch = +refs/heads/*:refs/remotes/devtools/* +[branch "master"] + remote = origin + merge = refs/heads/master +[branch "complete"] + remote = devtools + merge = refs/heads/master diff --git a/src/devtools/lddd.in b/src/devtools/lddd.in new file mode 100644 index 0000000..4040ce6 --- /dev/null +++ b/src/devtools/lddd.in @@ -0,0 +1,48 @@ +#!/bin/bash +# +# lddd - find broken library links on your machine +# + +source @pkgdatadir@/common.sh + +ifs=$IFS +IFS="${IFS}:" + +libdirs="/lib /usr/lib /usr/local/lib $(cat /etc/ld.so.conf.d/*)" +extras= + +TEMPDIR=$(mktemp -d --tmpdir lddd-script.XXXX) + +msg 'Go out and drink some tea, this will take a while :) ...' +# Check ELF binaries in the PATH and specified dir trees. +for tree in $PATH $libdirs $extras; do + msg2 "DIR $tree" + + # Get list of files in tree. + files=$(find $tree -type f ! -name '*.a' ! -name '*.la' ! -name '*.py*' ! -name '*.txt' ! -name '*.h' ! -name '*.ttf' ! \ + -name '*.rb' ! -name '*.ko' ! -name '*.pc' ! -name '*.enc' ! -name '*.cf' ! -name '*.def' ! -name '*.rules' ! -name \ + '*.cmi' ! -name '*.mli' ! -name '*.ml' ! -name '*.cma' ! -name '*.cmx' ! -name '*.cmxa' ! -name '*.pod' ! -name '*.pm' \ + ! -name '*.pl' ! -name '*.al' ! -name '*.tcl' ! -name '*.bs' ! -name '*.o' ! -name '*.png' ! -name '*.gif' ! -name '*.cmo' \ + ! -name '*.cgi' ! -name '*.defs' ! -name '*.conf' ! -name '*_LOCALE' ! -name 'Compose' ! -name '*_OBJS' ! -name '*.msg' ! \ + -name '*.mcopclass' ! -name '*.mcoptype') + IFS=$ifs + for i in $files; do + if (( $(file $i | grep -c 'ELF') != 0 )); then + # Is an ELF binary. + if (( $(ldd $i 2>/dev/null | grep -c 'not found') != 0 )); then + # Missing lib. + echo "$i:" >> $TEMPDIR/raw.txt + ldd $i 2>/dev/null | grep 'not found' >> $TEMPDIR/raw.txt + fi + fi + done +done +grep '^/' $TEMPDIR/raw.txt | sed -e 's/://g' >> $TEMPDIR/affected-files.txt +# invoke pacman +for i in $(cat $TEMPDIR/affected-files.txt); do + pacman -Qo $i | awk '{print $4,$5}' >> $TEMPDIR/pacman.txt +done +# clean list +sort -u $TEMPDIR/pacman.txt >> $TEMPDIR/possible-rebuilds.txt + +msg "Files saved to $TEMPDIR" diff --git a/src/devtools/lib/common.sh b/src/devtools/lib/common.sh new file mode 100644 index 0000000..d6fbe7c --- /dev/null +++ b/src/devtools/lib/common.sh @@ -0,0 +1,186 @@ +# Avoid any encoding problems +export LANG=C + +# check if messages are to be printed using color +unset ALL_OFF BOLD BLUE GREEN RED YELLOW +if [[ -t 2 ]]; then + # prefer terminal safe colored and bold text when tput is supported + if tput setaf 0 &>/dev/null; then + ALL_OFF="$(tput sgr0)" + BOLD="$(tput bold)" + BLUE="${BOLD}$(tput setaf 4)" + GREEN="${BOLD}$(tput setaf 2)" + RED="${BOLD}$(tput setaf 1)" + YELLOW="${BOLD}$(tput setaf 3)" + else + ALL_OFF="\e[1;0m" + BOLD="\e[1;1m" + BLUE="${BOLD}\e[1;34m" + GREEN="${BOLD}\e[1;32m" + RED="${BOLD}\e[1;31m" + YELLOW="${BOLD}\e[1;33m" + fi +fi +readonly ALL_OFF BOLD BLUE GREEN RED YELLOW + +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}==> WARNING:${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2 +} + +error() { + local mesg=$1; shift + printf "${RED}==> ERROR:${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2 +} + +stat_busy() { + local mesg=$1; shift + printf "${GREEN}==>${ALL_OFF}${BOLD} ${mesg}...${ALL_OFF}" >&2 +} + +stat_done() { + printf "${BOLD}done${ALL_OFF}\n" >&2 +} + +_setup_workdir=false +setup_workdir() { + [[ -z $WORKDIR ]] && WORKDIR=$(mktemp -d --tmpdir "${0##*/}.XXXXXXXXXX") + _setup_workdir=true + trap 'trap_abort' INT QUIT TERM HUP + trap 'trap_exit' EXIT +} + +cleanup() { + if [[ -n $WORKDIR ]] && $_setup_workdir; then + rm -rf "$WORKDIR" + fi + [[ -n $1 ]] && exit $1 +} + +abort() { + msg 'Aborting...' + cleanup 0 +} + +trap_abort() { + trap - EXIT INT QUIT TERM HUP + abort +} + +trap_exit() { + trap - EXIT INT QUIT TERM HUP + cleanup +} + +die() { + error "$*" + cleanup 1 +} + +## +# usage : in_array( $needle, $haystack ) +# return : 0 - found +# 1 - not found +## +in_array() { + local needle=$1; shift + local item + for item in "$@"; do + [[ $item = $needle ]] && return 0 # Found + done + return 1 # Not Found +} + +## +# usage : lock_open_write( $fd, $path, $wait_message ) +## +lock_open_write() { + local fd=$1 + local path=$2 + local msg=$3 + + # Only reopen the FD if it wasn't handed to us + if [[ $(readlink -f /dev/fd/$fd) != "${path}.lock" ]]; then + mkdir -p "${path%/*}" + eval "exec $fd>${path}.lock" + fi + + if ! flock -n $fd; then + stat_busy "$msg" + flock $fd + stat_done + fi +} + +## +# usage : lock_open_read( $fd, $path, $wait_message ) +## +lock_open_read() { + local fd=$1 + local path=$2 + local msg=$3 + + # Only reopen the FD if it wasn't handed to us + if [[ $(readlink -f /dev/fd/$fd) != "${path}.lock" ]]; then + mkdir -p "${path%/*}" + eval "exec $fd>${path}.lock" + fi + + if ! flock -sn $fd; then + stat_busy "$msg" + flock -s $fd + stat_done + fi +} + + +## +# usage : lock_close( $fd ) +## +lock_close() { + local fd=$1 + eval "exec $fd>&-" +} + +## +# usage : get_full_version( [$pkgname] ) +# return : full version spec, including epoch (if necessary), pkgver, pkgrel +## +get_full_version() { + # set defaults if they weren't specified in buildfile + pkgbase=${pkgbase:-${pkgname[0]}} + epoch=${epoch:-0} + if [[ -z $1 ]]; then + if [[ $epoch ]] && (( ! $epoch )); then + echo $pkgver-$pkgrel + else + echo $epoch:$pkgver-$pkgrel + fi + else + for i in pkgver pkgrel epoch; do + local indirect="${i}_override" + eval $(declare -f package_$1 | sed -n "s/\(^[[:space:]]*$i=\)/${i}_override=/p") + [[ -z ${!indirect} ]] && eval ${indirect}=\"${!i}\" + done + if (( ! $epoch_override )); then + echo $pkgver_override-$pkgrel_override + else + echo $epoch_override:$pkgver_override-$pkgrel_override + fi + fi +} diff --git a/src/devtools/makechrootpkg.in b/src/devtools/makechrootpkg.in new file mode 100644 index 0000000..9e5b04f --- /dev/null +++ b/src/devtools/makechrootpkg.in @@ -0,0 +1,328 @@ +#!/bin/bash +# Copyright 2011-2012 The Arch Linux Development Team +# Copyright 2012 Luke Shumaker +# +# 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. + +# Because of how we pull changes from devtools.git, some of the function +# bodies are not indented. I appologize for my sins against the reader. + +# Any function beginning with "_makechrootpkg_" is basically a multiline +# comment to minimize the diff. These functions may use different variable +# names. + +# Otherwise, a function may be affected by the variables: +# makepkg.conf +# - PKGDEST +# - SRCDEST +# chroot.conf (and derived) +# - CHROOT +# - CHROOTCOPY +# - rootdir # = $CHROOTDIR/$CHROOT/root +# - copydir # = $CHROOTDIR/$CHROOT/$CHROOTCOPY +# environment +# - LIBREUSER # conf.sh +# - LIBREHOME # conf.sh +# - INCHROOT # libremakepkg +# invocation +# - repack + +[[ -n ${repack:-} ]] || repack=false + +_makechrootpkg_init() { +m4_include(lib/common.sh) + +shopt -s nullglob + +makepkg_args='-s --noconfirm -L' +repack=false +update_first=false +clean_first=false +install_pkg= +add_to_db=false +run_namcap=false +chrootdir= +passeddir= + +default_copy=$USER +[[ -n $SUDO_USER ]] && default_copy=$SUDO_USER +[[ -z $default_copy || $default_copy = root ]] && default_copy=copy +src_owner=${SUDO_USER:-$USER} +} + +_makechrootpkg_usage() { + echo "Usage: ${0##*/} [options] -r <chrootdir> [--] [makepkg args]" + echo ' Run this script in a PKGBUILD dir to build a package inside a' + echo ' clean chroot. All unrecognized arguments passed to this script' + echo ' will be passed to makepkg.' + echo '' + echo ' The chroot dir consists of the following directories:' + echo ' <chrootdir>/{root, copy} but only "root" is required' + echo ' by default. The working copy will be created as needed' + echo '' + echo 'The chroot "root" directory must be created via the following' + echo 'command:' + echo ' mkarchroot <chrootdir>/root base base-devel sudo' + echo '' + echo "Default makepkg args: $makepkg_args" + echo '' + echo 'Flags:' + echo '-h This help' + echo '-c Clean the chroot before building' + echo '-u Update the working copy of the chroot before building' + echo ' This is useful for rebuilds without dirtying the pristine' + echo ' chroot' + echo '-d Add the package to a local db at /repo after building' + echo '-r <dir> The chroot dir to use' + echo '-I <pkg> Install a package into the working copy of the chroot' + echo '-l <copy> The directory to use as the working copy of the chroot' + echo ' Useful for maintaining multiple copies.' + echo " Default: $default_copy" + echo '-n Run namcap on the package' + exit 1 +} + +_makechrootpkg_parse_options_init() { +while getopts 'hcudr:I:l:n' arg; do + case "$arg" in + h) usage ;; + c) clean_first=true ;; + u) update_first=true ;; + d) add_to_db=true ;; + r) passeddir="$OPTARG" ;; + I) install_pkg="$OPTARG" ;; + l) copy="$OPTARG" ;; + n) run_namcap=true; makepkg_args="$makepkg_args -i" ;; + *) makepkg_args="$makepkg_args -$arg $OPTARG" ;; + esac +done + +# Canonicalize chrootdir, getting rid of trailing / +chrootdir=$(readlink -e "$passeddir") + +if [[ ${copy:0:1} = / ]]; then + copydir=$copy +else + [[ -z $copy ]] && copy=$default_copy + copydir="$chrootdir/$copy" +fi + +# Pass all arguments after -- right to makepkg +makepkg_args="$makepkg_args ${*:$OPTIND}" + +# See if -R was passed to makepkg +for arg in ${*:$OPTIND}; do + if [[ $arg = -R ]]; then + repack=true + break + fi +done + +if (( EUID )); then + die 'This script must be run as root.' +fi + +if [[ ! -f PKGBUILD && -z $install_pkg ]]; then + die 'This must be run in a directory containing a PKGBUILD.' +fi + +if [[ ! -d $chrootdir ]]; then + die "No chroot dir defined, or invalid path '$passeddir'" +fi + +if [[ ! -d $chrootdir/root ]]; then + die "Missing chroot dir root directory. Try using: mkarchroot $chrootdir/root base base-devel sudo" +fi + +umask 0022 + +# Lock the chroot we want to use. We'll keep this lock until we exit. +# Note this is the same FD number as in mkarchroot +lock_open_write 9 "$copydir.lock" "Locking chroot copy '$copy'" +} + +chroot_sync() { + if [[ $CHROOTCOPY = root ]]; then + error "Cannot sync the root copy with itself" + exit 1 + fi + # Get a read lock on the root chroot to make + # sure we don't clone a half-updated chroot + lock_open_read 8 "$rootdir" \ + "Waiting for existing lock on \`$rootdir' to be released" + + stat_busy 'Creating clean working copy' + local use_rsync=false + if type -P btrfs >/dev/null; then + [[ -d $copydir ]] && btrfs subvolume delete "$copydir" &>/dev/null + btrfs subvolume snapshot "$rootdir" "$copydir" &>/dev/null || + use_rsync=true + else + use_rsync=true + fi + + if $use_rsync; then + mkdir -p "$copydir" + rsync -a --delete -q -W -x "$rootdir/" "$copydir" + fi + stat_done + + # Drop the read lock again + lock_close 8 +} + +_makechrootpkg_install_pkg() { + pkgname="${install_pkg##*/}" + cp "$install_pkg" "$copydir/$pkgname" + + mkarchroot -r "pacman -U /$pkgname --noconfirm" "$copydir" + ret=$? + + rm "$copydir/$pkgname" + + # Exit early, we've done all we need to + exit $ret +} + +chroot_init() { +# make sure the chroot exists +librechroot -n "$CHROOT" -l "$CHROOTCOPY" -m + +mkdir -p "$copydir/build" +mkdir -p "$copydir/pkgdest" +mkdir -p "$copydir/srcdest" + +# Remove anything in there UNLESS -R (repack) was passed to makepkg +$repack || rm -rf "$copydir"/build/* + +if [[ -r "$LIBREHOME/.gnupg/pubring.gpg" ]]; then + install -D "$LIBREHOME/.gnupg/pubring.gpg" "$copydir/build/.gnupg/pubring.gpg" +fi +rm -f "$copydir/build/.makepkg.conf" + +MAKEPKG_CONF="$copydir/etc/makepkg.conf" set_conf_makepkg PKGDEST /pkgdest +MAKEPKG_CONF="$copydir/etc/makepkg.conf" set_conf_makepkg SRCDEST /srcdest + +if grep -q '^\[repo\]' "$copydir/etc/pacman.conf"; then + cat >> "$copydir/etc/makepkg.conf" <<EOF +[repo] +SigLevel = Optional TrustAll +Server = file:///repo +EOF +fi + +_let_nobody_use_pacman +} + +chroot_copy_in() { +# Copy PKGBUILD and sources +cp PKGBUILD "$copydir/build/" +( + set +euE + source PKGBUILD + # Copy source files + for file in "${source[@]}"; do + file="${file%%::*}" + file="${file##*://*/}" + if [[ -f $file ]]; then + cp "$file" "$copydir/srcdest/" + elif [[ -f $SRCDEST/$file ]]; then + cp "$SRCDEST/$file" "$copydir/srcdest/" + 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/build/" + done < <(sed -n "s/^[[:space:]]*$i=//p" PKGBUILD) + done +) + +chown -R nobody "$copydir"/{build,pkgdest,srcdest} +} + +_let_nobody_use_pacman() { +cat > "$copydir/etc/sudoers.d/nobody-pacman" <<EOF +Defaults env_keep += "HOME" +nobody ALL = NOPASSWD: /usr/bin/pacman +EOF +chmod 440 "$copydir/etc/sudoers.d/nobody-pacman" +} + +chroot_exec() { +local HASNET=true +[[ $1 == -N ]] && { HASNET=false; shift; } + +local cmd="$*" +# This is a little gross, but this way the script is recreated every time in the +# working copy +cat >"$copydir/chrootexec" <<EOF +#!/bin/bash +. /etc/profile +${INCHROOT} || export HOME=/build +${INCHROOT} || cd /build + +${cmd} +EOF +chmod 755 "$copydir/chrootexec" + +local flags='' +if $INCHROOT; then + $HASNET || flags='-n' + unshare $flags -- /chrootexec +else + $HASNET || flags='-N' + librechroot $flags -n "$CHROOT" -l "$CHROOTCOPY" -r /chrootexec +fi +} + +add_to_local_repo() { + for pkgfile in "$copydir"/pkgdest/*.pkg.tar*; do + if true; then + mkdir -p "$copydir/repo" + pushd "$copydir/repo" >/dev/null + cp "$pkgfile" . + repo-add repo.db.tar.gz "${pkgfile##*/}" + popd >/dev/null + fi + done +} +_chroot_copy_out_pkgs() { + for pkgfile in "$copydir"/pkgdest/*.pkg.tar*; do + chown "$LIBREUSER" "$pkgfile" + mv "$pkgfile" "$PKGDEST" + if [[ $PKGDEST != . ]]; then + ln -s "$PKGDEST/${pkgfile##*/}" . + fi + done +} + +_chroot_copy_out_logs() { + for l in "$copydir"/build/*.log; do + chown "$LIBREUSER" "$l" + [[ -f $l ]] && mv "$l" . + done +} + +_chroot_copy_out_srcs() { +for f in "$copydir"/srcdest/*; do + chown "$LIBREUSER" "$f" + mv "$f" "$SRCDEST" +done +} + +chroot_copy_out() { + _chroot_copy_out_pkgs + _chroot_copy_out_logs + _chroot_copy_out_srcs +} diff --git a/src/devtools/mkarchroot.in b/src/devtools/mkarchroot.in new file mode 100644 index 0000000..96f4399 --- /dev/null +++ b/src/devtools/mkarchroot.in @@ -0,0 +1,302 @@ +#!/bin/bash +# 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. + +source @pkgdatadir@/common.sh + +CHROOT_VERSION='v2' + +FORCE='n' +RUN='' +NOCOPY='n' +NONETWORK='n' + +working_dir='' + +APPNAME=$(basename "${0}") + +# usage: usage <exitvalue> +usage() { + echo "Usage: ${APPNAME} [options] working-dir [action]" + echo ' options:' + echo ' -f Force overwrite of files in the working-dir' + echo ' -C <file> Location of a pacman config file' + echo ' -M <file> Location of a makepkg config file' + echo ' -n Do not copy config files into the chroot' + echo ' -c <dir> Set pacman cache' + echo ' -N Disable networking in the chroot' + echo ' actions:' + echo ' -i <pkg-list> Install "pkg-list" in the chroot.' + echo ' Creates the chroot if necessary, workding-dir must exist' + echo ' -r <cmd> Run "cmd" within the context of the chroot' + echo ' -u Update the chroot via pacman' + echo ' -h Print this message' + + exit ${1-1} +} + +################################################################################ + +while getopts 'fC:M:nc:Nh' arg; do + case "${arg}" in + f) FORCE='y' ;; + C) pac_conf="$OPTARG" ;; + M) makepkg_conf="$OPTARG" ;; + n) NOCOPY='y' ;; + c) cache_dir="$OPTARG" ;; + N) NONETWORK='y' ;; + + h) action="-$arg" ;; + + *) error "invalid argument '${arg}'"; usage ;; + esac +done + +shift $(($OPTIND - 1)) + +if (( $# < 2 )); then + error 'You must specify a directory and an action.' + usage +fi + +working_dir="$(readlink -f "${1}")" +shift 1 +[[ -z $working_dir ]] && die 'Please specify a working directory.' + +action=$1 +shift 1 +case "$action" in + -i) PKGS=("$@") ;; + -r) RUN="$*" ;; + -u) + (( $# > 0 )) && { error 'Extra arguments.'; usage; } + RUN='/bin/sh -c "pacman -Syu --noconfirm && (pacman -Qqu >/dev/null && pacman -Su --noconfirm || exit 0)"' + ;; + -h) usage 0 ;; + -*) error "invalid argument '${action#-}'"; usage ;; + *) error "invalid action '${action}'"; usage ;; +esac +unset action + +################################################################################ + +if (( $EUID != 0 )); then + die 'This script must be run as root.' +fi + +if [[ -z $cache_dir ]]; then + cache_dirs=($(pacman -v $cache_conf 2>&1 | grep '^Cache Dirs:' | sed 's/Cache Dirs:\s*//g')) +else + cache_dirs=(${cache_dir}) +fi + +host_mirror=$(pacman -Sddp extra/devtools 2>/dev/null | sed -E 's#(.*/)extra/os/.*#\1$repo/os/$arch#') +if echo "${host_mirror}" | grep -q 'file://'; then + host_mirror_path=$(echo "${host_mirror}" | sed -E 's#file://(/.*)/\$repo/os/\$arch#\1#g') +fi + +# {{{ functions +bind_mount() { + local mode="${2:-rw}" + local target="${working_dir}${1}" + + if [[ ! -e "$target" ]]; then + if [[ -d "$1" ]]; then + install -d "$target" + else + install -D /dev/null "$target" + fi + fi + + mount -o bind "$1" "$target" + mount -o remount,${mode},bind "$target" + mount --make-slave "$target" +} + +chroot_mount() { + trap 'trap_chroot_umount' EXIT INT QUIT TERM HUP + + if (( ! have_nspawn )); then + bind_mount /sys ro + + [[ -e "${working_dir}/proc" ]] || mkdir "${working_dir}/proc" + mount -t proc proc -o nosuid,noexec,nodev "${working_dir}/proc" + bind_mount /proc/sys ro + + [[ -e "${working_dir}/dev" ]] || mkdir "${working_dir}/dev" + mount -t tmpfs dev "${working_dir}/dev" -o mode=0755,size=10M,nosuid,strictatime + mknod -m 666 "${working_dir}/dev/null" c 1 3 + mknod -m 666 "${working_dir}/dev/zero" c 1 5 + mknod -m 600 "${working_dir}/dev/console" c 5 1 + mknod -m 644 "${working_dir}/dev/random" c 1 8 + mknod -m 644 "${working_dir}/dev/urandom" c 1 9 + mknod -m 666 "${working_dir}/dev/tty" c 5 0 + mknod -m 666 "${working_dir}/dev/ptmx" c 5 2 + mknod -m 666 "${working_dir}/dev/tty0" c 4 0 + mknod -m 666 "${working_dir}/dev/full" c 1 7 + mknod -m 666 "${working_dir}/dev/rtc0" c 254 0 + ln -s /proc/kcore "${working_dir}/dev/core" + ln -s /proc/self/fd "${working_dir}/dev/fd" + ln -s /proc/self/fd/0 "${working_dir}/dev/stdin" + ln -s /proc/self/fd/1 "${working_dir}/dev/stdout" + ln -s /proc/self/fd/2 "${working_dir}/dev/stderr" + + [[ -e "${working_dir}/dev/shm" ]] || mkdir "${working_dir}/dev/shm" + mount -t tmpfs shm "${working_dir}/dev/shm" -o nodev,nosuid,size=128M + + bind_mount /dev/pts + + [[ -e "${working_dir}/run" ]] || mkdir "${working_dir}/run" + mount -t tmpfs tmpfs "${working_dir}/run" -o mode=0755,nodev,nosuid,strictatime,size=64M + + for host_config in resolv.conf localtime; do + bind_mount /etc/$host_config ro + done + fi + + [[ -n $host_mirror_path ]] && bind_mount "$host_mirror_path" ro + + bind_mount "${cache_dirs[0]}" + for cache_dir in ${cache_dirs[@]:1}; do + bind_mount "$cache_dir" ro + done +} + +copy_hostconf () { + cp -a /etc/pacman.d/gnupg "${working_dir}/etc/pacman.d" + echo "Server = ${host_mirror}" > ${working_dir}/etc/pacman.d/mirrorlist + + if [[ -n $pac_conf && $NOCOPY = 'n' ]]; then + cp ${pac_conf} ${working_dir}/etc/pacman.conf + fi + + if [[ -n $makepkg_conf && $NOCOPY = 'n' ]]; then + cp ${makepkg_conf} ${working_dir}/etc/makepkg.conf + fi + + sed -r "s|^#?\\s*CacheDir.+|CacheDir = $(echo -n ${cache_dirs[@]})|g" -i ${working_dir}/etc/pacman.conf +} + +trap_unmount_err () { + error "Error unmounting" +} + +trap_chroot_umount () { + trap 'trap_unmount_err' INT QUIT TERM HUP EXIT + + for cache_dir in ${cache_dirs[@]}; do + umount "${working_dir}/${cache_dir}" + done + [[ -n $host_mirror_path ]] && umount "${working_dir}/${host_mirror_path}" + + if (( ! have_nspawn )); then + for host_config in resolv.conf localtime; do + umount "${working_dir}/etc/${host_config}" + done + umount "${working_dir}/proc/sys" + umount "${working_dir}/proc" + umount "${working_dir}/sys" + umount "${working_dir}/dev/pts" + umount "${working_dir}/dev/shm" + umount "${working_dir}/dev" + umount "${working_dir}/run" + fi + + trap 'trap_abort' INT QUIT TERM HUP + trap 'trap_exit' EXIT +} + +chroot_lock () { + lock_open_write 9 "${working_dir}" "Locking chroot" +} + +chroot_run() { + local dir=$1 + shift + if (( have_nspawn)); then + local nspawn_args=(-D "$dir") + if [[ $NONETWORK = y ]]; then + nspawn_args+=(--private-network) + fi + eval systemd-nspawn "${nspawn_args[@]}" -- "${@}" 2>/dev/null + else + local unshare_args=(-mui) + if [[ $NONETWORK = y ]]; then + unshare_args+=(-n) + fi + eval unshare "${unshare_args[@]}" -- chroot "${dir}" "${@}" + fi +} + +# }}} + +# use systemd-nspawn if we have it available and systemd is running +if type -P systemd-nspawn >/dev/null && mountpoint -q /sys/fs/cgroup/systemd; then + have_nspawn=1 +fi + +umask 0022 +if [[ -n $RUN ]]; then + # run chroot {{{ + #Sanity check + if [[ ! -f "${working_dir}/.arch-chroot" ]]; then + die "'${working_dir}' does not appear to be a Arch chroot." + elif [[ $(cat "${working_dir}/.arch-chroot") != ${CHROOT_VERSION} ]]; then + die "'${working_dir}' is not compatible with ${APPNAME} version ${CHROOT_VERSION}. Please rebuild." + fi + + chroot_lock + chroot_mount + copy_hostconf + + chroot_run "${working_dir}" ${RUN} + + # }}} +else + # {{{ build chroot + if [[ -e $working_dir && $FORCE = 'n' ]]; then + die "Working directory '${working_dir}' already exists - try using -f" + fi + + if { type -P btrfs && btrfs subvolume create "${working_dir}"; } &>/dev/null; then + chmod 0755 "${working_dir}" + fi + + chroot_lock + chroot_mount + + pacargs="${cache_dirs[@]/#/--cachedir=}" + if [[ -n $pac_conf ]]; then + pacargs="$pacargs --config=${pac_conf}" + fi + + if (( $# != 0 )); then + if [[ $FORCE = 'y' ]]; then + pacargs="$pacargs --force" + fi + if ! pacstrap -GMcd "${working_dir}" ${pacargs} "${PKGS[@]}"; then + die 'Failed to install all packages' + fi + fi + + if [[ -d "${working_dir}/lib/modules" ]]; then + chroot_run "${working_dir}" ldconfig + fi + + if [[ -e "${working_dir}/etc/locale.gen" ]]; then + sed -i 's@^#\(en_US\|de_DE\)\(\.UTF-8\)@\1\2@' "${working_dir}/etc/locale.gen" + chroot_run "${working_dir}" locale-gen + fi + echo 'LANG=C' > "${working_dir}/etc/locale.conf" + + copy_hostconf + + echo "${CHROOT_VERSION}" > "${working_dir}/.arch-chroot" + # }}} +fi diff --git a/src/devtools/zsh_completion.in b/src/devtools/zsh_completion.in new file mode 100644 index 0000000..ec07b3b --- /dev/null +++ b/src/devtools/zsh_completion.in @@ -0,0 +1,34 @@ +#compdef finddeps archroot + +_archbuild_args=( + '-c[Recreate the chroot before building]' + '-r[Create chroots in this directory]:base_dir:_files -/' +) + +_finddeps_args=( + '1:packages:_devtools_completions_all_packages' +) + +_archroot_args=( + '-r[Run a program within the context of the chroot]:app' + '-u[Update the chroot via pacman]' + '-f[Force overwrite of files in the working-dir]' + '-C[Location of a pacman config file]:pacman_config:_files' + '-M[Location of a makepkg config file]:makepkg_config:_files' + '-n[Do not copy config files into the chroot]' + '-c[Set pacman cache]:pacman_cache:_files -/' + '-h[Display usage]' +) + +_devtools_completions_all_packages() { + typeset -U packages + packages=($(_call_program packages pacman -Sql)) + compadd - "${(@)packages}" +} + +_devtools() { + local argname="_${service}_args[@]" + _arguments -s "${(P)argname}" +} + +_devtools diff --git a/src/diff-unfree b/src/diff-unfree new file mode 100755 index 0000000..24ada67 --- /dev/null +++ b/src/diff-unfree @@ -0,0 +1,86 @@ +#!/bin/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/>. + +. /etc/libretools.conf + +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}" + + stdnull 'pushd "${tmp_dir}"' + + msg "Getting diff from $repo/$package..." + + stdnull 'svn checkout --depth=empty svn://svn.archlinux.org/$svnrepo' + + cd ${svnrepo} + svn update ${package} + + # Back to start dir + stdnull popd + + msg "Diffing files" + + for _file in ${unfree_dir}/*; do + msg2 "$(basename "${_file}")" + ${DIFFTOOL} "$PWD/$(basename "${_file}")" "${_file}" + done +} + +main "$@" diff --git a/src/fullpkg/Makefile b/src/fullpkg/Makefile new file mode 100644 index 0000000..f2cec54 --- /dev/null +++ b/src/fullpkg/Makefile @@ -0,0 +1,3 @@ +libre_execdir=$(bindir) +libre_datadir=$(sysconfdir)/libretools.d +include ../../common.mk diff --git a/src/fullpkg/fullpkg b/src/fullpkg/fullpkg new file mode 100755 index 0000000..6d6153a --- /dev/null +++ b/src/fullpkg/fullpkg @@ -0,0 +1,34 @@ +#!/bin/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..b497db5 --- /dev/null +++ b/src/fullpkg/fullpkg-build @@ -0,0 +1,211 @@ +#!/bin/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 + +source /etc/makepkg.conf +source /etc/libretools.conf + +if [ -e $XDG_CONFIG_HOME/libretools/libretools.conf ]; then + source $XDG_CONFIG_HOME/libretools/libretools.conf +fi + + +## 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 + } +} + +# return : full version spec, including epoch (if necessary), pkgver, pkgrel +# usage : get_fullver( ${epoch:-0}, $pkgver, $pkgrel ) +get_fullver() { + if [[ $1 -eq 0 ]]; then +# zero epoch case, don't include it in version + echo $2-$3 + else + echo $1:$2-$3 + fi + +} + +## 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 + find -name "*.pkg.tar.?z" -print0 | xargs -0 "$HOOKLOCALRELEASE" "$repo" + fi + + librestage $repo || echo "unstaged:$(basename $PWD)" >>$build_dir/log + + 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 + +if [ -z "$FULLBUILDCMD" ]; then + error "Set your FULLBUILDCMD on libretools.conf" +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..b09edf9 --- /dev/null +++ b/src/fullpkg/fullpkg-find @@ -0,0 +1,211 @@ +#!/bin/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)) +} + +# return : full version spec, including epoch (if necessary), pkgver, pkgrel +# usage : get_fullver( ${epoch:-0}, $pkgver, $pkgrel ) +get_fullver() { + if [[ $1 -eq 0 ]]; then +# zero epoch case, don't include it in version + echo $2-$3 + else + echo $1:$2-$3 + fi + +} + +copy_files() { + + local copydir="$build_dir/${pkgbase:-${pkgname[0]}}" + mkdir -p "$copydir" + + # Copy PKGBUILD and sources + cp PKGBUILD "$copydir" + ( + source 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 + source PKGBUILD + + local repo="${repo:-$(guess_repo)}" + local pkgbase="${pkgbase:-${pkgname[0]}}" + local fullver="$(get_fullver ${epoch:-0} ${pkgver} ${pkgrel})" + + 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]}" "${fullver}"; 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}-${fullver}" + +## 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 +} + +source /etc/libretools.conf +source /etc/makepkg.conf + +if [ -e $XDG_CONFIG_HOME/libretools/libretools.conf ]; then + source $XDG_CONFIG_HOME/libretools/libretools.conf +fi + +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..1fa79d2 --- /dev/null +++ b/src/is_built @@ -0,0 +1,36 @@ +#!/bin/bash +usage() { + echo "$0 " + echo + echo "Detect if a given package version is already in repos" + echo "Assuming you want greater or equal" + echo + echo "Example usage: is_built 'pcre' '20'" +} + +while getopts 'h' arg; do + case $arg in + h) usage; exit 0 ;; + *) usage; exit 1 ;; + esac +done + +ver=${2} +pkg=${1} +pver=$(LC_ALL=C pacman -Sddp --print-format "%v" "${pkg}" 2>/dev/null) + +# if pacman fails or returns nothing +r=$? +[ "${pver}" = " there is nothing to do" ] && r=1 + +result=$(vercmp "${pver}" "${ver}") + +# if vercmp > 1 means our version is bigger +if [ ${result} -ge 0 -a ${r} -eq 0 ]; then + exit 0 +else + exit 1 +fi + +# just in case +exit 1 diff --git a/src/is_unfree b/src/is_unfree new file mode 100755 index 0000000..c2a37c9 --- /dev/null +++ b/src/is_unfree @@ -0,0 +1,8 @@ +#!/bin/bash +# Checks if a package is on blacklist + +. /etc/libretools.conf + +blacklist="$XDG_CONFIG_HOME/libretools/blacklist.txt" +egrep -q "^${1}:" "${blacklist}" +exit $? diff --git a/src/lib/Makefile b/src/lib/Makefile new file mode 100644 index 0000000..0c69ba3 --- /dev/null +++ b/src/lib/Makefile @@ -0,0 +1,2 @@ +libre_datadir=$(datadir)/libretools +include ../../common.mk diff --git a/src/lib/conf.sh b/src/lib/conf.sh new file mode 100644 index 0000000..b11495d --- /dev/null +++ b/src/lib/conf.sh @@ -0,0 +1,116 @@ +#!/bin/bash + +INCLUDE_CONF_SH=conf.sh + +LIBREUSER="${SUDO_USER:-$USER}" +LIBREHOME="$(eval echo ~$LIBREUSER)" +if [[ -z ${XDG_CONFIG_HOME:-} ]]; then + export XDG_CONFIG_HOME="${LIBREHOME}/.config" +fi + +# Generic functions ############################################################ + +get_files() { + local slug=$1 + case $slug in + makepkg.conf) + if [[ $MAKEPKG_CONF != /etc/$slug && -r $MAKEPKG_CONF ]]; then + echo "$MAKEPKG_CONF" + else + echo /etc/$slug + echo "$LIBREHOME/.$slug" + fi + ;; + libretools.conf) + echo /etc/$slug + echo "$XDG_CONFIG_HOME/libretools/$slug" + ;; + *.conf) + echo /etc/libretools.d/$slug + echo "$XDG_CONFIG_HOME/libretools/$slug" + ;; + esac +} + +load_files() { + for file in $(get_files $1.conf); do + if [[ -r $file ]]; then + . "$file" + fi + done +} + +check_vars() { + local slug=$1 + shift + local ret=0 + for VAR in "$@"; do + if [[ -z ${!VAR} ]]; then + if [[ $(get_files $slug|wc -l) > 1 ]]; then + echo "Configure '$VAR' in one of:" + get_files $slug | sed 's/./ -> &/' + else + echo "Configure '$VAR' in $(get_files $slug)" + fi + ret=1 + fi >>/dev/stderr + done + if [[ $ret != 0 ]]; then + return 1 + fi +} + +# makepkg configuration ######################################################## + +[[ -n ${MAKEPKG_CONF:-} ]] || MAKEPKG_CONF=/etc/makepkg.conf + +load_conf_makepkg() { + load_files makepkg +} + +get_conf_makepkg() ( + set +euE + local setting=$1 + local default=$2 + load_conf_makepkg + printf '%s\n' "${!setting:-${default}}" +) + +set_conf_makepkg() { + local key=$1 + local val=$2 + for file in `get_files makepkg.conf|tac`; do + if [[ -w $file ]]; then + sed -i "/^\s*$key=/d" "$file" + echo "$key='$val'" >> "$file" + return 0 + fi + done + return 1 +} + + +# libretools configuration ##################################################### + +check_conf_libretools() { + check_vars libretools.conf \ + PARABOLAHOST LIBREDESTDIR BLACKLIST WORKDIR REPOS ARCHES \ + ABSLIBREGIT COMMITCMD DIFFTOOL FULLBUILDCMD SIGEXT SIGID +} + +load_conf_libretools() { + load_files libretools + check_conf_libretools +} + +load_conf_libretools_chroot() { + load_files chroot + # Exclude CHROOTEXTRAPKG from the checks because an empty value is valid + if [[ -f /.arch-chroot ]]; then + # inside of a chroot, only CHROOTEXTRAPKG needs to be set, but + # as stated above, we don't check for it. + : + else + check_vars chroot.conf CHROOTDIR CHROOT + fi +} diff --git a/src/librediff b/src/librediff new file mode 100755 index 0000000..6dbe41b --- /dev/null +++ b/src/librediff @@ -0,0 +1,57 @@ +#!/bin/bash +# Generates a patch for a nonfree PKGBUILD +# +# 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/>. + +. /etc/libretools.conf + +cmd=${0##*/} + +usage() { + echo "Usage: $cmd <pkgname> [<pkgname2> ...]" + echo "Requirements:" + echo " * Have a <pkgname>/ directory with nonfree build scripts inside" + echo " * Have a <pkgname>-libre/ directory with libre build scripts inside" +} + +main() { + local packages=("$@") + if [[ ${packages[#]} = 0 ]]; then + usage + exit 1 + fi + + for package in "${packages[@]}"; do + if [[ ! -f ./${package}/PKGBUILD || ! -f ./${package}-libre/PKGBUILD ]] + then + error "Build scripts not found for ${package}(-libre)" + else + + . ./${package}-libre/PKGBUILD + [[ -z ${pkgbase} ]] && pkgbase=${pkgname} + + # Generate a diff file, no -r since we don't want to patch src/ nor pkg/ + diff -auN ${package} ${package}-libre > $PATCHDIR/${pkgbase}-${pkgver}-${pkgrel}.patch + done + + exit 0 +} + +main "$@" diff --git a/src/libremessages b/src/libremessages new file mode 100755 index 0000000..ccb5fb4 --- /dev/null +++ b/src/libremessages @@ -0,0 +1,85 @@ +#!/bin/bash +# 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> +# +# 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 # +################################################################################ + +# This is only installed in Parabola's distribution of devtools, not Arch's +. /usr/share/devtools/common.sh + +################################################################################ +# gettext initialization # +################################################################################ + +export TEXTDOMAIN='libretools' +export TEXTDOMAINDIR='/usr/share/locale' + +################################################################################ +# Devtools overrides # +################################################################################ + +# Override several functions with built-in text to uses gettext + +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 +} + +stat_done() { + printf "${BOLD}$(gettext "done")${ALL_OFF}\n" >&2 +} + +################################################################################ +# Own functions # +################################################################################ + +stdnull() { + eval "$@ >/dev/null 2>&1" +} + +# Set the terminal title +term_title() { + 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 + _libremessages_cmd=$1 + shift + "$_libremessages_cmd" "$@" + unset _libremessages_cmd +fi diff --git a/src/librerepkg b/src/librerepkg new file mode 100755 index 0000000..85c58d9 --- /dev/null +++ b/src/librerepkg @@ -0,0 +1,69 @@ +#!/bin/bash +# Copyright 2011 Joshua Ismael Haase Hernandez + +# ---------- 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/>. + +. /etc/libretools.conf +. /etc/makepkg.conf +. /etc/abs.conf + +cmd=${0##*/} + +usage() { + echo "cd to a dir with a rePKGBUILD and other file info and run" + echo "$cmd [makepkg flags]" + echo "" + echo "This script will repackage an arch package without compiling" +} + +main() { + while getopts 'h' arg; do + case $arg in + h) usage; exit 0 ;; + esac + done + makepkgflags=("$@") + + if [[ ! -r rePKGBUILD ]]; then + error "This build does not contains a rePKGBUILD." + exit 1 + fi + . rePKGBUILD + + tempdir="$(mktemp --tmpdir -d ${PWD##*/}.XXXXX)" + + msg "Copying files" + cp ./* "${tempdir}/" + + for _arch in "${arch[@]}"; do + msg "Repackaging: $pkgname $pkgver-$pkgrel ($(date -u))" + stdnull pushd "${tempdir}" + + msg2 "Updating md5sums" + makepkg -gp rePKGBUILD >> rePKGBUILD + + echo "export CARCH=${_arch}" >> rePKGBUILD + + msg "Repackaging using makepkg" + makepkg -Lcdp rePKGBUILD "${makepkgflags[@]}" + + stdnull popd "${tempdir}" + done +} + +main "$@" diff --git a/src/libretools.conf b/src/libretools.conf new file mode 100644 index 0000000..777758c --- /dev/null +++ b/src/libretools.conf @@ -0,0 +1,104 @@ +#!/bin/bash + +################################################################################ +# misc # +################################################################################ + +## Blacklist URL +## Used by `pkgbuild-check-nonfree` +BLACKLIST=http://repo.parabolagnulinux.org/docs/blacklist.txt + +## Diff tool (vimdiff, gvimdiff, meld, etc) +## Used by `aur`, `diff-unfree` +DIFFTOOL=`which vimdiff gvimdiff meld colordiff diff 2>/dev/null|sed 's/\s.*//;1q'` + +## The repos you'll be packaging for +## Used by `toru`, `createworkdir`, `prfullpkg` +# 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 +## Used by `librestage` +ARCHES=('i686' 'x86_64' 'mips64el' 'any') + +################################################################################ +# abslibre # +################################################################################ + +# The dir where you work on +WORKDIR=/home/$USER/packages + +## Package signing +SIGEXT=".sig" +#SIGID="0xYOURID" + +## Parabola hostname +PARABOLAHOST=parabola +## Assumes something similar in your .ssh/config: + +## Repo server +# Host parabola +# Port 1863 +# HostName repo.parabolagnulinux.org +# User repo + +## Server destination of libre packages +# Don't change unless you know what you're doing and you won't screw +# anything ;) +LIBREDESTDIR=/srv/http/repo/public + +## ABSLibre +ABSLIBREGIT=http://projects.parabolagnulinux.org/abslibre.git + +## Commit Command +## Should be git or hg +## Uncomment only one of those +COMMITCMD=git +#COMMITCMD=hg + +################################################################################ +# fullpkg # +################################################################################ + +## Uncomment one of those or make one of your choice +# Normal fullpkg +FULLBUILDCMD="sudo libremakepkg" +# Cross compiling fullkpg +# FULLBUILDCMD="sudo libremakepkg -n cross-compile-chroot" +# Build from within the chroot (or host system) +# FULLBUILDCMD="makepkg -sL --noconfirm" + +# Run a command before releasing a package (ie. SSH connection, SSH tunnel, etc.) +HOOKPRERELEASE="ssh -fN parabola" + +# Run a command before running FULLBUILDCMD, usually to cleanup uneeded packages +# Note! chcleanup *is not* chroot aware, if you run it as it is it will cleanup +# your system +# HOOKPREBUILD="chcleanup" + +# Locally release the package or any other action after running FULLBUILDCMD +# succesfully +# HOOKLOCALRELEASE="" + +################################################################################ +# toru # +################################################################################ + +TORUPATH=/var/lib/libretools/toru + +################################################################################ +# Stub for old programs; wouldn't normally be in a .conf file # +################################################################################ + +if [[ -z ${INCLUDE_CONF_SH:-} ]]; then + . /usr/share/libretools/conf.sh + if [[ -e "$XDG_CONFIG_HOME/libretools/libretools.conf" ]]; then + . "$XDG_CONFIG_HOME/libretools/libretools.conf" + fi + check_conf_libretools || exit $? + + . /usr/bin/libremessages +fi diff --git a/src/mips64el-tools/Makefile b/src/mips64el-tools/Makefile new file mode 100644 index 0000000..f2cec54 --- /dev/null +++ b/src/mips64el-tools/Makefile @@ -0,0 +1,3 @@ +libre_execdir=$(bindir) +libre_datadir=$(sysconfdir)/libretools.d +include ../../common.mk diff --git a/src/mips64el-tools/add-mips64el b/src/mips64el-tools/add-mips64el new file mode 100755 index 0000000..e06d857 --- /dev/null +++ b/src/mips64el-tools/add-mips64el @@ -0,0 +1,6 @@ +#!/bin/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..f7d3a25 --- /dev/null +++ b/src/mips64el-tools/librebasebuilder @@ -0,0 +1,84 @@ +#!/bin/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) + +mkarchroot -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..da9b431 --- /dev/null +++ b/src/mips64el-tools/mips-add @@ -0,0 +1,7 @@ +#!/bin/bash +source /etc/libretools.conf +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" + librecommit PKGBUILD +fi diff --git a/src/mips64el-tools/mips64el.conf b/src/mips64el-tools/mips64el.conf new file mode 100644 index 0000000..836b407 --- /dev/null +++ b/src/mips64el-tools/mips64el.conf @@ -0,0 +1,12 @@ +## Arquitecture specific commands + +## Run a command for PKGBUILD modifications before building +## Like adding 'mips64el' to arch if it's not there +# HOOKPKGBUILDMOD="mips-add" + +## Run a command for local releasing of packages +# Useful for mass packaging (ie. mips port) +# Must accept the following parameters even if the command won't use them: +# $1 repo name +# $2+ packages +# HOOKLOCALRELEASE="mipsrelease" diff --git a/src/mips64el-tools/mipsrelease b/src/mips64el-tools/mipsrelease new file mode 100755 index 0000000..4d7a7de --- /dev/null +++ b/src/mips64el-tools/mipsrelease @@ -0,0 +1,65 @@ +#!/bin/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 + +source /etc/makepkg.conf +source /etc/libretools.conf + +libretoolsdir="$(dirname $0)/../" + +usage() { + echo "$0 repo package1 [ package2 ... packageN ]" + echo + echo " release packages locally on ${PKGDEST}/stage3." + echo " and make a clean ABS sync " +} + +## +# usage : get_full_version( $epoch, $pkgver, $pkgrel ) +# return : full version spec, including epoch (if necessary), pkgver, pkgrel +## +get_full_version() { + if [[ $1 -eq 0 ]]; then + # zero epoch case, don't include it in version + echo $2-$3 + else + echo $1:$2-$3 + fi +} + +repo=$1; shift + +if [ -z "${repo}" ]; then + error "Empty repo" + exit 1 +fi + +# Get all needed sources +source PKGBUILD +fullver=$(get_full_version ${epoch:-0} ${pkgver} ${pkgrel}) +pkgs=() +makepkg --source -f --skippgpcheck + +msg "Adding packages to [stage3]..." +for name in ${pkgname[@]}; do + msg2 "${name} ${fullver}" + pkgs+=("${PKGDEST}/${name}-${fullver}-*.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]}}-${fullver}${SRCEXT} +popd >/dev/null + +exit $? diff --git a/src/pkgbuild-check-nonfree b/src/pkgbuild-check-nonfree new file mode 100755 index 0000000..0fd480c --- /dev/null +++ b/src/pkgbuild-check-nonfree @@ -0,0 +1,187 @@ +#!/bin/bash +# pkgbuild-check-nonfree +# Copyright 2010 Joshua Ismael Haase Hernández, Joseph Graham +# Copyright 2012 Luke Shumaker + +# ---------- 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/>. + +. /etc/libretools.conf + +cmd=${0##*/} +ev=0 + +# log_end() { +# kill "$teepid" +# rm "$logpipe" +# } + +# log() { +# local LOG="pkgbuild-check-nonfree-$(date -u +%Y%m%d).log" +# # ensure overridden package variables survive tee with split packages +# logpipe="$(mktemp)" +# mkfifo "$logpipe" +# tee "$LOG" < "$logpipe" & +# teepid=$! +# trap log_end ERR EXIT +# } + + +unset_pkgbuild() { + unset 'pkgbase' 'pkgname' 'pkgver' 'pkgrel' 'epoch' 'pkgdesc' \ + 'arch' 'url' 'license' 'groups' 'optdepends' 'provides' \ + 'conflicts' 'replaces' 'backup' 'options' 'install' \ + 'changelog' 'source' 'noextract' 'md5sums' 'build' \ + 'check' 'package' 'depends' 'makedepends' 'checkdepends' +} + +assert_pkgbuild() { + if [ -e "$1" ]; then + + source "$1" + if [ -n "${pkgname[0]}" ]; then + return 0 # valid PKGBUILD + fi + + fi + + error "$1 is not a valid PKGBUILD" + return 1 +} + +check_replacement() { + [ $2 ] || return 0 # Free (not found) + local needle=$1; shift + local item + local rep + for line in $@; do + + local item="$(echo "$line" | cut -d':' -f1)" + local rep="$(echo "$line" | cut -s -d':' -f2)" + + if [ "$item" == "$needle" ]; then + if [ -z "$rep" ]; then + return 15 # Nonfree (found) + else + echo "$rep" + return 0 # Free (has replacement) + fi + fi + + done + return 0 # Free (not found) +} + +## +# Download the blacklist. +## +get_blacklist() { + mkdir -p "$XDG_CONFIG_HOME/libretools" + pushd "$XDG_CONFIG_HOME/libretools" >/dev/null + + msg "Downloading the blacklist of proprietary software packages." + + if ! wget -N -q -O blacklist.txt "${BLACKLIST}" 2>/dev/null; then + + if [ -e "$XDG_CONFIG_HOME/libretools/blacklist.txt" ]; then + warning "Using local copy of blacklist" + else + error "Download failed, exiting" + fi + + fi + + popd > /dev/null +} + +## +# Check wheter a package depends on non-free +## +check_deps() { + unset_pkgbuild + if ! assert_pkgbuild "$1"; then + exit 1 # not PKGBUILD + fi + + msg2 "${pkgbase:-${pkgname[0]}} $pkgver $pkgrel ${epoch:-""}" # > "$logpipe" + + for pkg in "${pkgname[@]}" "${depends[@]}" "${makedepends[@]}" "${checkdepends[@]}"; do + + local lines=($(grep "$pkg" "$XDG_CONFIG_HOME/libretools/blacklist.txt" | tr " " "_")) + + local rep="$(check_replacement $pkg ${lines[@]})" + local freedom=$? + + if [[ $freedom = 15 ]]; then + warning "found $pkg" # > "$logpipe" + ev=15 + elif [ -n "$rep" ]; then + if [ "$rep" = "$pkg" ]; then + plain "$pkg is repackaged with the same name." # > "$logpipe" + else + plain "$pkg -> $rep" # > "$logpipe" + fi + fi + done +} + +usage() { + # TODO: implement PKGBUILD arguments + echo "Usage: $cmd [OPTIONS] [PKGBUILD1 PKGBUILD2 ...]" + echo "" + echo "If no PKGBUILD is specified, \`./PKGBUILD' is implied" + echo "" + echo "Options:" + echo " -f Allow running as root user" + echo " -h Show this message" +} + +main() { + local asroot=false + while getopts 'fh' arg; do + case "$arg" in + f) asroot=true;; + h) usage; exit 0;; + *) usage; exit 1;; + esac + done + shift $(($OPTIND - 1)) + pkgbuilds=("$@") + if [[ $# < 1 ]]; then + pkgbuilds=("`pwd`/PKGBUILD") + fi + + if [[ -w / ]] && ! $asroot; then + error "Run as normal user" + exit 1 + fi + + get_blacklist + # log + + msg "Looking for unfree dependencies" + + for p in "${pkgbuilds[@]}"; do + if [[ -n "$p" ]]; then + check_deps "$p" + fi + done + + return $ev +} + +main "$@" diff --git a/src/toru/Makefile b/src/toru/Makefile new file mode 100644 index 0000000..f2cec54 --- /dev/null +++ b/src/toru/Makefile @@ -0,0 +1,3 @@ +libre_execdir=$(bindir) +libre_datadir=$(sysconfdir)/libretools.d +include ../../common.mk diff --git a/src/toru/toru b/src/toru/toru new file mode 100755 index 0000000..28f0b8a --- /dev/null +++ b/src/toru/toru @@ -0,0 +1,314 @@ +#!/bin/bash +# Queries the ABS +# License: GPL3 + +## TODO +# * Add license text +# * Create symlinks from pkgbase to pkgname[@] for easy package finding + +## GOALS +# * Have a searchable database of PKGBUILD metadata +# * Have an interface for source-only builds +# * Possibility to hook up ABS dirs besides ABSROOT (low priority) +# * Tell updates and non available binary packages (working on this) + +source $(dirname $(command -v $0))/toru-utils + +# Saves contents on a named cache +# $1 cache name (repo) +# $2+ contents +function store_cache { + cache=$1; shift + + [ -z "$cache" ] && return 1 + + cat $@ > ${TORUPATH}/${cache}.cache + + return $? +} + +# Return cache contents +# $1 cache name +read_cache() { + cat ${TORUPATH}/${1}.cache 2>/dev/null + + return $? +} + +## +# usage : get_full_version( $epoch, $pkgver, $pkgrel ) +# return : full version spec, including epoch (if necessary), pkgver, pkgrel +## +get_full_version() { + if [[ $1 -eq 0 ]]; then + # zero epoch case, don't include it in version + echo $2-$3 + else + echo $1:$2-$3 + fi +} + +# Outputs an ordered package-fullpkgver array +print_package_array() { + echo "$@" | tr " " "\n" | sort -u +} + + +# Gets repo.db contents (unordered) +# $1 repo +get_db_contents() { + [ ! -r /var/lib/pacman/sync/$1.db ] && return 0 + + bsdtar -tf /var/lib/pacman/sync/$1.db | cut -d'/' -f1 | sort -u +} + +# Get the pkgname +# pkgname from pkgver separator can be either '-' or ' ' +extract_pkgname() { + echo "$@" | tr " " "\n" | sed "s/^\(.\+\)[- ][^-]\+-[^-]\+$/\1/" +} + +# Get all the pkgnames from a file +# pkgname from pkgver separator can be either '-' or ' ' +extract_pkgname_from_file() { + sed "s/^\(.\+\)[- ][^-]\+-[^-]\+$/\1/" $1 +} + +# Split pkgnames from pkgvers +split_pkgname_from_pkgver() { + sed "s/^\(.\+\)-\([^-]\+-[^-]\+\)$/\1 \2/" $1 +} + +# Get the fullpkgver +# pkgname from pkgver separator can be either '-' or ' ' +extract_fullpkgver() { + echo "$@" | tr " " "\n" | sed "s/^.\+[ -]\([^-]\+-[^-]\+\)$/\1/" +} + +# Checks if $1 is a valid repo +is_repo() { + if ! in_array ${1} ${REPOS[@]}; then + $quiet || warning "${1} is not a valid repo (check REPOS array at libretools.conf)" + return 1 + fi +} + +# Updates the database by finding all PKGBUILDS +# Workflow: +# * Find all PKGBUILDs on the ABS repo specified +# * Get all packages already on package repos +# * Compare them +# Args: +update() { + local update_sync_file=false +# The PKGBUILDs found + local -a pkgbuilds=() +# The list of pkgname-fullpkgver + local -a packages_in_abs=() + local -a pkg_updates=() + local -a package_paths=() + +# Traverse all specified repos + for __repo in $@; do +# Check if the repo is set as such, otherwise skip + is_repo ${__repo} || continue + +# Fullpath of the repo + _repopath=$(readlink -f ${__repo}) + +# This is the syncfile, stores the last date as content and mtime + local lastsyncfile=${TORUPATH}/${__repo}.lastsync + +# Find all the PKGBUILDs newer than the last update +# Update newer, otherwise everything + if [[ $force = true || ! -e ${lastsyncfile} ]]; then + + $quiet || warning "Forcing upgrade" +# Get all PKGBUILDs + pkgbuilds=($(find ${_repopath} -maxdepth 2 -type f -name 'PKGBUILD')) + + else + +# Only find newer than lastsyncfile and read everything else from cache + pkgbuilds=($(find ${_repopath} -maxdepth 2 -type f -name 'PKGBUILD' -newer ${lastsyncfile})) + packages_in_abs=($(read_cache ${__repo})) + + $quiet || msg2 "Getting ${#packages_in_abs[@]} packages from cache" + + fi + + package_paths=($(read_cache ${__repo}.paths || true)) + +# Inform how many PKGBUILDS were found and quit immediately if none + $quiet || msg "Found $((${#pkgbuilds[*]}-1)) PKGBUILDs to update" + +# Traverse all found PKGBUILDs + for _pkgbuild in ${pkgbuilds[@]}; do +# Update the sync file because there are pkgbuilds to update + update_sync_file=true + +# Load PKGBUILD's metadata + source ${_pkgbuild} || continue + +# Guess pkgbase from PKGBUILD's basedir + _pkgpath=$(dirname "${_pkgbuild}") + _pkgbase=${pkgbase:-${pkgname[0]}} + +# We won't need this (all unsets are for memory efficiency) + unset build package url md5sums install pkgdesc backup options +# TODO fill a license list + unset license +# TODO create source tarballs? + unset mksource +# TODO solve dependency tree? + unset depends makedepends + + for _pkg in ${pkgname[@]}; do +# Keep removing unneeded stuff + unset package_${_pkg} >/dev/null 2>&1 || true +# Fill the list of packages to find + packages_in_abs+=($_pkg-$(get_full_version ${epoch:-0} $pkgver $pkgrel)) + package_paths+=($_pkg:$_pkgpath) + done # end pkgnames + + unset pkgbase pkgname pkgver pkgrel source epoch + done # end pkgbuilds + +# Sync! (Only if there was an actual sync) + ${update_sync_file} && lastsync ${lastsyncfile} + + if [ "${lastsyncfile}" -nt "${TORUPATH}/${__repo}.paths.cache" ]; then + print_package_array "${package_paths[@]}" > $TMPDIR/paths + store_cache ${__repo}.paths $TMPDIR/paths + fi + +# If there isn't an update cache or it's older than the last update, we check + if [ "${lastsyncfile}" -nt "${TORUPATH}/${__repo}.updates.cache" ]; then + +# Get repo database contents + packages_in_sync=($(get_db_contents ${__repo})) +# Drops arrays into files + print_package_array "${packages_in_abs[@]}" > ${TMPDIR}/packages_in_abs + print_package_array "${packages_in_sync[@]}" > ${TMPDIR}/packages_in_sync + +# Work with files + unset packages_in_abs package_in_sync + +# Use a different separator for pkgnames and pkgvers +# so we can join them by pkgname (first field) + split_pkgname_from_pkgver ${TMPDIR}/packages_in_abs | sort -k1b,1 > ${TMPDIR}/in_abs + split_pkgname_from_pkgver ${TMPDIR}/packages_in_sync | sort -k1b,1 > ${TMPDIR}/in_sync + + $quiet || msg "These packages are available to update" +# Join both files by pkgname, the end result is: +# pkgname syncver absver + join ${TMPDIR}/in_sync ${TMPDIR}/in_abs | \ + while read need_line; do + _pkg=$(echo "${need_line}" | cut -d' ' -f1) + _syncver=$(echo "${need_line}" | cut -d' ' -f2) + _absver=$(echo "${need_line}" | cut -d' ' -f3) + +# If the versions differ we need an update +# TODO move this to update query + if [ "${_syncver}" != "${_absver}" ]; then + $quiet || msg2 "$_pkg update from $_syncver to $_absver" + $quiet && echo "$_pkg" + +# FIXME this works all right but it's unset once the while ends + #pkg_updates+=("$_pkg") + +# Fix for the above problem, but it access the file every time instead of +# puting all packages together once + echo $_pkg >> ${TMPDIR}/updates + + fi + done # end need_line + + unset _pkg _syncver _absver need_line + +# Save the cache + store_cache ${__repo} ${TMPDIR}/packages_in_abs + +# See above FIXME + # print_package_array "${updates[@]}" > ${TMPDIR}/updates + if [ -r ${TMPDIR}/updates ]; then + store_cache ${__repo}.updates ${TMPDIR}/updates + fi + + else + $quiet || msg "Reading updates from cache..." + read_cache ${__repo}.updates + fi + + done # end repos +} + +# Find all the packages that are missing from the repo dbs (aka not built) +missing() { + true +} + +## Finds a PKGBUILD on toru's path cache +## usage: where_is <pkgname> +# Look in all caches but pick the first one +where_is() { + local __repo + local _path + for __repo in ${REPOS[@]}; do + _path=$(grep "^${1}:" "${TORUPATH}/${__repo}.paths.cache" 2>/dev/null | + cut -d: -f2) + + [ -n "${_path}" ] && break + done + + [ -z "$_path" ] && return 1 + + echo ${_path} +} + +# TODO: clean usage instructions +function usage { + echo "" + echo "$0 [options] repo1 ... repon" + echo "" + echo "Make a db containing PKGBUILD metadata." + echo "" + echo "-h : this message" +# echo "-a : update all repos at once" + echo "-u : update repo information" + echo "-q : quiet" + echo "-f : rebuild the db even if it is updated" + echo "-p <pkgname>: return the path for pkgname" + echo "" + exit 1 +} + +## MAIN +commands=() +repos=() +quiet=false +force=false +while getopts 'haqfpum' arg; do + case $arg in + h) usage; exit 0 ;; +# TODO: Update all repos on $REPOS array +# a) update_all_repos ;; + q) quiet=true ;; + f) force=true ;; + u) commands+=(update);; + p) shift $(( OPTIND - 1 )) + where_is "$1" || exit 1;; + m) commands+=(missing);; + esac + + shift $(( OPTIND - 1 )) +done + + +TMPDIR=$(mktemp -d) + +[[ -z ${TMPDIR} ]] && exit 1 + +${commands[0]} ${@} + +exit $? diff --git a/src/toru/toru-info b/src/toru/toru-info new file mode 100755 index 0000000..523f682 --- /dev/null +++ b/src/toru/toru-info @@ -0,0 +1,28 @@ +#!/bin/bash +# Prints info about a given pkgname +source /etc/libretools.conf + +for _pkg in $@; do + _pkgbuild="$(toru-where $_pkg)" + + if [ -f "$_pkgbuild/PKGBUILD" ]; then + source "$_pkgbuild/PKGBUILD" 2>/dev/null || { + warning "Errors on %s" $_pkg + continue + } + + deps="${depends[@]} ${makedepends[@]} ${checkdepends[@]}" + repo="$(basename $(dirname "$_pkgbuild"))" + + unset build package depends makedepends checkdepends optdepends source md5sums + + msg "%s/%s %s-%s" $repo $_pkg $pkgver $pkgrel + msg2 "$pkgdesc" + msg2 "$url" + msg2 "Depends: ${deps}" + else + warning "%s doesn't exist" $_pkg + fi + + unset pkgname pkgver pkgrel pkgdesc url +done diff --git a/src/toru/toru-path b/src/toru/toru-path new file mode 100755 index 0000000..baeaeb5 --- /dev/null +++ b/src/toru/toru-path @@ -0,0 +1,50 @@ +#!/bin/bash + +source $(dirname $(command -v $0))/toru-utils + +TORUPATH=${T:-${TORUPATH}} +VERBOSE=${V:-false} + +if [ ! -w "$TORUPATH" ]; then + error "Toru's path isn't writable. Please check $TORUPATH" + exit 1 +fi + +LASTSYNCFILE=${TORUPATH}/lastsync.paths +PATHFILE=${TORUPATH}/paths.tch + +if [ ! -e "${PATHFILE}" ]; then + tcamgr create "${PATHFILE}" +fi + +# TODO pass other paths via flags +# ABSROOT has trailing slash +fullrepos=() +for (( i = ${#REPOS[@]}-1 ; i >= 0 ; i-- )); do + ${VERBOSE} && msg "Processing [%s]" ${REPOS[$i]} + + [ -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" + source ${_pkgbuild} >/dev/null 2>&1 || { + error "${_pkgbuild} contains errors, skipping" + continue + } + + fullpath=$(dirname ${_pkgbuild}) + + for _pkg in ${pkgbase} ${pkgname[@]} ${provides[@]}; do + $VERBOSE && msg2 "${_pkg} -> ${fullpath}" + tcamgr put ${PATHFILE} ${_pkg/[<>=]*} ${fullpath} + done + + unset pkgbase pkgname provides +done + +lastsync ${LASTSYNCFILE} diff --git a/src/toru/toru-utils b/src/toru/toru-utils new file mode 100755 index 0000000..316e6b8 --- /dev/null +++ b/src/toru/toru-utils @@ -0,0 +1,76 @@ +#!/bin/bash + +source /etc/abs.conf +source /etc/libretools.conf + +LASTSYNCFILE=${TORUPATH}/lastsync +FORCE=false +QUIET=false +DEBUG=false + +# usage : in_array( $needle, $haystack ) +function in_array { + [[ $2 ]] || return 1 # Not found + + local needle=$1; shift + local item + + for item in "$@"; do + [[ ${item#@} = $needle ]] && return 0 # Found + done + + return 1 # Not Found +} + +# Stores the lastsync date +lastsync() { + local lastsyncfile + + lastsyncfile=$1 + + [ -e ${lastsyncfile} -a ! -w ${lastsyncfile} ] && { + error "The sync date can't be saved. ${lastsyncfile} isn't writable." + return 1 + } + + date +%s > ${lastsyncfile} + touch ${lastsyncfile} +} + +get_dbs() { + local _db + for _db in /var/lib/pacman/sync/*.db; do + bsdtar tf ${_db} | cut -d'/' -f1 | sort -u + done +} + +# repo paths +get_pkgbuilds() { + pkgbuilds=() + + if [[ $FORCE = true || ! -e ${LASTSYNCFILE} ]]; then + + $QUIET || warning "Forcing upgrade" +# Get all PKGBUILDs + extra="" + else +# Only find newer than lastsyncfile and read everything else from cache + extra=" -newer ${LASTSYNCFILE}" + fi + +# Return all PKGBUILDs found + find $@ -mindepth 2 -maxdepth 3 -type f -name 'PKGBUILD' ${extra} +} + +# End inmediately but print a useful message +trap_exit() { + error "$@" + + exit 1 +} + +# Trap signals from makepkg +set -E +trap 'trap_exit "TERM signal caught. Exiting..."' TERM HUP QUIT +trap 'trap_exit "Aborted by user! Exiting..."' INT +trap 'trap_exit "An unknown error has occurred. Exiting..."' ERR diff --git a/src/toru/toru-where b/src/toru/toru-where new file mode 100755 index 0000000..e9ab29d --- /dev/null +++ b/src/toru/toru-where @@ -0,0 +1,7 @@ +#!/bin/bash +# Locates a PKGBUILD dir on toru's path cache +source /etc/libretools.conf + +PATHFILE=${TORUPATH}/paths.tch + +tcamgr get ${PATHFILE} $1 2>/dev/null || echo "" diff --git a/src/treepkg b/src/treepkg new file mode 100755 index 0000000..8c4cc8e --- /dev/null +++ b/src/treepkg @@ -0,0 +1,237 @@ +#!/bin/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 /etc/libretools.conf +source $XDG_CONFIG_HOME/libretools/libretools.conf >/dev/null 2>&1|| true + +term_title "$(basename $0)" + +# Get system variables +source /etc/makepkg.conf +source $HOME/makepkg.conf >/dev/null 2>&1|| true + +# 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 + +# return : full version spec, including epoch (if necessary), pkgver, pkgrel +# usage : get_fullver( ${epoch:-0}, $pkgver, $pkgrel ) +get_fullver() { + if [ $1 -eq 0 ]; then +# zero epoch case, don't include it in version + echo $2-$3 + else + echo $1:$2-$3 + fi + +} + +# 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}};${fullver};${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 ! source 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]}}" +fullver=$(get_fullver ${epoch:-0} ${pkgver} ${pkgrel}) + +# 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}" -a ${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}" "${fullver}"; 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}" -o ! -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 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 $? |