1
0
mirror of https://github.com/moparisthebest/pacman synced 2024-11-02 08:35:06 -04:00
pacman/scripts/makepkg.sh.in
Andrew Fyfe 678983d262 scripts/*.sh.in: Clean up and fix a few bugs
repo-add, repo-remove:
		'bsdtar -c * | ...' doesn't work (you need '-f -'). Code clean up
		eliminated this bug.

		Removed the multiple checksum support, pacman now only supports MD5, so
		there's no need for the database to contain multiple checksums.

		Quote all variables containing file/dir names to prevent paths
		containing spaces from causing problems.

		Add msg, warning and error functions.

		General code clean up.

	pacman-optimize:
		Use a sub-directory in /tmp for working files to make it easier to clean
		up at the end.

		Add quotes round $@ in die and die_r, otherwise printf can't display the
		message correctly.

	makepkg:
		Disable colour output if stderr is not a tty.

Signed-off-by: Andrew Fyfe <andrew@neptune-one.net>
2007-09-06 19:28:57 -05:00

1370 lines
38 KiB
Bash

#!/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.
#
# makepkg uses quite a few external programs during its execution. You
# need to have at least the following installed for makepkg to function:
# awk, bsdtar (libarchive), bzip2, coreutils, fakeroot, find (findutils),
# getopt (util-linux), gettext, grep, gzip, sed
# 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 [ -t 2 -a ! "$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 [ -t 2 -a ! "$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 [ -t 2 -a ! "$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 [ -t 2 -a ! "$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 [ -t 2 -a ! "$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 127 ]; 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 --asdeps $striplist || ret=$?
else
pacman $PACMAN_OPTS -S --asdeps $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...")"
if [ ! -w "$SRCDEST" ] ; then
error "$(gettext "You do not have write permission to store downloads in %s.")" "$SRCDEST"
plain "$(gettext "Aborting...")"
exit 1
fi
pushd "$SRCDEST" &>/dev/null
local netfile
for netfile in ${source[@]}; do
local file=$(strip_url "$netfile")
if [ -f "$startdir/$file" ]; then
msg2 "$(gettext "Found %s in build dir")" "$file"
cp -s --remove-destination "$startdir/$file" "$srcdir/"
continue
elif [ -f "$SRCDEST/$file" ]; then
msg2 "$(gettext "Using cached copy of %s")" "$file"
cp -s --remove-destination "$SRCDEST/$file" "$srcdir/"
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
cp -s --remove-destination "$SRCDEST/$file" "$srcdir/"
done
popd &>/dev/null
}
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")"
if [ ! -f "$file" ] ; then
if [ ! -f "$SRCDEST/$file" ] ; then
error "$(gettext "Unable to find source file %s to generate checksum.")" "$file"
plain "$(gettext "Aborting...")"
exit 1
else
file=$SRCDEST/$file
fi
fi
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 [ ! -f "$file" ] ; then
if [ ! -f "$file" ] ; then
echo "$(gettext "NOT FOUND")" >&2
errors=1
continue
else
file=$SRCDEST/$file
fi
fi
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
if [ ! -f "$file" ] ; then
if [ ! -f "$SRCDEST/$file" ] ; then
error "$(gettext "Unable to find source file %s for extraction.")" "$file"
plain "$(gettext "Aborting...")"
exit 1
else
file=$SRCDEST/$file
fi
fi
# fix flyspray #6246
local file_type=$(file -bizL "$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 CHOST
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 "makepkg (pacman) %s\n" "$myver"
printf "$(gettext "\
Copyright (C) 2002-2007 Judd Vinet <jvinet@zeroflux.org>.\n\n\
This is free software; see the source for copying conditions.\n\
There is NO WARRANTY, to the extent permitted by law.\n")"
}
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" -a $EUID -gt 0 ]; 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
elif [ $EUID -gt 0 ]; then
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: