#!/usr/bin/env bash # librefetch # # Copyright (C) 2013-2014 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 . . $(librelib conf) . $(librelib messages) setup_traps declare -r tempdir="$(mktemp -d --tmpdir ${0##*/}.XXXXXXXXXXX)" trap "rm -rf -- $(printf '%q' "$tempdir")" EXIT cmd=${0##*/} usage() { print "Usage: %s [OPTIONS] SOURCE_URL [OUTPUT_FILE]" "$cmd" print "Usage: %s -[g|P|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 looks at a build script, and uses that to create the source tarball. SOURCE_URL is ignored, except that it is used to set the default value of OUTPUT_FILE." echo prose "The default build script is 'PKGBUILD', or 'SRCBUILD' if it exists." echo prose "Unrecognized options are passed straight to makepkg." echo prose "%s does NOT support getopt-style flag combining. You must use '-a -b', not '-ab'." "$cmd" echo print "Example usage:" print ' $ %s https://repo.parabolagnulinux.org/other/mypackage/mypackage-1.0.tar.gz' "$cmd" echo print "Options:" print " Settings:" flag "-C" "Force create mode (don't download)" flag "-D" "Force download mode (don't create)" flag "-p <$(_ FILE)>" "Use an alternate build script (instead of 'PKGBUILD') If an SRCBUILD exists in the same directory, it is used instead" print " Alternate modes:" flag "-g, --geninteg" "Generage integrity checks for source files" flag "-P, --print" "Print the effective build script (SRCBUILD)" flag "-h, --help" "Show this message" } main() { BUILDFILE="$(readlink -m PKGBUILD)" makepkg_opts=() extra_opts=() mode=download-create parse_options "$@" # Mode: help ########################################################### if [[ $mode =~ help ]]; then usage return 0 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 makepkg="$(modified_makepkg "$(which makepkg)")" # 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 return 0 fi # Mode: print ########################################################## if [[ $mode =~ print ]]; then cat "$srcbuild" return 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="$(readlink -m -- "$dst")" # Mode: download ####################################################### if [[ $mode =~ download ]]; then load_files librefetch check_vars librefetch MIRRORS DOWNLOADER || return 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 && return 0 fi # Mode: create ######################################################### if [[ $mode =~ create ]]; then PKGEXT=${dst##*/} export PKGEXT=${PKGEXT%.part} export PKGDEST=${dst%/*} export pkg_file=$dst cd "$BUILDFILEDIR" "$makepkg" "${makepkg_opts[@]}" -p "$srcbuild" >&2 || return $? fi } # sets the variables BUILDFILE, makepkg_opts, extra_opts, mode parse_options() { # Detect makepkg options local makepkg_orig="$(which makepkg)" # --long flags that take a second argument local makepkg_opt2long=( $(LC_ALL=C "${makepkg_orig}" -h | sed -rn 's/\s*(--\S*) <.*/\1/p')) # -s hort flags that take a second argument local makepkg_opt2short=($(LC_ALL=C "${makepkg_orig}" -h | sed -rn 's/\s*(-.) <.*/\1/p')) # all flags local makepkg_argall=( $(LC_ALL=C "${makepkg_orig}" -h | sed -rn \ -e 's/^ +(-.) .*/\1/p' \ -e 's/^ +(-.), (--\S*) .*/\1\n\2/p' \ -e 's/^ +(--\S*) .*/\1/p')) local opt local have_opt while [[ $# -gt 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|--print) mode=print;; -p) BUILDFILE="$(readlink -m -- "$opt")";; -h|--help) mode=help;; --) shift; break;; -*) if in_array "${arg}" "${makepkg_argall[@]}"; then makepkg_opts+=("$arg") $have_opt && makepkg_opts+=("$opt") else printf '%s: invalid flag: %s' "$cmd" "$arg" return 1 fi ;; *) extra_opts+=("$arg");; esac shift done extra_opts+=("$@") # check the number of extra_opts case "$mode" in help) # don't worry about it :;; checksums|print) # don't take any extra arguments if [[ ${#extra_opts[@]} != 0 ]]; then print "%s: found extra non-flag arguments: %s" "$cmd" "${extra_opts[*]}" >&2 usage >&2 return 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 usage >&2 return 1 fi ;; esac } # Modify makepkg ############################################################### # an ERE makepkg_modify=' /create_package\(\) \{/,/^\}$/ { /pkg_file=/d # allow us to set pkg_file s/"?\$\{comp_files\[@\]\}"?// # do not include .{PKGINFO,INSTALL,CHANGELOG} s/bsdtar /&--format=ustar / # ustar, not pax s/create_signature .*/&; return $?/ # do not procede to create symlinks } /tidy_install\(\) \{/,/^\}$/ { /for .*PURGE_TARGETS/itidy_install_purge /for .*PURGE_TARGETS/,/done/d /^\}$/ifind . -exec touch --date="1990-01-01 0:0:0 +0" {} + } /download_sources\(\) \{/ { arm -rf "$srcdir"\nmkdir "$srcdir" } s|srcdir=.*|&-libre| s|pkgdirbase=.*|&-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 } 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 [[ ${#pkgname[@]} -gt 1 ]]; then if [[ -n $pkgbase ]]; then pkgname=("$pkgbase") else pkgname=("$pkgname") fi 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 staticlibs emptydirs !zipman purge !upx) 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="$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 '/PKGEXT=/d' < "$orig" > "$new" printf '%s\n' "$new" } main "$@"