diff options
Diffstat (limited to 'src/librefetch/librefetch')
-rwxr-xr-x | src/librefetch/librefetch | 400 |
1 files changed, 400 insertions, 0 deletions
diff --git a/src/librefetch/librefetch b/src/librefetch/librefetch new file mode 100755 index 0000000..2b8af61 --- /dev/null +++ b/src/librefetch/librefetch @@ -0,0 +1,400 @@ +#!/usr/bin/env bash +# librefetch +# +# Copyright (C) 2013-2016 Luke Shumaker <lukeshu@sbcglobal.net> +# +# For just the create_signature() function: +# Copyright (C) 2006-2013 Pacman Development Team <pacman-dev@archlinux.org> +# Copyright (C) 2002-2006 Judd Vinet <jvinet@zeroflux.org> +# Copyright (C) 2005 Aurelien Foret <orelien@chez.com> +# Copyright (C) 2006 Miklos Vajna <vmiklos@frugalware.org> +# Copyright (C) 2005 Christian Hamar <krics@linuxforum.hu> +# Copyright (C) 2006 Alex Smith <alex@alex-smith.me.uk> +# Copyright (C) 2006 Andras Voroskoi <voroskoi@frugalware.org> +# +# License: GNU GPLv3+ +# +# This file is part of LibreFetch. +# +# LibreFetch 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. +# +# LibreFetch 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 LibreFetch. If not, see <http://www.gnu.org/licenses/>. + +# create_signature() is taken from pacman:makepkg, which is GPLv2+, +# so we take the '+' to combine it with our GPLv3+. + +. "$(librelib conf)" +. "$(librelib messages)" +setup_traps + +tmpfiles=() +tmpdirs=() +trap 'rm -f -- "${tmpfiles[@]}"; rm -rf -- "${tmpdirs[@]}"' EXIT + +cmd=${0##*/} +usage() { + print "Usage: %s [OPTIONS] SOURCE_URL [OUTPUT_FILE]" "$cmd" + print "Usage: %s -[g|S|M|h]" "$cmd" + print "Downloads or creates a liberated source tarball." + echo + prose "The default mode is to create OUTPUT_FILE, first by trying + download mode, then create mode." + echo + prose "If OUTPUT_FILE isn't specified, it defaults to the non-directory + part of SOURCE_URL, in the current directory." + echo + prose "Unless '-C' is specified, if SOURCE_URL does not begin with a + configured mirror, create mode is inhibited." + echo + prose "In download mode, it simply tries to download SOURCE_URL. At the + beginning of a URL, 'libre://' expands to the first configured + mirror." + echo + prose "In create mode, it either looks at a build script and uses that + to create the source tarball, or it uses GPG to create a + signature (if OUTPUT_FILE ends with \`.sig\` or \`.sig.part\`). + If it is using GPG to create a signature, but the file that it is + trying to sign doesn't exist yet, it recurses on itself to first + create that file. SOURCE_URL is ignored, except that it is used + to set the default value of OUTPUT_FILE, and that it may be used + when recursing." + echo + prose "The default build script is 'PKGBUILD', or 'SRCBUILD' if it + exists." + echo + prose "Other options, if they are valid \`makepkg\` options, are passed + straight to makepkg." + echo + print "Example usage:" + print ' $ %s https://repo.parabola.nu/other/mypackage/mypackage-1.0.tar.gz' "$cmd" + echo + print "Options:" + flag 'Settings:' \ + "-C" "Force create mode (don't download)" \ + "-D" "Force download mode (don't create)" \ + "-p <$(_ FILE)>" "Use an alternate build script (instead of + 'PKGBUILD'). If an SRCBUILD exists in the same + directory, it is used instead" \ + 'Alternate modes:' \ + "-g, --geninteg" "Generate integrity checks for source files" \ + "-S, --srcbuild" "Print the effective build script (SRCBUILD)" \ + "-M, --makepkg" "Generate and print the location of the + effective makepkg script" \ + "-h, --help" "Show this message" +} + +main() { + BUILDFILE="$(realpath -Lm PKGBUILD)" + makepkg_opts=() + extra_opts=() + mode=download-create + if ! parse_options "$@"; then + usage >&2 + exit 1 + fi + + doit +} + +doit() { + # Mode: help ########################################################### + + if [[ $mode =~ help ]]; then + usage + exit 0 + fi + + ######################################################################## + + makepkg="$(modified_makepkg)" + + # Mode: makepkg ######################################################## + + if [[ $mode =~ makepkg ]]; then + printf '%s\n' "$makepkg" + exit 0 + else + tmpdirs+=("${makepkg%/*}") + fi + + ######################################################################## + + local BUILDFILEDIR="${BUILDFILE%/*}" + if [[ -f "${BUILDFILEDIR}/SRCBUILD" ]]; then + BUILDFILE="${BUILDFILEDIR}/SRCBUILD" + fi + if [[ ! -f "$BUILDFILE" ]]; then + error "%s does not exist." "$BUILDFILE" + exit 1 + fi + case "$BUILDFILE" in + */SRCBUILD) srcbuild="$(modified_srcbuild "$BUILDFILE")";; + *) srcbuild="$(modified_pkgbuild "$BUILDFILE")";; + esac + tmpfiles+=("$srcbuild") + + # Mode: checksums ###################################################### + + if [[ $mode =~ checksums ]]; then + "$makepkg" "${makepkg_opts[@]}" -g -p "$srcbuild" | + case ${BUILDFILE##*/} in + PKGBUILD) sed -e 's/^[a-z]/mk&/' -e 's/^\s/ &/';; + SRCBUILD) cat;; + esac + exit 0 + fi + + # Mode: srcbuild ####################################################### + + if [[ $mode =~ srcbuild ]]; then + cat "$srcbuild" + exit 0 + fi + + ######################################################################## + + local src="${extra_opts[0]}" + local dst="${extra_opts[1]:-${src##*/}}" + + # Don't canonicalize $src unless mode =~ download, and we've validated + # that $MIRRORS is configured. + + # Canonicalize $dst + dst="$(realpath -Lm -- "$dst")" + + # Mode: download ####################################################### + + if [[ $mode =~ download ]]; then + load_files librefetch + check_vars librefetch MIRRORS DOWNLOADER || exit 1 + + # Canonicalize $src + if [[ "$src" == libre://* ]]; then + src="${MIRRORS[0]}/${src#libre://}" + fi + + # check to see if $src is a candidate for create mode + local inmirror=false; + local mirror + for mirror in "${MIRRORS[@]}"; do + if [[ "$src" == "$mirror"* ]]; then + inmirror=true + break + fi + done + if ! $inmirror; then + # inhibit create + mode=download + fi + + local dlcmd="${DOWNLOADER}" + [[ $dlcmd = *%u* ]] || dlcmd="$dlcmd %u" + dlcmd="${dlcmd//\%o/\"\$dst\"}" + dlcmd="${dlcmd//\%u/\"\$src\"}" + + { eval "$dlcmd"; } >&2 && exit 0 + fi + + # Mode: create ######################################################### + + if [[ $mode =~ create ]]; then + local base_dst=${dst%.part} + local suffix=${dst#"$base_dst"} + + if [[ $base_dst == *.sig ]]; then + if ! [[ -e $base_dst ]]; then + extra_opts=("${src%.sig}" "${base_dst%.sig}") + doit || exit $? + fi + create_signature "${base_dst%.sig}" || exit $? + if [[ -n $suffix ]]; then + mv -f "$base_dst" "$dst" + fi + else + export PKGEXT=${base_dst##*/} + export PKGDEST=${dst%/*} + export pkg_file=$dst + + cd "$BUILDFILEDIR" + "$makepkg" "${makepkg_opts[@]}" -p "$srcbuild" >&2 || exit $? + fi + fi +} + +# sets the variables BUILDFILE, makepkg_opts, extra_opts, mode +parse_options() { + declare -i ret=0 + local {shrt,long}{1,2} + + # makepkg options + local makepkg_orig="$(which makepkg)" + shrt1=($(LC_ALL=C "${makepkg_orig}" -h | sed -rn 's/^ +-(.)(,| [^<]).*/\1/p')) + shrt2=($(LC_ALL=C "${makepkg_orig}" -h | sed -rn 's/^ +-(.) <.*/\1/p')) + long1=($(LC_ALL=C "${makepkg_orig}" -h | sed -rn -e 's/^ +(-., )?--(\S*) [^<].*/\2/p')) + long2=($(LC_ALL=C "${makepkg_orig}" -h | sed -rn 's/^ +--(\S*) <.*/\1/p')) + + # librefetch options + shrt1+=(C D g S M h) + shrt2+=(p) + long1+=(geninteg srcbuild makepkg help) + long2+=() + + # Feed the options through getopt (sanitize them) + local shrt="$({ printf '%s\0' "${shrt1[@]}"; printf '%s:\0' "${shrt2[@]}"; } | sort -zu | xargs -0 printf '%s')" + local long="$({ printf '%s\0' "${long1[@]}"; printf '%s:\0' "${long2[@]}"; } | sort -zu | xargs -0 printf '%s,')" + local args="$(getopt -n "$cmd" -o "$shrt" -l "${long%,}" -- "$@")" + ret=$? + eval set -- "$args" + unset shrt long args + + # Parse the options. + local opt optarg have_optarg + while [[ $# -gt 0 ]]; do + opt=$1; shift + have_optarg=false + + if { [[ $opt == --?* ]] && in_array "${opt#--}" "${long2[@]}"; } \ + || { [[ $opt == -? ]] && in_array "${opt#-}" "${shrt2[@]}"; } + then + optarg=$1; shift + have_optarg=true + fi + + case "$opt" in + -C) mode=create;; + -D) mode=download;; + -g|--geninteg) mode=checksums;; + -S|--srcbuild) mode=srcbuild;; + -M|--makepkg) mode=makepkg;; + -p) BUILDFILE="$(realpath -Lm -- "$optarg")";; + -h|--help) mode=help;; + --) break;; + *) + makepkg_opts+=("$opt") + if $have_optarg; then makepkg_opts+=("$optarg"); fi + ;; + esac + done + extra_opts+=("$@") + + # check the number of extra_opts + case "$mode" in + help) # don't worry about it + :;; + checksums|srcbuild|makepkg) # don't take any extra arguments + if [[ ${#extra_opts[@]} != 0 ]]; then + print "%s: found extra non-flag arguments: %s" "$cmd" "${extra_opts[*]}" >&2 + ret=1 + fi + ;; + *download*|*create*) # take 1 or 2 extra arguments + if [[ ${#extra_opts[@]} != 1 ]] && [[ ${#extra_opts[@]} != 2 ]]; then + print "%s: %d non-flag arguments found, expected 1 or 2: %s" "$cmd" ${#extra_opts[@]} >&2 + ret=1 + fi + ;; + esac + + return $ret +} + +# Modify makepkg ############################################################### + +modified_makepkg() { + local dir="$(mktemp --tmpdir --directory "${cmd}.XXXXXXXXXXX.makepkg")" + make -s -f "$(librelib librefetchdir/Makefile)" new="$dir" + realpath -es "$dir/makepkg" +} + +# Modify PKGBUILD ############################################################## + +# a string to be appended +pkgbuild_append=' +# do not do split packages +if [[ ${#pkgname[@]} -gt 1 ]]; then + if [[ -n $pkgbase ]]; then + pkgname=("$pkgbase") + else + pkgname=("$pkgname") + fi +fi + +# copy source variables +source=("${mksource[@]}") ; unset "source_${CARCH}" +noextract=("${mknoextract[@]}") + +declare algo +for algo in "${known_hash_algos[@]}"; do + eval "${algo}sums=(\"\${mk${algo}sums[@]}\")" + unset "${algo}sums_${CARCH}" +done + +depends=() ; unset "depends_${CARCH}" +checkdepends=() ; unset "checkdepends_${CARCH}" +makedepends=("${mkdepends[@]}") ; unset "makedepends_${CARCH}" + +#### +options=(!strip docs libtool staticlibs emptydirs !zipman purge !upx !optipng !debug) +PURGE_TARGETS=(.bzr/ .cvs/ .git/ .hg/ .svn/ .makepkg/) + +#### +if ! declare -f mksource >/dev/null; then + mksource() { :; } +fi +prepare() { :; } +build() { mksource; } +check() { :; } +package() { cp -a "$srcdir"/*/ "$pkgdir/"; } +' + +modified_pkgbuild() { + local pkgbuild=$1 + local srcbuild="$(mktemp "${pkgbuild%/*}/${cmd}.XXXXXXXXXXX.PKGBUILD.to.SRCBUILD")" + printf '%s' "$pkgbuild_append" | cat "$pkgbuild" - > "$srcbuild" + printf '%s\n' "$srcbuild" +} + + +# Modify SRCBUILD ############################################################## + +modified_srcbuild() { + local orig=$1 + local srcbuild="$(mktemp "${orig%/*}/${cmd}.XXXXXXXXXXX.SRCBUILD.to.SRCBUILD")" + sed -e '/PKGDEST=/d' -e '/PKGEXT=/d' < "$orig" > "$new" + printf '%s\n' "$new" +} + +################################################################################ + +# This function is taken almost verbatim from makepkg +create_signature() { + local ret=0 + local filename="$1" + msg "Signing package..." + + local SIGNWITHKEY=() + if [[ -n $GPGKEY ]]; then + SIGNWITHKEY=(-u "${GPGKEY}") + fi + + gpg --detach-sign --use-agent "${SIGNWITHKEY[@]}" --no-armor "$filename" &>/dev/null || ret=$? + + + if (( ! ret )); then + msg2 "Created signature file %s." "$filename.sig" + else + error "Failed to sign package file." + return $ret + fi +} + +main "$@" |