From 2ca1bce59850d92bb2cb6eb6c8f69f4ba10acbd8 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Thu, 25 Apr 2013 15:55:41 -0400 Subject: initial implementation of librefetch --- src/librefetch/librefetch | 320 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 320 insertions(+) create mode 100755 src/librefetch/librefetch (limited to 'src/librefetch/librefetch') diff --git a/src/librefetch/librefetch b/src/librefetch/librefetch new file mode 100755 index 0000000..9ba2a84 --- /dev/null +++ b/src/librefetch/librefetch @@ -0,0 +1,320 @@ +#!/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 "$@" -- cgit v1.2.2