From c8a5d97eeadb53f4b3a6f4931f5278a99b2c3ff4 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Thu, 25 Apr 2013 15:53:55 -0400 Subject: second iteration of librefetch --- src/librefetch/librefetch | 504 +++++++++++++++++++++++----------------------- 1 file changed, 247 insertions(+), 257 deletions(-) (limited to 'src') diff --git a/src/librefetch/librefetch b/src/librefetch/librefetch index 9ba2a84..b637661 100755 --- a/src/librefetch/librefetch +++ b/src/librefetch/librefetch @@ -1,4 +1,4 @@ -#!/bin/bash -euE +#!/bin/bash # librefetch # # Copyright 2013 Luke Shumaker @@ -18,157 +18,264 @@ # You should have received a copy of the GNU General Public License # along with Parabola. If not, see . -# Overview: -# For 'create' (default) mode, the program flow is easily summarized as: -# librefetch_extract() { -# download_sources -# check_source_integrity -# extract_sources -# } -# librefetch_create() { -# librefetch_extract -# run_function_safe 'mksource' -# create_package -# } - -unset CDPATH export TEXTDOMAIN='libretools' export TEXTDOMAINDIR='/usr/share/locale' -# Constants -declare -r confdir='/etc' -declare -r BUILDSCRIPT='PKGBUILD' # The default for ${BUILDFILE} +declare -r tempdir="$(mktemp -d --tmpdir ${0##*/}.XXXXXXXXXXX)" +cleanup() { rm -rf -- "$tempdir"; } +trap cleanup EXIT +cmd=${0##*/} usage() { - print "Usage: ${0##*/} [OPTIONS] SOURCEURL OUTFILE" + print "Usage: %s [options] " "$cmd" + print "Usage: %s [options] -g" "$cmd" print "Downloads or creates a liberated source tarball." echo + print "The default build script is 'PKGBUILD', or 'SRCBUILD' if it exists." + echo + print "Unrecognized options are passed straight to makepkg." + echo print "Options:" - print " -c Force create mode (don't download)" - print " -d Force download mode (don't create)" - print " -e Extract only (don't run \`mksource\` or \`tar\`)" - print " -g Generate checksums for the \`mksource\` array" - print " -m Do not use color" - print " -p Do Use an alternative build script (instead of 'PKGBUILD')" - print " -h Show this message" + print " -C Force create mode (don't download)" + print " -D Force download mode (don't create)" + print " -p Use an alternate build script (instead of 'PKGBUILD')" + print " If an SRCBUILD exists in the same directory, it is used" + print " instead" + print " -g, --geninteg Generage integrity checks for source files" + print " -V, --version Show version information" + print " -h, --help Show this message" +} + +version() { + print "librefetch (libretools) beta 2" + echo + print "Copyright (C) 2013 Luke Shumaksr " + print "This is free software; see the source for copying conditions." + print "There is NO WARRANTY, to the extent permitted by law." } -# The semantics of ${BUILDDIR} and ${startdir} are a little confusing. -# - ${startdir} is the directory that the program is run from. -# This is either where output files are created, or where they are linked to -# if the relevent *DEST is set. -# - ${BUILDDIR} is the directory that ${srcdir} and ${pkgdir} are in. -# -# How ${BUILDDIR} is set varries between makepkg an librefetch: -# (high precedence is higher up; lower number) -# - makepkg: -# 1. The `BUILDDIR` environmental variable -# 2. ${startdir} -# - librefetch -# 1. The directory a manually specified (`-p` flag) PKGBUILD is in -# 2. The `BUILDDIR` environmental variable -# 3. ${startdir} -# -# librefetch forces PKGDEST=$startdir; so it does not symlink the output into -# $startdir main() { - # Init/Parse command line ############################################## - - # Global variables - USE_COLOR=y - startdir=$PWD - [[ -n ${BUILDDIR:-} ]] || BUILDDIR=$startdir - - local mode='download-or-create' - while getopts 'cdegmp:h' arg; do - case $arg in - c) mode='create';; - d) mode='download';; - e) mode='extract';; - g) mode='generate-checksums';; - m) USE_COLOR=n;; - p) - BUILDFILE="$(readlink -m "$OPTARG")" - BUILDDIR="${BUILDFILE%/*}" - ;; - h) usage; return 0;; - *) usage; return 1;; + BUILDFILE="$(readlink -m PKGBUILD)" + makepkg_opts=() + extra_opts=() + mode=create # download-create + parse_options "$@" + + local startdir=$PWD + export BUILDDIR="${BUILDFILE%/*}" + if [[ -f "${BUILDDIR}/SRCBUILD" ]]; then + BUILDFILE="${BUILDDIR}/SRCBUILD" + srcbuild="$(modified_srcbuild "$BUILDFILE")" + else + srcbuild="$(modified_pkgbuild "$BUILDFILE")" + fi + makepkg="$(modified_makepkg "$(which "${MAKEPKG:-makepkg}")")" + + # Mode: checksums ###################################################### + + if [[ $mode =~ checksums ]]; then + if [[ ${#extra_opts[@]} != 0 ]]; then + print "%s: found extra non-flag arguments: %s" "$cmd" "${extra_opts[*]}" + usage >> /dev/stderr + return 1 + fi + "$makepkg" "${makepkg_opts[@]}" -g -p "$srcbuild" | + case ${BUILDFILE##*/} in + PKGBUILD) sed -e 's/^[a-z]/mk&/' -e 's/^\s/ &/';; + SRCBUILD) cat;; esac - done - shift $(($OPTIND - 1)) + return 0 + fi - # Lock in these variables globally - declare -rg USE_COLOR - declare -rg startdir - declare -rg BUILDDIR + ######################################################################## - # Main routine ######################################################### + if [[ ${#extra_opts[@]} != 2 ]]; then + print "%s: %d non-flag arguments found, expected 2: %s" "$cmd" ${#extra_opts[@]} + usage >> /dev/stderr + return 1 + fi + local src="${extra_opts[0]#*://}" + local dst="$(readlink -m "${extra_opts[1]}")" - if [[ $mode = 'generate-checksums' ]]; then - librefetch_makepkg_init '/dev/null' '/dev/null' - librefetch_generate_checksums - return $? - else - if [[ $# != 2 ]]; then - usage - return 1; - fi - local src="${1#*://}" - local dst="$(readlink -m "$2")" + # Mode: download ####################################################### - case $mode in - download) - librefetch_download "$src" "$dst" - ;; - extract) - librefetch_makepkg_init "$src" "$dst" - librefetch_extract - ;; - download-or-create) - librefetch_makepkg_init "$src" "$dst" - librefetch_download "$src" "$dst" || librefetch_create "$dst" - ;; - create) - librefetch_makepkg_init "$src" "$dst" - librefetch_create "$dst" + if [[ $mode =~ download ]]; then + load_conf_libretools_librefetch || return 1 + + local url="${MIRROR}/${src}" + + local dlcmd="${DOWNLOADER}" + dlcmd="${dlcmd//\%o/\"$dst\"}" + dlcmd="${dlcmd//\%u/\"$url\"}" + { eval "$dlcmd"; } && return 0 + fi + + # Mode: create ######################################################### + + if [[ $mode =~ create ]]; then + PKGEXT=${dst##*/} + export PKGEXT=${PKGEXT%.part} + export PKGDEST=$startdir + export pkg_file=$dst + "$makepkg" "${makepkg_opts[@]}" -p "$srcbuild" + fi +} + +# sets the variables BUILDFILE, makepkg_opts, extra_opts, mode +parse_options() { + # Detect makepkg options that take a second argument + local makepkg_orig="$(which "${MAKEPKG:-makepkg}")" + local makepkg_opt2long=($("${makepkg_orig}" -h | sed -rn 's/\s*(--\S*) <.*/\1/p')) + local makepkg_opt2short=($("${makepkg_orig}" -h | sed -rn 's/\s*(-.) <.*/\1/p')) + + local opt + local have_opt + while [[ $# > 0 ]]; do + arg=$1 + have_opt=false + if in_array "${arg%%=*}" "${makepkg_opt2long[@]}"; then + opt="${arg#*=}" + arg="${arg%%=*}" + have_opt=true + fi + if in_array "${arg}" "${makepkg_opt2short[@]}"; then + shift + opt=$1 + have_opt=true + fi + case "$arg" in + -C) mode=create;; + -D) mode=download;; + -g|--geninteg) mode=checksums;; + -p) BUILDFILE="$(readlink -m "$opt")";; + -*) + makepkg_opts+=("$arg") + $have_opt && makepkg_opts+=("$opt") ;; + --) shift; break;; + *) extra_opts+=("$arg");; esac - fi + shift + done + extra_opts+=("$@") +} + +# Modify makepkg ############################################################### + +# an ERE +makepkg_modify=' +/create_package\(\) \{/,/^\}$/ { + /pkg_file=/d # allow us to set pkg_file + /check_package/d # do not run check_package + s/"?\$\{comp_files\[@\]\}"?// # do not include .{PKGINFO,INSTALL,CHANGELOG} +} + +/tidy_install\(\) \{/,/^\}$/ { + /for .*PURGE_TARGETS/itidy_install_purge + /for .*PURGE_TARGETS/,/done/d + /^\}$/ifind . -exec touch --date="1990-01-01 0:0:0 +0" {} + } -librefetch_makepkg_init() { - local src=$1 - local dst=$2 - - import_makepkg_functions - - makepkg_variables - makepkg_preimport - - set +u - makepkg_import - set -u - - # Override certain variables - declare -rg srcdir="$BUILDDIR/src-libre" - declare -rg pkgdir="$BUILDDIR/pkg-libre" - declare -rg PKGDEST=$startdir - - declare -rg PKGEXT="${src##*/}" # this affects the tar command used, and - # pkg_file - declare -rg pkg_file=$dst # but we already know what we want this to be - # (so PKGEXT only affects tar) - declare -rg changelog='' # don't include a special changelog file in the tarball - declare -rg install='' # don't include an install script in the tarball - - # copy the mk* source-related arrays to the standard names - set +u - for var in source noextract md5sums sha1sums sha256sums sha384sums sha512sums; do - copy_array "mk${var}" "${var}" - [[ -n "${!var}" ]] || eval "${var}=''" - declare -rga "$var" +s|srcdir=.*|srcdir="$BUILDDIR/src-libre"| +s|pkgdir=.*|pkgdir="$BUILDDIR/pkg-libre"| +s|check_build_status$|:| +' + +tidy_install_purge() { + local pt + for pt in "${PURGE_TARGETS[@]}"; do + if [[ ${pt} = "${pt%/}" ]]; then + if [[ ${pt} = "${pt//\/}" ]]; then + find . ! -type d -name "${pt}" -exec rm -f -- '{}' + + else + rm -f "${pt}" + fi + else + if [[ ${pt%/} = "${pt//\/}" ]]; then + find . -type d -name "${pt%/}" -exec rm -rf -- '{}' + + else + rm -rf "${pt}" + fi + fi done - set -u +} + +modified_makepkg() { + local makepkg_orig=$1 + local makepkg_mine="$tempdir/makepkg" + { + echo '#!/bin/bash' + declare -f tidy_install_purge + sed -r "$makepkg_modify" < "$makepkg_orig" + } > "$makepkg_mine" + chmod 755 "$makepkg_mine" + printf "%s\n" "$makepkg_mine" +} + +# Modify PKGBUILD ############################################################## + +# a string to be appended +pkgbuild_append=' +# do not do split packages +if [[ -n $pkgbase ]]; then + pkgname=$pkgbase +else + pkgname=$pkgname +fi + +# copy source variables +source=("${mksource[@]}") +noextract=("${mknoextract[@]}") +md5sums=("${mkmd5sums[@]}") +sha1sums=("${mksha1sums[@]}") +sha256sums=("${mksha256sums[@]}") +sha384sums=("${mksha384sums[@]}") +sha512sums=("${mksha512sums[@]}") + +depends=() +checkdepends=() +makedepends=("${mkdepends[@]}") + +#### +options+=(!strip docs libtool emptydirs !zipman purge !upx) +PURGE_TARGETS+=(.bzr/ .cvs/ .git/ .hg/ .svn/) + +#### +if ! declare -f mksource >/dev/null; then + mksource() { :; } +fi +build() { mksource; } +package() { + if [[ $(ls "$pkgdir" | wc -l) == 0 ]]; then + # pkgdir is empty; provide good default behavior + cp -a "${srcdir}"/*/ "$pkgdir/" + fi +} +' + +modified_pkgbuild() { + local pkgbuild=$1 + local srcbuild="$tempdir/SRCBUILD" + printf '%s' "$pkgbuild_append" | cat "$pkgbuild" - > "$srcbuild" + printf '%s\n' "$srcbuild" +} + + +# Modify SRCBUILD ############################################################## + +modified_srcbuild() { + local orig=$1 + local new="$tempdir/SRCBUILD" + sed -e '/PKGDEST=/d' -e 's/PKGEXT=/d' < "$orig" > "$new" + printf '%s\n' "$new" +} + +# "Library" crap ############################################################### + +print() { + local fmt=$1 + shift + printf -- "$(gettext "$fmt")\n" "$@" } # Emulates the behavior of bleeding /usr/share/libretools/conf.sh @@ -177,7 +284,6 @@ load_conf_libretools_librefetch() { . /etc/libretools.d/librefetch.conf local ret=0 for VAR in MIRROR DOWNLOADER; do - echo "$VAR: ${!VAR:-}" if [[ -z ${!VAR:-} ]]; then echo "Configure '$VAR' in /etc/libretools.d/librefetch.conf" ret=1 @@ -188,133 +294,17 @@ load_conf_libretools_librefetch() { fi } -################################################################################ - -copy_array() { - local src=$1 - local dst=$2 - eval "$(printf '%s=("${%s[@]}")' "${dst}" "${src}")" -} - -print() { - local fmt=$1 - shift - printf -- "$(gettext "$fmt")\n" "$@" +# From devtools common.sh, which is only distributed in a package with bleeding +# libretools +in_array() { + local needle=$1; shift + local item + for item in "$@"; do + [[ $item = $needle ]] && return 0 # Found + done + return 1 # Not Found } ################################################################################ -librefetch_download() { - local src=$1 - local dst=$2 - load_conf_libretools_librefetch || exit 1 - - local url="${MIRROR}/${src}" - - local dlcmd="${DOWNLOADER}" - dlcmd="${dlcmd//\%o/\"$dst\"}" - dlcmd="${dlcmd//\%u/\"$url\"}" - eval "$dlcmd" -} - -librefetch_extract() { - mkdir -p "$srcdir" - # The 'full' is for compatability with makepkg-git-2abe1f1; whose design - # I disagree with, but I'll play along. - # (it could be any value, except 'fast') - download_sources 'full' - check_source_integrity - extract_sources -} - -librefetch_create() { - local dst=$1 - librefetch_extract - - rm -rf "$pkgdir" - mkdir -p "$pkgdir" - - if declare -f mksource >/dev/null; then - run_function_safe "mksource" - else - mv "$srcdir"/*/ "$pkgdir" - fi - create_package -} - -librefetch_generate_checksums() { - mkdir -p "$srcdir" - chmod a-s "$srcdir" - cd_safe "$srcdir" - # The 'fast' is for compatability with makepkg-git-2abe1f1; whose design - # I disagree with, but I'll play along. - download_sources fast - generate_checksums | sed -e 's/^[a-z]/mk&/' -e 's/^\s/ &/' && (exit $PIPESTATUS) -} - -# Hack to load functions defined in makepkg -import_makepkg_functions() { - # The file we are reading from - local makepkg="$(which "${MAKEPKG:-makepkg}")" - # The temporary file that we will include - local makepkg_lib="$(mktemp --tmpdir makepkg-lib.XXXXXXXXXX.sh)" - - # Extract all functions defined in $makepkg - sed -n '/^[a-z0-9_]*() {/,/^}$/p' < $makepkg >> $makepkg_lib - # Extract variable initialization as `makepkg_variables()` - { - echo 'makepkg_variables() {' - sed -n '/^# Options/,/^\s*$/p' - echo '}' - } < $makepkg >> $makepkg_lib - - # Extract the init routine between parsing options and first looking at - # the PKGBUILD as `makepkg_preimport()` - { - echo 'makepkg_preimport() {' - sed -n '/^# setup signal traps/,/^unset pkgname/p' | sed '$d' - echo '}' - } < $makepkg >> $makepkg_lib - # Extract the PKGBUILD inclusion routine as `makepkg_import()` - # from the main routine - { - echo 'makepkg_import() {' - sed -n '/^unset pkgname/,/^epoch=/p' - echo '}' - } < $makepkg >> $makepkg_lib - - # Modify `create_package()` suit our needs. - sed -ri ' - /create_package() \{/,/^\}$/ { - /PKGINFO/d - /pkg_file=/d - /check_package/d - s/"?\$\{comp_files\[@\]\}"?// - } - ' $makepkg_lib - - # Modify `get_filepath()` to work with `set -e`, as it is frequently - # expected to not output a value. - sed -i ' - /get_filepath() {/,/^}$/ { - s/return 1/return 0/ - } - ' $makepkg_lib - - # Modify everything to make `[[ -z VARIABLE ]]` and `[[ -n VARIABLE ]]` - # tests work with `set -u` - sed -ri 's/\[\[ -([nz]) "?\$\{?(!?[A-Za-z0-9_]+)\}?"? /[[ -\1 ${\2:-} /g' $makepkg_lib - - . $makepkg_lib - echo rm -- $makepkg_lib - - # makepkg-git defines these *_safe functions that makepkg-4.0.3 doesn't use; if - # ${MAKEPKG} doesn't define them, define them as no-op wrappers for our use. - for func in cd run_function; do - if ! declare -f "${func}_safe" >/dev/null; then - eval "${func}_safe() { ${func} \"\$@\"; }" - fi - done -} - main "$@" -- cgit v1.2.3-54-g00ecf