index : pacman | |
Archlinux32 fork of pacman | gitolite user |
summaryrefslogtreecommitdiff |
author | Dan McGee <dan@archlinux.org> | 2007-07-06 18:43:24 -0400 |
---|---|---|
committer | Dan McGee <dan@archlinux.org> | 2007-07-06 18:43:24 -0400 |
commit | b5f8a44bebc906bf6a29d30c159802b0c1a7dbb1 (patch) | |
tree | b5096ea45a1a8b48e12dd14c446dda346c71688a /scripts/makepkg.sh.in | |
parent | 49f447d02c803e5a2f63582ce78cabb850ebfa89 (diff) |
-rw-r--r-- | scripts/makepkg.sh.in | 1334 |
diff --git a/scripts/makepkg.sh.in b/scripts/makepkg.sh.in new file mode 100644 index 00000000..8be44c65 --- /dev/null +++ b/scripts/makepkg.sh.in @@ -0,0 +1,1334 @@ +#!/bin/bash -e +# +# makepkg - make packages compatable for use with pacman +# @configure_input@ +# +# Copyright (c) 2002-2007 by Judd Vinet <jvinet@zeroflux.org> +# Copyright (c) 2005 by Aurelien Foret <orelien@chez.com> +# Copyright (c) 2006 by Miklos Vajna <vmiklos@frugalware.org> +# Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu> +# Copyright (c) 2006 by Alex Smith <alex@alex-smith.me.uk> +# Copyright (c) 2006 by Andras Voroskoi <voroskoi@frugalware.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +# USA. +# + +# gettext initialization +export TEXTDOMAIN='pacman' +export TEXTDOMAINDIR='@localedir@' + +myver='@PACKAGE_VERSION@' +confdir='@sysconfdir@' +startdir="$PWD" +srcdir="$startdir/src" +pkgdir="$startdir/pkg" + +# Options +ASROOT=0 +CLEANUP=0 +CLEANCACHE=0 +DEP_BIN=0 +DEP_SRC=0 +FORCE=0 +INFAKEROOT=0 +GENINTEG=0 +INSTALL=0 +NOBUILD=0 +NODEPS=0 +NOEXTRACT=0 +RMDEPS=0 +REPKG=0 +LOGGING=0 +SOURCEONLY=0 +IGNOREARCH=0 + +PACMAN_OPTS= + +### SUBROUTINES ### + +plain() { + local mesg=$1; shift + if [ ! "$USE_COLOR" = "n" -a "$(check_buildenv color)" = "y" ]; then + printf "\033[1;37m ${mesg}\033[0m\n" "$@" >&2 + else + printf " ${mesg}\n" "$@" >&2 + fi +} + +msg() { + local mesg=$1; shift + if [ ! "$USE_COLOR" = "n" -a "$(check_buildenv color)" = "y" ]; then + printf "\033[1;32m==>\033[1;37m ${mesg}\033[0m\n" "$@" >&2 + else + printf "==> ${mesg}\n" "$@" >&2 + fi +} + +msg2() { + local mesg=$1; shift + if [ ! "$USE_COLOR" = "n" -a "$(check_buildenv color)" = "y" ]; then + printf "\033[1;34m ->\033[1;37m ${mesg}\033[0m\n" "$@" >&2 + else + printf " -> ${mesg}\n" "$@" >&2 + fi +} + +warning() { + local mesg=$1; shift + if [ ! "$USE_COLOR" = "n" -a "$(check_buildenv color)" = "y" ]; then + printf "\033[1;33m==> $(gettext "WARNING:")\033[1;37m ${mesg}\033[0m\n" "$@" >&2 + else + printf "==> $(gettext "WARNING:") ${mesg}\n" "$@" >&2 + fi +} + +error() { + local mesg=$1; shift + if [ ! "$USE_COLOR" = "n" -a "$(check_buildenv color)" = "y" ]; then + printf "\033[1;31m==> $(gettext "ERROR:")\033[1;37m ${mesg}\033[0m\n" "$@" >&2 + else + printf "==> $(gettext "ERROR:") ${mesg}\n" "$@" >&2 + fi +} + + +## +# Special exit call for traps, Don't print any error messages when inside, +# the fakeroot call, the error message will be printed by the main call. +## +trap_exit() { + if [ "$INFAKEROOT" = "0" ]; then + echo + error "$@" + fi + exit 1 +} + + +## +# Clean up function. Called automatically when the script exits. +## +clean_up() { + local EXIT_CODE=$? + + if [ "$INFAKEROOT" = "1" ]; then + # Don't clean up when leaving fakeroot, we're not done yet. + return + fi + + if [ $EXIT_CODE -eq 0 -a "$CLEANUP" = "1" ]; then + # If it's a clean exit and -c/--clean has been passed... + msg "$(gettext "Cleaning up...")" + cd "$startdir" + rm -rf pkg src + if [ "$pkgname" != "" ]; then + # Can't do this unless the BUILDSCRIPT has been sourced. + rm -f "${pkgname}-${pkgver}-${pkgrel}-${CARCH}.log*" + fi + fi + + remove_deps +} + + +## +# Signal Traps +## +trap 'clean_up' 0 +trap 'trap_exit "$(gettext "TERM signal caught. Exiting...")"' TERM HUP QUIT +trap 'trap_exit "$(gettext "Aborted by user! Exiting...")"' INT +trap 'trap_exit "$(gettext "An unknown error has occured. Exiting...")"' ERR + + +strip_url() { + echo "$1" | sed 's|^.*://.*/||g' +} + + +## +# Checks to see if options are present in makepkg.conf or PKGBUILD; +# PKGBUILD options always take precedence. +# +# usage : check_option( $option ) +# return : y - enabled +# n - disabled +# ? - not found +## +check_option() { + local ret=$(in_opt_array "$1" ${options[@]}) + if [ "$ret" != '?' ]; then + echo $ret + return + fi + + # BEGIN DEPRECATED + # TODO: This code should be removed in the next release of makepkg. + local needle=$(echo $1 | tr [:upper:] [:lower:]) + local opt + for opt in ${options[@]}; do + opt=$(echo $opt | tr [:upper:] [:lower:]) + if [ "$opt" = "no$needle" ]; then + warning "$(gettext "Options beginning with 'no' will be deprecated in the next version of makepkg!")" + plain "$(gettext "Please replace 'no' with '!': %s -> %s.")" "no$needle" "!$needle" + echo 'n' # Disabled + return + elif [ "$opt" = "keepdocs" -a "$needle" = "docs" ]; then + warning "$(gettext "Option 'keepdocs' may not work as intended. Please replace with 'docs'.")" + echo 'y' # Enabled + return + fi + done + # END DEPRECATED + + # fall back to makepkg.conf options + ret=$(in_opt_array "$1" ${OPTIONS[@]}) + if [ "$ret" != '?' ]; then + echo $ret + return + fi + + echo '?' # Not Found +} + + +## +# Check if option is present in BUILDENV +# +# usage : check_buildenv( $option ) +# return : y - enabled +# n - disabled +# ? - not found +## +check_buildenv() { + echo $(in_opt_array "$1" ${BUILDENV[@]}) +} + + +## +# usage : in_opt_array( $needle, $haystack ) +# return : y - enabled +# n - disabled +# ? - not found +## +in_opt_array() { + local needle=$(echo $1 | tr [:upper:] [:lower:]); shift + + local opt + for opt in "$@"; do + opt=$(echo $opt | tr [:upper:] [:lower:]) + if [ "$opt" = "$needle" ]; then + echo 'y' # Enabled + return + elif [ "$opt" = "!$needle" ]; then + echo 'n' # Disabled + return + fi + done + + echo '?' # Not Found +} + + +## +# usage : in_array( $needle, $haystack ) +# return : 0 - found +# 1 - not found +## +in_array() { + local needle=$1; shift + [ -z "$1" ] && return 1 # Not Found + local item + for item in "$@"; do + [ "$item" = "$needle" ] && return 0 # Found + done + return 1 # Not Found +} + +get_downloadclient() { + # $1 = url with valid protocol prefix + local url=$1 + local proto=$(echo $netfile | sed 's|://.*||') + + # loop through DOWNLOAD_AGENTS variable looking for protocol + local i + for i in "${DLAGENTS[@]}"; do + local handler=$(echo $i | sed 's|::.*||') + if [ "$proto" == "$handler" ]; then + agent=$(echo $i | sed 's|^.*::||') + break + fi + done + + # if we didn't find an agent, return an error + if [ -z "$agent" ]; then + error "$(gettext "There is no agent set up to handle %s URLs. Check %s.")" "$proto" "$confdir/makepkg.conf" + plain "$(gettext "Aborting...")" + exit 1 # $E_CONFIG_ERROR + fi + + # ensure specified program is installed + local program="$(echo $agent | awk '{print $1 }')" + if [ ! -x "$program" ]; then + local baseprog=$(basename $program) + error "$(gettext "The download program %s is not installed.")" "$baseprog" + plain "$(gettext "Aborting...")" + exit 1 # $E_MISSING_PROGRAM + fi + + echo "$agent" +} + +check_deps() { + [ $# -gt 0 ] || return + + pmout=$(pacman $PACMAN_OPTS -T $*) + ret=$? + if [ $ret -eq 1 ]; then #unresolved deps + echo "$pmout" + elif [ $ret -ne 0 ]; then + error "$(gettext "Pacman returned a fatal error (%i): %s")" "$ret" "$pmout" + exit 1 + fi +} + +handledeps() { + local R_DEPS_SATISFIED=0 + local R_DEPS_MISSING=1 + + [ $# -eq 0 ] && return $R_DEPS_SATISFIED + + local deplist="$*" + local dep depstrip striplist + for dep in $deplist; do + depstrip="$(echo $dep | sed -e 's|=.*$||' -e 's|>.*$||' -e 's|<.*$||')" + striplist="$striplist $depstrip" + done + + if [ "$DEP_SRC" = "0" -a "$DEP_BIN" = "0" ]; then + return $R_DEPS_MISSING + fi + + if [ "$DEP_BIN" = "1" ]; then + # install missing deps from binary packages (using pacman -S) + msg "$(gettext "Installing missing dependencies...")" + local ret=0 + + if [ "$ASROOT" = 0 ]; then + sudo pacman $PACMAN_OPTS -S $striplist || ret=$? + else + pacman $PACMAN_OPTS -S $striplist || ret=$? + fi + + if [ $ret -ne 0 ]; then + error "$(gettext "Pacman failed to install missing dependencies.")" + exit 1 # TODO: error code + fi + elif [ "$DEP_SRC" = "1" ]; then + msg "$(gettext "Building missing dependencies...")" + + # install missing deps by building them from source. + # we look for each package name in $SRCROOT and build it. + if [ "$SRCROOT" = "" ]; then + error "$(gettext "Source root cannot be found - please make sure it is specified in %s.")" "$confdir/makepkg.conf" + exit 1 # TODO: error code + fi + + # TODO: handle version comparators (eg, glibc>=2.2.5) + for dep in $striplist; do + local candidates="$(find "$SRCROOT" -type d -name "$dep")" + if [ "$candidates" = "" ]; then + error "$(gettext "Could not find '%s' under %s")" "$dep" "$SRCROOT" + exit 1 # TODO: error code + fi + + local makepkg_opts='-i -c -b' + [ "$RMDEPS" = "1" ] && makepkg_opts="$makepkg_opts -r" + local ret packagedir + for packagedir in $candidates; do + if [ -f "$packagedir/$BUILDSCRIPT" ]; then + cd "$packagedir" + ret=0 + PKGDEST="$PKGDEST" makepkg $makepkg_opts || ret=$? + [ $ret -eq 0 ] && continue 2 + fi + done + + error "$(gettext "Failed to build '%s'")" "$dep" + exit 1 # TODO: error code + done + fi + + # rerun any additional sh scripts found in /etc/profile.d/ + local script + for script in /etc/profile.d/*.sh; do + if [ -x $script ]; then + source $script &>/dev/null + fi + done + + return $R_DEPS_SATISFIED +} + +resolve_deps() { + # $pkgdeps is a GLOBAL variable, used by remove_deps() + local R_DEPS_SATISFIED=0 + local R_DEPS_MISSING=1 + + local deplist="$(check_deps $*)" + if [ "$deplist" = "" ]; then + return $R_DEPS_SATISFIED + else + pkgdeps="$pkgdeps $deplist" + fi + + if handledeps $deplist; then + # check deps again to make sure they were resolved + deplist="$(check_deps $*)" + [ "$deplist" = "" ] && return $R_DEPS_SATISFIED + elif [ "$DEP_BIN" = "1" -o "$DEP_SRC" = "1" ]; then + error "$(gettext "Failed to install all missing dependencies.")" + fi + + msg "$(gettext "Missing Dependencies:")" + local dep + for dep in $deplist; do + msg2 "$dep" + done + + return $R_DEPS_MISSING +} + +# fix flyspray bug #5923 +remove_deps() { + # $pkgdeps is a GLOBAL variable, set by resolve_deps() + [ "$RMDEPS" = "0" ] && return + [ "$pkgdeps" = "" ] && return + + local dep depstrip deplist + for dep in $pkgdeps; do + depstrip=$(echo $dep | sed -e 's|=.*$||' -e 's|>.*$||' -e 's|<.*$||') + deplist="$deplist $depstrip" + done + + msg "Removing installed dependencies..." + if [ "$ASROOT" = "0" ]; then + sudo pacman $PACMAN_OPTS -Rs $deplist + else + pacman $PACMAN_OPTS -Rs $deplist + fi +} + +download_sources() { + msg "$(gettext "Retrieving Sources...")" + local netfile + for netfile in ${source[@]}; do + local file=$(strip_url "$netfile") + if [ -f "../$file" ]; then + msg2 "$(gettext "Found %s in build dir")" "$file" + cp "../$file" . + continue + elif [ -f "$SRCDEST/$file" ]; then + msg2 "$(gettext "Using cached copy of %s")" "$file" + cp "$SRCDEST/$file" . + continue + fi + + # find the client we should use for this URL + local dlclient=$(get_downloadclient $netfile) || exit $? + + msg2 "$(gettext "Downloading %s...")" "$file" + # fix flyspray bug #3289 + local ret=0 + $dlclient "$netfile" || ret=$? + if [ $ret -gt 0 ]; then + error "$(gettext "Failure while downloading %s")" "$file" + plain "$(gettext "Aborting...")" + exit 1 + fi + + if [ -n "$SRCDEST" ]; then + mkdir -p "$SRCDEST" && cp "$file" "$SRCDEST" || ret=$? + if [ $ret -gt 0 ]; then + warning "$(gettext "You do not have correct permissions to cache source in %s")" "$SRCDEST" + cp "$file" .. + fi + else + cp "$file" .. + fi + done +} + +generate_checksums() { + msg "$(gettext "Generating checksums for source files...")" + plain "" + + local integ + for integ in ${INTEGRITY_CHECK[@]}; do + integ="$(echo $integ | tr [:upper:] [:lower:])" + case "$integ" in + md5|sha1|sha256|sha384|sha512) : ;; + *) + error "$(gettext "Invalid integrity algorithm '%s' specified.")" "$integ" + exit 1;; # $E_CONFIG_ERROR + esac + + if [ ! $(type -p "${integ}sum") ]; then + error "$(gettext "Cannot find the '%s' program.")" "${integ}sum" + exit 1 # $E_MISSING_PROGRAM + fi + + local ct=0 + local numsrc=${#source[@]} + echo -n "${integ}sums=(" + + local i=0; + local indent='' + while [ $i -lt $((${#integ}+6)) ]; do + indent="$indent " + i=$(($i+1)) + done + + local netfile + for netfile in ${source[@]}; do + local file="$(strip_url "$netfile")" + local sum="$(${integ}sum "$file" | cut -d ' ' -f 1)" + [ $ct -gt 0 ] && echo -n "$indent" + echo -n "'$sum'" + ct=$(($ct+1)) + [ $ct -lt $numsrc ] && echo + done + + echo ")" + done +} + +check_checksums() { + local integ + for integ in ${INTEGRITY_CHECK[@]}; do + integ="$(echo $integ | tr [:upper:] [:lower:])" + case "$integ" in + md5|sha1|sha256|sha384|sha512) : ;; + *) + error "$(gettext "Invalid integrity algorithm '%s' specified")" "$integ" + exit 1;; # $E_CONFIG_ERROR + esac + + if [ ! $(type -p "${integ}sum") ]; then + error "$(gettext "Cannot find the '%s' program.")" "${integ}sum" + exit 1 # $E_MISSING_PROGRAM + fi + + local integrity_sums=($(eval echo \${${integ}sums[@]})) + if [ ${#integrity_sums[@]} -eq ${#source[@]} ]; then + msg "$(gettext "Validating source files with %s...")" "${integ}sums" + local errors=0 + local idx=0 + local file + for file in "${source[@]}"; do + file="$(strip_url "$file")" + echo -n " $file ... " >&2 + + if echo "${integrity_sums[$idx]} $file" | ${integ}sum --status -c - &>/dev/null; then + echo "$(gettext "Passed")" >&2 + else + echo "$(gettext "FAILED")" >&2 + errors=1 + fi + + idx=$(($idx+1)) + done + + if [ $errors -gt 0 ]; then + error "$(gettext "One or more files did not pass the validity check!")" + exit 1 # TODO: error code + fi + else + warning "$(gettext "Integrity checks (%s) are missing or incomplete.")" "$integ" + fi + done +} + +extract_sources() { + msg "$(gettext "Extracting Sources...")" + local netfile + for netfile in "${source[@]}"; do + file=$(strip_url "$netfile") + if in_array "$file" ${noextract[@]}; then + #skip source files in the noextract=() array + # these are marked explicitly to NOT be extracted + continue + fi + + # fix flyspray #6246 + local file_type=$(file -biz "$file") + local cmd='' + case "$file_type" in + *application/x-tar*|*application/x-zip*|*application/x-cpio*) + cmd="bsdtar -x -f $file" ;; + *application/x-gzip*) + cmd="gunzip -d -f $file" ;; + *application/x-bzip*) + cmd="bunzip2 -f $file" ;; + *) + # Don't know what to use to extract this file, + # skip to the next file + continue;; + esac + + local ret=0 + msg2 "$cmd" + $cmd || ret=$? + if [ $ret -ne 0 ]; then + error "$(gettext "Failed to extract %s")" "$file" + plain "$(gettext "Aborting...")" + exit 1 + fi + done + + if [ $EUID -eq 0 ]; then + # chown all source files to root.root + chown -R root.root "$srcdir" + fi +} + +run_build() { + # use distcc if it is requested (check buildenv and PKGBUILD opts) + if [ "$(check_buildenv distcc)" = "y" -a "$(check_option distcc)" != "n" ]; then + [ -d /usr/lib/distcc/bin ] && export PATH="/usr/lib/distcc/bin:$PATH" + export DISTCC_HOSTS + elif [ "$(check_option distcc)" = "n" ]; then + # if it is not wanted, clear the makeflags too + MAKEFLAGS="" + fi + + # use ccache if it is requested (check buildenv and PKGBUILD opts) + if [ "$(check_buildenv ccache)" = "y" -a "$(check_option ccache)" != "n" ]; then + [ -d /usr/lib/ccache/bin ] && export PATH="/usr/lib/ccache/bin:$PATH" + fi + + # clear user-specified makeflags if requested + if [ "$(check_option makeflags)" = "n" ]; then + MAKEFLAGS="" + fi + + msg "$(gettext "Starting build()...")" + cd "$srcdir" + + # ensure we have a sane umask set + umask 0022 + + # ensure all necessary build variables are exported + export CFLAGS CXXFLAGS MAKEFLAGS + + local ret=0 + if [ "$LOGGING" = "1" ]; then + BUILDLOG="${startdir}/${pkgname}-${pkgver}-${pkgrel}-${CARCH}.log" + if [ -f "$BUILDLOG" ]; then + local i=1 + while true; do + if [ -f "$BUILDLOG.$i" ]; then + i=$(($i +1)) + else + break + fi + done + mv "$BUILDLOG" "$BUILDLOG.$i" + fi + + build 2>&1 | tee "$BUILDLOG"; ret=${PIPESTATUS[0]} + else + build 2>&1 || ret=$? + fi + + if [ $ret -gt 0 ]; then + error "$(gettext "Build Failed.")" + plain "$(gettext "Aborting...")" + remove_deps + exit 2 # $E_BUILD_FAILED + fi +} + +tidy_install() { + cd "$pkgdir" + msg "$(gettext "Tidying install...")" + + if [ "$(check_option docs)" = "n" ]; then + msg2 "$(gettext "Removing info/doc files...")" + #fix flyspray bug #5021 + rm -rf ${DOC_DIRS[@]} + fi + + if [ -d usr/share/man ]; then + msg2 "$(gettext "Moving usr/share/man files to usr/man...")" + mkdir -p usr/man + cp -a usr/share/man/* usr/man/ + rm -rf usr/share/man + fi + + + msg2 "$(gettext "Compressing man pages...")" + local manpage ext file link + find {usr{,/local},opt/*}/man -type f 2>/dev/null | while read manpage ; do + ext="${manpage##*.}" + file="${manpage##*/}" + if [ "$ext" != "gz" -a "$ext" != "bz2" ]; then + # update symlinks to this manpage + find {usr{,/local},opt/*}/man -lname "$file" 2>/dev/null | while read link ; do + rm -f "$link" + ln -sf "${file}.gz" "${link}.gz" + done + # compress the original + gzip -9 "$manpage" + fi + done + + + if [ "$(check_option strip)" = "y" ]; then + msg2 "$(gettext "Stripping debugging symbols from binaries and libraries...")" + for file in $(find {,*/}{bin,lib,sbin} -type f 2>/dev/null || true); do + case "$(file -biz "$file")" in + *application/x-sharedlib*) # Libraries + /usr/bin/strip --strip-debug "$file";; + *application/x-executable*) # Binaries + /usr/bin/strip "$file";; + esac + done + fi + + if [ "$(check_option libtool)" = "n" ]; then + msg2 "$(gettext "Removing libtool .la files...")" + find -type f -name "*.la" -exec rm -f -- '{}' \; + fi + + if [ "$(check_option emptydirs)" = "n" ]; then + msg2 "$(gettext "Removing empty directories...")" + find -depth -type d -empty -delete + fi +} + +create_package() { + if [ ! -d "$pkgdir" ]; then + error "$(gettext "Missing pkg/ directory.")" + plain "$(gettext "Aborting...")" + exit 1 # $E_MISSING_PKGDIR + fi + + cd "$pkgdir" + msg "$(gettext "Creating package...")" + + local builddate=$(LC_ALL= LANG= date -u "+%a %b %e %H:%M:%S %Y") + if [ "$PACKAGER" != "" ]; then + local packager="$PACKAGER" + else + local packager="Arch Linux (http://www.archlinux.org)" + fi + local size=$(du -sb | awk '{print $1}') + + msg2 "$(gettext "Generating .FILELIST file...")" + # The following command does the following: + # - find all directories and add a trailing / + # - find all other files/links + # - grep out dot files in root dir (e.g. .FILELIST .PKGINFO...) + # - sort the list + find -mindepth 1 \( -type d -printf '%P/\n' \) , \( ! -type d -printf '%P\n' \) \ + 2>/dev/null | grep -v '^\.' | sort >.FILELIST + + # write the .PKGINFO file + msg2 "$(gettext "Generating .PKGINFO file...")" + echo "# Generated by makepkg $myver" >.PKGINFO + if [ "$INFAKEROOT" = "1" ]; then + echo "# using $(fakeroot -v)" >>.PKGINFO + fi + echo "# $(LC_ALL= LANG= date -u)" >>.PKGINFO + echo "pkgname = $pkgname" >>.PKGINFO + echo "pkgver = $pkgver-$pkgrel" >>.PKGINFO + echo "pkgdesc = $pkgdesc" >>.PKGINFO + echo "url = $url" >>.PKGINFO + echo "builddate = $builddate" >>.PKGINFO + echo "packager = $packager" >>.PKGINFO + echo "size = $size" >>.PKGINFO + if [ "$CARCH" != "" ]; then + echo "arch = $CARCH" >>.PKGINFO + fi + + local it + for it in "${license[@]}"; do + echo "license = $it" >>.PKGINFO + done + for it in "${replaces[@]}"; do + echo "replaces = $it" >>.PKGINFO + done + for it in "${groups[@]}"; do + echo "group = $it" >>.PKGINFO + done + for it in "${depends[@]}"; do + echo "depend = $it" >>.PKGINFO + done + for it in "${conflicts[@]}"; do + echo "conflict = $it" >>.PKGINFO + done + for it in "${provides[@]}"; do + echo "provides = $it" >>.PKGINFO + done + for it in "${backup[@]}"; do + echo "backup = $it" >>.PKGINFO + done + + # TODO maybe remove this at some point + # warn if license array is not present or empty + if [ "$license" = "" ]; then + warning "$(gettext "Please add a license line to your %s!")" "$BUILDSCRIPT" + plain "$(gettext "Example for GPL'ed software: license=('GPL').")" + fi + + local comp_files=".PKGINFO .FILELIST" + + # check for an install script + # TODO: should we include ${pkgname}.install if it exists and $install is unset? + if [ "$install" != "" ]; then + msg2 "$(gettext "Adding install script...")" + cp "$startdir/$install" .INSTALL + comp_files="$comp_files .INSTALL" + fi + + # do we have a changelog? + if [ -f "$startdir/ChangeLog" ]; then + msg2 "$(gettext "Adding package changelog...")" + cp "$startdir/ChangeLog" .CHANGELOG + comp_files="$comp_files .CHANGELOG" + fi + + # tar it up + msg2 "$(gettext "Compressing package...")" + + local pkg_file="$PKGDEST/${pkgname}-${pkgver}-${pkgrel}-${CARCH}${PKGEXT}" + + if ! bsdtar -czf "$pkg_file" $comp_files $(ls); then + error "$(gettext "Failed to create package file.")" + exit 1 # TODO: error code + fi +} + +create_xdelta() { + if [ "$(check_buildenv xdelta)" != "y" ]; then + return + elif [ ! "$(type -p xdelta)" ]; then + error "$(gettext "Cannot find the xdelta binary! Is xdelta installed?")" + return + fi + + local pkg_file=$1 + local cache_dir="/var/cache/pacman/pkg" # TODO: autoconf me + local pkginfo="$(mktemp "$startdir"/xdelta-pkginfo.XXXXXXXXX)" + + local old_file old_version + for old_file in $(ls {"$cache_dir","$PKGDEST"}/${pkgname}-*-*{,-$CARCH}$PKGEXT 2>/dev/null); do + bsdtar -xOf "$oldfile" .PKGINFO > "$pkginfo" || continue + if [ "$(cat "$pkginfo" | grep '^pkgname = ')" != "pkgname = $pkgname" ]; then + continue # Package name does not match. + elif [ "$(cat "$pkginfo" | grep '^arch = ')" != "arch = $CARCH" ] ; then + continue # Not same arch. + fi + + old_version="$(cat "$pkginfo" | grep '^pkgver = ' | sed 's/^pkgver = //')" + + # old_version may include the target package, only use the old versions + local vercmp=$(vercmp "$old_version" "$latest_version") + if [ "$old_version" != "$pkgver-$pkgrel" -a $vercmp -gt 0 ]; then + local latest_version=$old_version + local base_file=$old_file + fi + done + + rm -f "$pkginfo" + + if [ "$base_file" != "" ]; then + msg "$(gettext "Making delta from version %s...")" "$latest_version" + local delta_file="$PKGDEST/$pkgname-${latest_version}_to_$pkgver-$pkgrel-$CARCH.delta" + + # xdelta will decompress base_file & pkg_file into TMP_DIR (or /tmp if + # TMP_DIR is unset) then perform the delta on the resulting tars + xdelta delta "$base_file" "$pkg_file" "$delta_file" + + # Generate the final gz using xdelta for compression. xdelta will be our + # common denominator compression utility between the packager and the users + # makepkg and pacman must use the same compression algorithm or the delta + # generated package may not match, producing md5 checksum errors. + msg2 "$(gettext "Recreating package tarball from delta to match md5 signatures")" + msg2 "$(gettext "NOTE: the delta should ONLY be distributed with this tarball")" + xdelta patch "$delta_file" "$base_file" "$pkg_file" + else + warning "$(gettext "No previous version found, skipping xdelta.")" + fi +} + +create_srcpackage() { + cd "$startdir" + msg "$(gettext "Creating source package...")" + local comp_files="PKGBUILD" + msg2 "$(gettext "Adding %s...")" "PKGBUILD" + + if [ "$install" != "" ]; then + if [ -f $install ]; then + msg2 "$(gettext "Adding install script...")" + comp_files="$comp_files $install" + else + error "$(gettext "Install script %s not found.")" "$install" + fi + fi + + if [ -f ChangeLog ]; then + msg2 "$(gettext "Adding %s...")" "ChangeLog" + comp_files="$comp_files ChangeLog" + fi + + local i + for i in ${source[@]}; do + if [ -f $i ]; then + msg2 "$(gettext "Adding %s...")" "$i" + comp_files="$comp_files $i" + fi + done + + local pkg_file="$PKGDEST/${pkgname}-${pkgver}-${pkgrel}${SRCEXT}" + + # tar it up + msg2 "$(gettext "Compressing source package...")" + if ! bsdtar -czf "$pkg_file" $comp_files; then + error "$(gettext "Failed to create source package file.")" + exit 1 # TODO: error code + fi +} + +install_package() { + [ "$INSTALL" = "0" ] && return + + msg "$(gettext "Installing package with pacman -U...")" + if [ "$ASROOT" = "0" ]; then + sudo pacman $PACMAN_OPTS -U $PKGDEST/${pkgname}-${pkgver}-${pkgrel}-${CARCH}${PKGEXT} || exit $? + else + pacman $PACMAN_OPTS -U $PKGDEST/${pkgname}-${pkgver}-${pkgrel}-${CARCH}${PKGEXT} || exit $? + fi +} + +usage() { + printf "makepkg (pacman) %s\n" "$myver" + echo + printf "$(gettext "Usage: %s [options]")\n" "$0" + echo + echo "$(gettext "Options:")" + printf "$(gettext " -A, --ignorearch Ignore incomplete arch field in %s")\n" "$BUILDSCRIPT" + echo "$(gettext " -b, --builddeps Build missing dependencies from source")" + echo "$(gettext " -c, --clean Clean up work files after build")" + echo "$(gettext " -C, --cleancache Clean up source files from the cache")" + echo "$(gettext " -d, --nodeps Skip all dependency checks")" + echo "$(gettext " -e, --noextract Do not extract source files (use existing src/ dir)")" + echo "$(gettext " -f, --force Overwrite existing package")" + echo "$(gettext " -g, --geninteg Generate integrity checks for source files")" + echo "$(gettext " -h, --help This help")" + echo "$(gettext " -i, --install Install package after successful build")" + echo "$(gettext " -L, --log Log package build process")" + echo "$(gettext " -m, --nocolor Disable colorized output messages")" + echo "$(gettext " -o, --nobuild Download and extract files only")" + printf "$(gettext " -p <buildscript> Use an alternate build script (instead of '%s')")\n" "$BUILDSCRIPT" + echo "$(gettext " -r, --rmdeps Remove installed dependencies after a successful build")" + # fix flyspray feature request #2978 + echo "$(gettext " -R, --repackage Repackage contents of pkg/ without building")" + echo "$(gettext " -s, --syncdeps Install missing dependencies with pacman")" + echo "$(gettext " --asroot Allow makepkg to run as root user")" + echo "$(gettext " --source Do not build package; generate a source-only tarball")" + echo + echo "$(gettext "These options can be passed to pacman:")" + echo + echo "$(gettext " --noconfirm Do not ask for confirmation when resolving dependencies")" + echo "$(gettext " --noprogressbar Do not show a progress bar when downloading files")" + echo + printf "$(gettext "If -p is not specified, makepkg will look for '%s'")\n" "$BUILDSCRIPT" + echo +} + +version() { + printf "$(gettext "makepkg (pacman) %s")\n" "$myver" + echo "$(gettext "Copyright (C) 2002-2007 Judd Vinet <jvinet@zeroflux.org>.")" + echo + echo "$(gettext "This is free software; see the source for copying conditions.")" + echo "$(gettext "There is NO WARRANTY, to the extent permitted by law.")" + echo +} + +ARGLIST=$@ + +#preserve environment variables +_PKGDEST=${PKGDEST} +_SRCDEST=${SRCDEST} + +# Source makepkg.conf; fail if it is not found +if [ -r "$confdir/makepkg.conf" ]; then + source "$confdir/makepkg.conf" +else + error "$(gettext "%s not found.")" "$confdir/makepkg.conf" + plain "$(gettext "Aborting...")" + exit 1 # $E_CONFIG_ERROR +fi + +# Source user-specific makepkg.conf overrides +if [ -r ~/.makepkg.conf ]; then + source ~/.makepkg.conf +fi + +# override settings with an environment variable for batch processing +PKGDEST=${_PKGDEST:-$PKGDEST} +PKGDEST=${PKGDEST:-$startdir} #default to $startdir if undefined +SRCDEST=${_SRCDEST:-$SRCDEST} +SRCDEST=${SRCDEST:-$startdir} #default to $startdir if undefined + +# Only use ABSROOT if we haven't been passed a SRCROOT on the command line. +if [ -z "$SRCROOT" ]; then + if [ -r "$confdir/abs/abs.conf" ]; then + source "$confdir/abs/abs.conf" + fi + if [ -r ~/.abs.conf ]; then + source ~/.abs.conf + fi + SRCROOT=$ABSROOT +fi + + + +# Parse Command Line Options. +OPT_SHORT="bcCdefFghiLmop:rRsSV" +OPT_LONG="asroot,builddeps,clean,cleancache,nodeps,noextract,force,geninteg,help,install,log" +OPT_LONG="$OPT_LONG,nocolor,nobuild,rmdeps,repackage,source,syncdeps,usesudo,version" +# Pacman Options +OPT_LONG="$OPT_LONG,noconfirm,noprogressbar" +OPT_TEMP="$(getopt -o "$OPT_SHORT" -l "$OPT_LONG" -n "$(basename "$0")" -- "$@" || echo 'GETOPT GO BANG!')" +if echo "$OPT_TEMP" | grep -q 'GETOPT GO BANG!'; then + # This is a small hack to stop the script bailing with 'set -e' + echo; usage; exit 1 # E_INVALID_OPTION; +fi +eval set -- "$OPT_TEMP" +unset OPT_SHORT OPT_LONG OPT_TEMP + +while true; do + case "$1" in + # Pacman Options + --noconfirm) PACMAN_OPTS="$PACMAN_OPTS --noconfirm" ;; + --noprogressbar) PACMAN_OPTS="$PACMAN_OPTS --noprogressbar" ;; + + # Makepkg Options + --asroot) ASROOT=1 ;; + -A|--ignorearch) IGNOREARCH=1 ;; + -b|--builddeps) DEP_SRC=1 ;; + -c|--clean) CLEANUP=1 ;; + -C|--cleancache) CLEANCACHE=1 ;; + -d|--nodeps) NODEPS=1 ;; + -e|--noextract) NOEXTRACT=1 ;; + -f|--force) FORCE=1 ;; + -F) INFAKEROOT=1 ;; + -g|--geninteg) GENINTEG=1 ;; + -i|--install) INSTALL=1 ;; + -L|--log) LOGGING=1 ;; + -m|--nocolor) USE_COLOR='n' ;; + -o|--nobuild) NOBUILD=1 ;; + -r|--rmdeps) RMDEPS=1 ;; + -R|--repackage) REPKG=1 ;; + --source) SOURCEONLY=1 ;; + -s|--syncdeps) DEP_BIN=1 ;; + + # BEGIN DEPRECATED + -S|--usesudo) + warning "$(gettext "Sudo is used by default now. The --usesudo option is deprecated!")" ;; + # END DEPRECATED + + -h|--help) usage; exit 0 ;; # E_OK + -V|--version) version; exit 0 ;; # E_OK + + --) OPT_IND=0; shift; break;; + *) usage; exit 1 ;; # E_INVALID_OPTION + esac + shift +done + + +if [ "$CLEANCACHE" = "1" ]; then + #fix flyspray feature request #5223 + if [ -n "$SRCDEST" -a "$SRCDEST" != "$startdir" ]; then + msg "$(gettext "Cleaning up ALL files from %s.")" "$SRCDEST" + echo -n "$(gettext " Are you sure you wish to do this? [Y/n] ")" + read answer + answer=$(echo $answer | tr [:upper:] [:lower:]) + if [ "$answer" = "yes" -o "$answer" = "y" ]; then + rm "$SRCDEST"/* + if [ $? -ne 0 ]; then + error "$(gettext "Problem removing files; you may not have correct permissions in %s")" "$SRCDEST" + exit 1 + else + # removal worked + msg "$(gettext "Source cache cleaned.")" + exit 0 + fi + else + # answer = no + msg "$(gettext "No files have been removed.")" + exit 0 + fi + else + # $SRCDEST is $startdir, two possibilities + error "$(gettext "Source destination must be defined in makepkg.conf.")" + plain "$(gettext "In addition, please run makepkg -C outside of your cache directory.")" + exit 1 + fi +fi + +if [ -z $BUILDSCRIPT ]; then + error "$(gettext "BUILDSCRIPT is undefined! Ensure you have updated %s.")" "$confdir/makepkg.conf" + exit 1 +fi + +if [ "$INFAKEROOT" = "0" ]; then + if [ $EUID -eq 0 -a "$ASROOT" = "0" ]; then + # Warn those who like to live dangerously. + error "$(gettext "Running makepkg as root is a BAD idea and can cause")" + plain "$(gettext "permanent, catastrophic damage to your system. If you")" + plain "$(gettext "wish to run as root, please use the --asroot option.")" + exit 1 # $E_USER_ABORT + elif [ $EUID -gt 0 -a "$ASROOT" = "1" ]; then + # Warn those who try to use the --asroot option when they are not root + error "$(gettext "The --asroot option is meant for the root user only.")" + plain "$(gettext "Please rerun makepkg without the --asroot flag.")" + exit 1 # $E_USER_ABORT + elif [ "$(check_buildenv fakeroot)" = "y" ]; then + if [ ! $(type -p fakeroot) ]; then + error "$(gettext "Fakeroot must be installed if using the 'fakeroot' option")" + plain "$(gettext "in the BUILDENV array in %s.")" "$confdir/makepkg.conf" + exit 1 + fi + else + warning "$(gettext "Running makepkg as an unprivileged user will result in non-root")" + plain "$(gettext "ownership of the packaged files. Try using the fakeroot environment by")" + plain "$(gettext "placing 'fakeroot' in the BUILDENV array in makepkg.conf.")" + sleep 1 + fi +else + if [ "$FAKEROOTKEY" = "" ]; then + error "$(gettext "Do not use the '-F' option. This option is only for use by makepkg.")" + exit 1 # TODO: error code + fi +fi + +# check for sudo if we will need it during makepkg execution +if [ "$ASROOT" = "0" -a \( "$DEP_BIN" = "1" -o "$DEP_SRC" = "1" \ + -o "$RMDEPS" = "1" -o "$INSTALL" = "1" \) ]; then + if [ ! "$(type -p sudo)" ]; then + error "$(gettext "Cannot find the sudo binary! Is sudo installed?")" + plain "$(gettext "Missing dependencies cannot be installed or removed as a normal user")" + plain "$(gettext "without sudo; install and configure sudo to auto-resolve dependencies.")" + exit 1 + fi +fi + +unset pkgname pkgver pkgrel pkgdesc url license groups provides md5sums force +unset replaces depends conflicts backup source install build makedepends +unset options noextract + +if [ ! -f "$BUILDSCRIPT" ]; then + error "$(gettext "%s does not exist.")" "$BUILDSCRIPT" + exit 1 + #TODO this is an attempt at a generic way to unset all package specific + #variables in a PKGBUILD + #else + # #this is fun.... we'll unset + # for var in $(grep "=" $BUILDSCRIPT | sed "s|.*\(\<.*\>\)=.*|\1|g"); do + # unset $var + # done +fi + +source "$BUILDSCRIPT" + +# check for no-no's in the build script +if [ -z "$pkgver" ]; then + error "$(gettext "%s is not allowed to be empty.")" "pkgver" + exit 1 +fi +if [ -z "$pkgrel" ]; then + error "$(gettext "%s is not allowed to be empty.")" "pkgrel" + exit 1 +fi +if [ $(echo "$pkgver" | grep '-') ]; then + error "$(gettext "%s is not allowed to contain hyphens.")" "pkgver" + exit 1 +fi +if [ $(echo "$pkgrel" | grep '-') ]; then + error "$(gettext "%s is not allowed to contain hyphens.")" "pkgrel" + exit 1 +fi + +if ! in_array $CARCH ${arch[@]}; then + if "$IGNOREARCH" = "0" ]; then + error "$(gettext "%s is not available for the '%s' architecture.")" "$pkgname" "$CARCH" + plain "$(gettext "Note that many packages may need a line added to their %s")" "$BUILDSCRIPT" + plain "$(gettext "such as arch=('%s').")" "$CARCH" + exit 1 + else + warning "$(gettext "%s is not available for the '%s' architecture.")" "$pkgname" "$CARCH" + plain "$(gettext "Note that many packages may need a line added to their %s")" "$BUILDSCRIPT" + plain "$(gettext "such as arch=('%s').")" "$CARCH" + fi +fi + +if [ "$install" -a ! -f "$install" ]; then + error "$(gettext "Install scriptlet (%s) does not exist.")" "$install" + exit 1 +fi + +if [ -f "$PKGDEST/${pkgname}-${pkgver}-${pkgrel}-${CARCH}${PKGEXT}" \ + -a "$FORCE" = "0" -a "$GENINTEG" = "0" -a "$SOURCEONLY" = "0" ]; then + if [ "$INSTALL" = "1" ]; then + warning "$(gettext "A package has already been built, installing existing package...")" + install_package + exit $? + else + error "$(gettext "A package has already been built. (use -f to overwrite)")" + exit 1 + fi +fi + +# Run the bear minimum in fakeroot +# fix flyspray bug 6208 -- using makepkg with fakeroot gives an error +if [ "$INFAKEROOT" = "1" ]; then + if [ "$REPKG" = "1" ]; then + warning "$(gettext "Skipping build.")" + else + run_build + tidy_install + fi + + create_package + + msg "$(gettext "Leaving fakeroot environment.")" + exit 0 # $E_OK +fi + +msg "$(gettext "Making package: %s")" "$pkgname $pkgver-$pkgrel ($(date))" + +if [ $EUID -eq 0 ]; then + warning "$(gettext "Running makepkg as root...")" +fi + +# if we are creating a source-only package, go no further +if [ "$SOURCEONLY" = "1" ]; then + if [ -f "$PKGDEST/${pkgname}-${pkgver}-${pkgrel}${SRCEXT}" \ + -a "$FORCE" = "0" ]; then + error "$(gettext "A package has already been built. (use -f to overwrite)")" + exit 1 + fi + create_srcpackage + msg "$(gettext "Source package created: %s")" "$pkgname ($(date))" + exit 0 +fi + +# fix flyspray bug #5973 +if [ "$NODEPS" = "1" -o "$GENINTEG" = "1" -o "$NOBUILD" = "1" -o "$REPKG" = "1" ]; then + if [ "$NODEPS" = "1" ]; then + warning "$(gettext "Skipping dependency checks.")" + fi + # skip printing a warning message for the others: geninteg, nobuild, repkg +elif [ $(type -p pacman) ]; then + unset pkgdeps # Set by resolve_deps() and used by remove_deps() + deperr=0 + + msg "$(gettext "Checking Runtime Dependencies...")" + resolve_deps ${depends[@]} || deperr=1 + + msg "$(gettext "Checking Buildtime Dependencies...")" + resolve_deps ${makedepends[@]} || deperr=1 + + if [ $deperr -eq 1 ]; then + error "$(gettext "Could not resolve all dependencies.")" + exit 1 + fi +else + warning "$(gettext "pacman was not found in PATH; skipping dependency checks.")" +fi + +# get back to our src directory so we can begin with sources +mkdir -p "$srcdir" +cd "$srcdir" + +if [ "$GENINTEG" = "1" ]; then + download_sources + generate_checksums + exit 0 # $E_OK +fi + +if [ "$NOEXTRACT" = "1" -o "$REPKG" = "1" ]; then + warning "$(gettext "Skipping source retrieval -- using existing src/ tree")" + warning "$(gettext "Skipping source integrity checks -- using existing src/ tree")" + warning "$(gettext "Skipping source extraction -- using existing src/ tree")" + + if [ "$NOEXTRACT" = "1" -a "$(ls "$srcdir" 2>/dev/null)" = "" ]; then + error "$(gettext "The source directory is empty, there is nothing to build!")" + plain "$(gettext "Aborting...")" + exit 1 + elif [ "$REPKG" = "1" -a \( ! -d "$pkgdir" -o "$(ls "$pkgdir" 2>/dev/null)" = "" \) ]; then + error "$(gettext "The package directory is empty, there is nothing to repackage!")" + plain "$(gettext "Aborting...")" + exit 1 + fi +else + download_sources + check_checksums + extract_sources +fi + +if [ "$NOBUILD" = "1" ]; then + msg "$(gettext "Sources are ready.")" + exit 0 #E_OK +else + # check for existing pkg directory; don't remove if we are repackaging + if [ -d "$pkgdir" -a "$REPKG" = "0" ]; then + msg "$(gettext "Removing existing pkg/ directory...")" + rm -rf "$pkgdir" + fi + mkdir -p "$pkgdir" + + if [ $EUID -eq 0 ]; then + # if we are root, then we don't need to recall makepkg with fakeroot + if [ "$REPKG" = "1" ]; then + warning "$(gettext "Skipping build.")" + else + run_build + tidy_install + fi + + create_package + else + msg "$(gettext "Entering fakeroot environment...")" + cd "$startdir" + + fakeroot -- $0 -F $ARGLIST || exit $? + fi + + create_xdelta "$PKGDEST/${pkgname}-${pkgver}-${pkgrel}-${CARCH}${PKGEXT}" +fi + +msg "$(gettext "Finished making: %s")" "$pkgname ($(date))" + +install_package + +exit 0 #E_OK + +# vim: set ts=2 sw=2 noet: |