#!/bin/bash -euE # librefetch # # Copyright 2013 Luke Shumaker # # This file is part of Parabola. # # Parabola is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Parabola is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Parabola. If not, see . # 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} usage() { print "Usage: ${0##*/} [OPTIONS] SOURCEURL OUTFILE" print "Downloads or creates a liberated source tarball." 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" } # 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;; esac done shift $(($OPTIND - 1)) # Lock in these variables globally declare -rg USE_COLOR declare -rg startdir declare -rg BUILDDIR # Main routine ######################################################### 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")" 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" ;; esac fi } 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" done set -u } # Emulates the behavior of bleeding /usr/share/libretools/conf.sh # without requiring bleeding libretools 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 fi >>/dev/stderr done if [[ $ret != 0 ]]; then return 1 fi } ################################################################################ copy_array() { local src=$1 local dst=$2 eval "$(printf '%s=("${%s[@]}")' "${dst}" "${src}")" } print() { local fmt=$1 shift printf -- "$(gettext "$fmt")\n" "$@" } ################################################################################ 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 "$@"