summaryrefslogtreecommitdiff
path: root/src/librefetch
diff options
context:
space:
mode:
Diffstat (limited to 'src/librefetch')
-rw-r--r--src/librefetch/.gitignore2
-rw-r--r--src/librefetch/Makefile13
-rwxr-xr-xsrc/librefetch/librefetch400
-rw-r--r--src/librefetch/librefetch-install.in114
-rw-r--r--src/librefetch/librefetch-makepkg.conf.in16
-rw-r--r--src/librefetch/librefetch.8.ronn214
-rw-r--r--src/librefetch/librefetch.conf7
-rw-r--r--src/librefetch/librefetch.conf.5.ronn42
-rw-r--r--src/librefetch/librefetchdir/Makefile56
-rwxr-xr-xsrc/librefetch/librefetchdir/libmakepkg/source.sh.gen25
-rwxr-xr-xsrc/librefetch/librefetchdir/libmakepkg/tidy/purge.sh58
-rwxr-xr-xsrc/librefetch/librefetchdir/libmakepkg/tidy/~source_date_epoch.sh38
-rwxr-xr-xsrc/librefetch/librefetchdir/makepkg.gen42
13 files changed, 1027 insertions, 0 deletions
diff --git a/src/librefetch/.gitignore b/src/librefetch/.gitignore
new file mode 100644
index 0000000..d34a2fc
--- /dev/null
+++ b/src/librefetch/.gitignore
@@ -0,0 +1,2 @@
+librefetch-install
+librefetch-makepkg.conf
diff --git a/src/librefetch/Makefile b/src/librefetch/Makefile
new file mode 100644
index 0000000..26ee2ee
--- /dev/null
+++ b/src/librefetch/Makefile
@@ -0,0 +1,13 @@
+include $(dir $(lastword $(MAKEFILE_LIST)))/../../config.mk
+include $(topsrcdir)/automake.head.mk
+
+libretools-bins = librefetch librefetch-install
+libretools-confs += librefetch-makepkg.conf
+libretools-libexecs += $(filter librefetchdir/%,$(detect-exec))
+libretools-libs += $(filter-out $(libretools-libexecs),$(filter librefetchdir/%,$(detect-all)))
+pots = $(libretools-bins)
+
+$(outdir)/librefetch-install: $(var)pkgconfdir
+$(outdir)/librefetch-makepkg.conf: $(var)bindir
+
+include $(topsrcdir)/automake.tail.mk
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 "$@"
diff --git a/src/librefetch/librefetch-install.in b/src/librefetch/librefetch-install.in
new file mode 100644
index 0000000..34815a7
--- /dev/null
+++ b/src/librefetch/librefetch-install.in
@@ -0,0 +1,114 @@
+#!/usr/bin/env bash
+# lirefetch-install: (un)install librefetch to /etc/makepkg.conf
+#
+# Copyright (C) 2013-2015 Luke Shumaker <lukeshu@sbcglobal.net>
+#
+# License: GNU GPLv3+
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+set -ueE
+. "$(librelib messages)"
+
+# This line should be installed
+new_code='. @pkgconfdir@/librefetch-makepkg.conf # This line was added by librefetch-install'
+
+# These lines were installed by previous versions of this script
+old_code=(
+ '# The following line is added by the libretools post_install script'
+ '[[ ! -x /usr/bin/librefetch ]] || DLAGENTS+=("libre::/usr/bin/librefetch -p \"\$BUILDFILE\" %u %o")'
+ '[[ ! -x /usr/bin/librefetch ]] || DLAGENTS+=({https,libre}"::/usr/bin/librefetch -p \"\$BUILDFILE\" -- %u %o")'
+ 'DLAGENTS+=({https,libre}"::/usr/bin/librefetch -p $(printf "%q" "$BUILDFILE") -- %u %o")'
+ 'DLAGENTS+=({https,libre}'\''::/usr/bin/librefetch -p "$BUILDFILE" -- %u %o'\'')'
+)
+
+# has_line $file $line
+has_line() {
+ local file=$1
+ local line=$2
+ grep -Fxq -- "$line" "$file"
+}
+# del_line $file $line
+del_line() {
+ local file=$1
+ local line=$2
+ local lineno=($(grep -Fxn -- "$line" "$file" | cut -d: -f1))
+ if [[ "${#lineno[@]}" -gt 0 ]]; then
+ sed -i "$(printf '%dd;' "${lineno[@]}")" "$file"
+ fi
+}
+
+# post_install $file
+post_install() {
+ local file=$1
+ if grep -q 'librefetch' "$file"; then
+ msg2 "%s: librefetch is already in %q" "${0##*/}" "$(realpath -s "$file")"
+ local line del=false
+ for line in "${old_code[@]}"; do
+ if has_line "$file" "$line"; then
+ msg2 "%s: ... but it's an old version" "${0##*/}"
+ pre_remove "$file"
+ post_install "$file"
+ return $?
+ fi
+ done
+ else
+ msg2 "%s: adding librefetch to %q" "${0##*/}" "$(realpath -s "$file")"
+ printf '%s\n' "$new_code" >> "$file"
+ fi
+}
+
+# pre_remove $file
+pre_remove() {
+ local file=$1
+ msg2 "%s: removing librefetch from %q" "${0##*/}" "$(realpath -s "$file")"
+
+ # Check for the old stuff
+ sed -ri 's/^#(.*) # commented out by the libretools post_install script/\1/' "$file"
+ local line
+ for line in "${old_code[@]}"; do
+ del_line "$file" "$line"
+ done
+
+ # Check for the current stuff
+ del_line "$file" "$new_code"
+}
+
+usage() {
+ print "Usage: %s [install|remove] MAKEPKG_CONF_FILE" "${0##*/}"
+ print "Adds or removes librefetch to/from makepkg.conf:DLAGENTS"
+}
+
+main() {
+ if [[ $# != 2 ]]; then
+ usage >&2
+ return 1
+ fi
+ local file=$2
+ if [[ ! -f "$file" ]]; then
+ msg2 "%s: does not exist: %q" "${0##*/}" "$(realpath -s "$file")"
+ fi
+ if [[ ! -w "$file" ]]; then
+ msg2 "%s: cannot write to file: %q" "${0##*/}" "$(realpath -s "$file")"
+ fi
+ case "$1" in
+ install) post_install "$file";;
+ remove) pre_remove "$file";;
+ *) usage >&2; return 1;;
+ esac
+}
+
+main "$@"
diff --git a/src/librefetch/librefetch-makepkg.conf.in b/src/librefetch/librefetch-makepkg.conf.in
new file mode 100644
index 0000000..723bc15
--- /dev/null
+++ b/src/librefetch/librefetch-makepkg.conf.in
@@ -0,0 +1,16 @@
+#!/hint/bash
+
+# This file should be 'source'd by makepkg.conf to enable librefetch
+edit_dlagents() {
+ local dlagent="@bindir@/librefetch -p $(printf %q "$(realpath -Lm "${BUILDFILE:-${BUILDSCRIPT:-PKGBUILD}}")") -- %u %o"
+
+ local i
+ for i in "${!DLAGENTS[@]}"; do
+ if [[ "${DLAGENTS[$i]}" = https::* ]]; then
+ DLAGENTS[$i]="https::$dlagent"
+ fi
+ done
+ DLAGENTS+=("libre::$dlagent")
+}
+edit_dlagents
+unset -f edit_dlagents
diff --git a/src/librefetch/librefetch.8.ronn b/src/librefetch/librefetch.8.ronn
new file mode 100644
index 0000000..cf009de
--- /dev/null
+++ b/src/librefetch/librefetch.8.ronn
@@ -0,0 +1,214 @@
+librefetch(8) -- downloads or creates a liberated source tarball
+================================================================
+
+## SYNOPSIS
+
+`librefetch` [<OPTIONS>] <SOURCE-URL> [<OUTPUT-FILE>]<br>
+`librefetch` `-`[`g`|`S`|`M`|`h`]
+
+## DESCRIPTION
+
+`librefetch` is a program to streamline creation of custom source
+tarballs for `PKGBUILD(5)` files.
+
+If a URL mentioned in the <source> array in a `PKGBUILD` is in a
+location that Parabola uploads "custom" source tarballs to (or
+configured locations), and no file is at that URL, librefetch will
+automatically create it for you.
+
+This works because a post-install script for the package configures
+`librefetch` as the download agent for `https://` URLs in
+`makepkg.conf`; allowing it to jump in and create a file if need be.
+Because of this, it is almost never necessary to call `librefetch`
+manually.
+
+The post-install script also configures `librefetch` as the download
+agent for `libre://` URLs, for compatibility with `PKGBUILD` files
+that used a previous version of librefetch.
+
+There are 5 modes:
+
+ * `download`: Download the tarball from the configured mirror.
+ * `create`: Create the tarball from a `PKGBUILD`/`SRCBUILD`.
+ * `checksums`: Generate integrity checks for source files.
+ * `srcbuild`: Print the effective build script.
+ * `makepkg`: Generate and print the location of the effective makepkg
+ script.
+ * `help`: Print `librefetch` usage information.
+
+The normal mode of operation is `download` mode. If `download` mode
+fails, it may choose to try `create` mode.
+
+## OPTIONS
+
+ * `-C`: Force `create` mode (don't download)
+ * `-D`: Force `download` mode (don't create)
+ * `-p` <file>: Use an alternate build script for `create` mode
+ (instead of `PKGBUILD`). If an `SRCBUILD` file exists in the same
+ directory, it is used instead.
+ * `-g` | `--geninteg`: Use `checksums` mode: Generate integrity
+ checks for source files.
+ * `-S` | `--srcbuild`: Use `srcbuild` mode: print the effective build
+ script.
+ * `-M` | `--makepkg`: Use `makepkg` mode: generate and print the
+ location of the effective makepkg script.
+ * `-h` | `--help`: Use `help` mode: Show usage information.
+
+Other options, if they are documented in `makepkg -h`, are passed to
+the modified copy of makepkg created during `create` mode.
+
+## DOWNLOAD MODE
+
+If <SOURCE-URL> begins with the string `libre://`, it is replaced with
+the first value in <MIRRORS>, as configured in `librefetch.conf(5)`;
+this is for compatibility with `PKGBUILD` files that used a previous
+version of librefetch.
+
+It uses <DOWNLOADER>, as configured in `librefetch.conf` to attempt to
+download the source tarball from that URL. If that fails, and
+following conditions are met, it proceeds to `create` mode:
+
+ * The `-D` flag has not been specified to inhibit `create` mode.
+ * The <SOURCE-URL> begins with one of the values in <MIRRORS>.
+
+The latter requirement allows librefetch to be used as a generic
+HTTP(S) download agent, that can automatically create files from
+whitelisted locations.
+
+## CREATE MODE
+
+The principle of `create` mode is that a special `PKGBUILD(5)` (called
+`SRCBUILD(5)`) installs source files to <$pkgdir>, and the resulting
+"package" is then used as a source tarball. The `SRCBUILD` exists in
+the same directory as the `PKGBUILD`. It can be created manually, or
+generated on-the-fly from the `PKGBUILD`. Extra steps are taken to
+ensure that as long as the same directory contents go in, an identical
+tarball will come out--the checksum of the file should not change
+based on when it is built or who builds it.
+
+The `SRCBUILD` is either created, or sanitized if it already exists.
+If the output filename does not end with `.sig` or `.sig.part`, then
+the `SRCBUILD` is fed to a modified version of `makepkg(8)`. If the
+output filename does end with `.sig` or `.sig.part`, then it uses GPG
+to create a signature. If the file it is trying to sign does not
+exist yet, librefetch recurses on itself to create it.
+
+The reason `makepkg` must be modified is that we need the resulting
+tarball to be deterministic (as well as not containing package
+metadata).
+
+When this documentation speaks of a file being modified, it is a
+temporary copy of the file that is modified, your original file will
+remain intact.
+
+## SRCBUILD GENERATION
+
+As explained in the `CREATE MODE` section, in `create` mode, this
+program generates an `SRCBUILD` file. For debugging purposes, this
+file can be printed instead of executed with `srcbuild` mode.
+
+### PRE-EXISTING SRCBUILD
+
+The use of `SRCBUILD` files pre-dates `librefetch`. By convention,
+they set <PKGDEST> and <PKGEXT> in `package()` in order to modify the
+behavior of `makepkg`. Because a modified version of `makepkg` is
+used, this interferes with the correct behavior. To compensate for
+this, lines containing "`PKGDEST=`" or "`PKGEXT=`" are deleted from
+the `SRCBUILD`.
+
+The general idea is that `build()` makes any modifications to the
+source, then `package()` copies it from <$srcdir> to <$pkgdir>.
+
+### SRCBUILD FROM PKGBUILD
+
+Possibly more elegant than having a separate `SRCBUILD` file is having
+an `mksource()` function in the main `PKGBUILD`. This results in less
+boilerplate and fewer files to edit.
+
+Note that this only happens if a file named `SRCBUILD` doesn't already
+exist; when migrating a package from a manually created `SRCBUILD` to
+this method, the `SRCBUILD` must be deleted (or renamed) for this to
+work.
+
+The dynamically created `SRCBUILD` is created by copying `PKGBUILD` to
+a temporary file, then re-setting variables and re-defining functions.
+Following is a table of the translations.
+
+ Variables
+ source = mksource
+ noextract = mknoextract
+ *sums = mk*sums (md5, sha1, sha224, sha256, sha384, sha512)
+ depends = <empty>
+ checkdepends = <empty>
+ makedepends = mkdepends
+ *_$CARCH = <unset>
+ Functions
+ prepare() { :; }
+ build() { mksource; }
+ check() { :; }
+ package() { cp -a "$srcdir"/*/ "$pkgdir/"; }
+
+The `mksource()` function does not need to be defined. If it isn't
+defined, then no transformations will be made to the source between it
+being extracted to <$srcdir> and copied to <$pkgdir>.
+
+In summary:
+
+ * Set <mksource=()> and <mkmd5sums=()> to act as <source=()> and
+ <md5sums=()>, respectively.
+ * Declare a `mksource()` function to make modifications to the
+ source, if necessary.
+
+Other changes:
+
+ * <pkgname> is set to <pkgbase>, or the first element of the
+ <pkgname> array (the effect is that split packaging is turned
+ off).
+ * <options=()> is set have `makepkg` avoid making changes to
+ <$pkgdir>. The exact change is:
+
+ options=(!strip docs libtool staticlibs emptydirs !zipman purge !upx)
+
+ * <PURGE_TARGETS=()> has VCS directories added to it:
+
+ PURGE_TARGETS=(.bzr/ .cvs/ .git/ .hg/ .svn/ .makepkg/)
+
+### MAKEPKG MODIFICATIONS
+
+The following modifications are made to makepkg:
+
+ * Allow us to manipulate the output file (<$pkg_file>)
+ * Do not include metadata in the output file (<${comp_files[@]}>)
+ * Force 'ustar' tar format, don't allow it to upgrade to 'pax' to
+ store extended file attributes.
+ * Don't symlink the resulting file into the current directory.
+ * <PURGE_TARGETS> interprets an item as a directory if it ends with a
+ slash ("/").
+ * Timestamps in <$pkgdir> are reset to the date specified in
+ <SOURCE_DATE_EPOCH>[1], or "1990-01-01 0:0:0 +0" if it's not set, so
+ that the resulting tarball will be the same, regardless of when it
+ was created.
+ * Sort the files included in the tarball; normally the order of files
+ in a tarball is essentially random (even if it tends to be the same
+ when re-created on the same machine).
+ * append `-libre` to <$srcdir>
+ * append `-libre` to <$pkgbasedir> (which becomes <$pkgdir>)
+ * Don't check if the package has already been built.
+
+For debugging purposes, this modified makepkg can be printed instead
+of executed with `makepkg` mode. Before it is run in create mode,
+`PKGEXT`, `PKGDEST`, and `pkg_file` are set as environment variables.
+
+## CONFIGURATION
+
+See `librefetch.conf(5)` for details on configuring librefetch using
+the `librefetch.conf` file.
+
+## SEE ALSO
+
+librefetch.conf(5), makepkg(8), PKGBUILD(5), SRCBUILD(5)
+
+## NOTES
+
+ 1. <SOURCE_DATE_EPOCH> specification for build systems
+ https://reproducible-builds.org/specs/source-date-epoch/
diff --git a/src/librefetch/librefetch.conf b/src/librefetch/librefetch.conf
new file mode 100644
index 0000000..7251ff3
--- /dev/null
+++ b/src/librefetch/librefetch.conf
@@ -0,0 +1,7 @@
+MIRRORS=(
+ 'https://repo.parabola.nu/sources/'
+ 'https://repo.parabola.nu/other/'
+ 'https://repo.parabolagnulinux.org/sources/'
+ 'https://repo.parabolagnulinux.org/other/'
+)
+DOWNLOADER='/usr/bin/curl -fLC - --retry 3 --retry-delay 3 -o %o %u'
diff --git a/src/librefetch/librefetch.conf.5.ronn b/src/librefetch/librefetch.conf.5.ronn
new file mode 100644
index 0000000..29df4d2
--- /dev/null
+++ b/src/librefetch/librefetch.conf.5.ronn
@@ -0,0 +1,42 @@
+librefetch.conf(5) -- librefetch configuration file
+===================================================
+
+## SYNOPSIS
+
+`/etc/libretools.d/librefetch.conf`, `~/.config/libretools/librefetch.conf`
+
+## DESCRIPTION
+
+Configuration for librefetch is stored in `librefetch.conf`. The
+several places it looks for the file are:
+
+ * `/etc/libretools.d/librefetch.conf`
+ * `$XDG_CONFIG_HOME/libretools/librefetch.conf`
+
+The later files take precedence over earlier files, but earlier files
+are loaded, so that later files only need to set the values they want
+to override.
+
+If `$XDG_CONFIG_HOME` is not set, a default value is set:
+
+ * if `$SUDO_USER` is set: `$(eval echo ~$SUDO_USER)/.config`
+ * else: `$HOME/.config`
+
+## OPTIONS
+
+ * `MIRRORS=( ... )`:
+ A list of locations that generated source tarballs may be located
+ at. If a URL begins with `libre://`, then `libre://` is replaced
+ with the first location listed here.
+ * `DOWNLOADER='/usr/bin/curl -fLC - --retry 3 --retry-delay 3 -o %o %u'`:
+ The HTTP client to use when downloading pre-built source tarballs
+ in download mode. The format and semantics are similar to
+ `DLAGENTS` in `makepkg.conf`(5). If present, `%u` will be replaced
+ with the download URL (correctly quoted), otherwise the download
+ URL will be appended to the end of the command. If present, `%o`
+ will be replaced with the local filename that it should be
+ downloaded to.
+
+## SEE ALSO
+
+librefetch(8), makepkg.conf(5)
diff --git a/src/librefetch/librefetchdir/Makefile b/src/librefetch/librefetchdir/Makefile
new file mode 100644
index 0000000..58116bb
--- /dev/null
+++ b/src/librefetch/librefetchdir/Makefile
@@ -0,0 +1,56 @@
+#!/usr/bin/env bash
+# librefetchdir/Makefile
+#
+# Copyright (C) 2016 Luke Shumaker <lukeshu@sbcglobal.net>
+#
+# 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/>.
+
+# new =
+librefetchdir := $(dir $(lastword $(MAKEFILE_LIST)))
+
+old_makepkg := $(shell which makepkg)
+old_library := $(shell $(shell grep LIBRARY= $(old_makepkg)); echo $$LIBRARY)
+
+new_makepkg = $(new)/makepkg
+new_library = $(new)/libmakepkg
+
+targets += $(new_makepkg)
+targets += $(patsubst $(old_library)/%,$(new_library)/%,$(shell find $(old_library) -type f))
+targets += $(new_library)/tidy/~source_date_epoch.sh
+
+all: $(targets)
+.PHONY: all
+
+.SECONDARY:
+.DELETE_ON_ERROR:
+
+$(new_makepkg): $(old_makepkg) $(librefetchdir)/makepkg.gen
+ <$^ | install -Dm755 /dev/stdin $@
+
+$(new_library)/source.sh: \
+$(new_library)/%: $(old_library)/% $(librefetchdir)/libmakepkg/%.gen
+ <$^ | install -Dm755 /dev/stdin $@
+
+$(new_library)/tidy/purge.sh $(new_library)/tidy/~source_date_epoch.sh: \
+$(new_library)/%: $(librefetchdir)/libmakepkg/%
+ mkdir -p $(@D)
+ ln -sfT $(abspath $< $@)
+
+$(new_library)/%: $(old_library)/%
+ mkdir -p $(@D)
+ ln -sfT $(abspath $< $@)
diff --git a/src/librefetch/librefetchdir/libmakepkg/source.sh.gen b/src/librefetch/librefetchdir/libmakepkg/source.sh.gen
new file mode 100755
index 0000000..269f9fd
--- /dev/null
+++ b/src/librefetch/librefetchdir/libmakepkg/source.sh.gen
@@ -0,0 +1,25 @@
+#!/usr/bin/sed -rf
+# librefetchdir/makepkg.gen
+#
+# Copyright (C) 2013, 2016 Luke Shumaker <lukeshu@sbcglobal.net>
+#
+# 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/>.
+
+/download_sources\(\) \{/ {
+ arm -rf "$srcdir"\nmkdir "$srcdir"
+}
diff --git a/src/librefetch/librefetchdir/libmakepkg/tidy/purge.sh b/src/librefetch/librefetchdir/libmakepkg/tidy/purge.sh
new file mode 100755
index 0000000..acb0030
--- /dev/null
+++ b/src/librefetch/librefetchdir/libmakepkg/tidy/purge.sh
@@ -0,0 +1,58 @@
+#!/usr/bin/bash
+#
+# purge.sh - Remove unwanted files from the package
+#
+# Copyright (c) 2008-2016 Pacman Development Team <pacman-dev@archlinux.org>
+# Copyright (c) 2013-2016 Luke Shumaker <lukeshu@sbcglobal.net>
+#
+# License: GNU GPLv2+
+#
+# This file is part of LibreFetch
+#
+# This program 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 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+[[ -n "$LIBMAKEPKG_TIDY_PURGE_SH" ]] && return
+LIBMAKEPKG_TIDY_PURGE_SH=1
+
+LIBRARY=${LIBRARY:-'/usr/share/makepkg'}
+
+source "$LIBRARY/util/message.sh"
+source "$LIBRARY/util/option.sh"
+
+
+packaging_options+=('purge')
+tidy_remove+=('tidy_purge')
+
+tidy_purge() {
+ if check_option "purge" "y" && [[ -n ${PURGE_TARGETS[*]} ]]; then
+ msg2 "$(gettext "Purging unwanted files...")"
+ 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
+ fi
+}
diff --git a/src/librefetch/librefetchdir/libmakepkg/tidy/~source_date_epoch.sh b/src/librefetch/librefetchdir/libmakepkg/tidy/~source_date_epoch.sh
new file mode 100755
index 0000000..9141d67
--- /dev/null
+++ b/src/librefetch/librefetchdir/libmakepkg/tidy/~source_date_epoch.sh
@@ -0,0 +1,38 @@
+#!/usr/bin/bash
+#
+# librefetchdir/libmakepkg/tidy/~source_date_epoch.sh
+#
+# Copyright (C) 2013-2016 Luke Shumaker <lukeshu@sbcglobal.net>
+#
+# 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/>.
+
+# This filename starts with a ~ because it sorts after every other
+# (printable) ASCII character, and we want this to run last.
+
+[[ -n "$LIBMAKEPKG_TIDY_SOURCE_DATE_EPOCH_SH" ]] && return
+LIBMAKEPKG_TIDY_SOURCE_DATE_EPOCH_SH=1
+
+tidy_modify+=('tidy_source_date_epoch')
+
+tidy_source_date_epoch() {
+ local date='1990-01-01 0:0:0 +0'
+ if [[ -n "$SOURCE_DATE_EPOCH" ]]; then
+ date="@$SOURCE_DATE_EPOCH"
+ fi
+ find . -exec touch --no-dereference --date="$date" -- {} +
+}
diff --git a/src/librefetch/librefetchdir/makepkg.gen b/src/librefetch/librefetchdir/makepkg.gen
new file mode 100755
index 0000000..8928d91
--- /dev/null
+++ b/src/librefetch/librefetchdir/makepkg.gen
@@ -0,0 +1,42 @@
+#!/usr/bin/sed -rf
+# librefetchdir/makepkg.gen
+#
+# Copyright (C) 2013-2016 Luke Shumaker <lukeshu@sbcglobal.net>
+#
+# 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/>.
+
+/LIBRARY=/iexport LIBRARY="${0%/*}/libmakepkg"
+
+/create_package\(\) \{/,/^\}$/ {
+ /pkg_file=/d # allow us to set pkg_file
+ s/"?\$\{comp_files\[@\]\}"?// # do not include .{PKGINFO,BUILDINGO,CHANGELOG,INSTALL,MTREE}
+ # This is long/gross. What it does:
+ # - pass --format=ustar to bsdtar, to inhibit it using the pax format
+ # - take the files that would be included in the tarball, and use
+ # find/sort/--files-from to order them for bsdtar
+ s/bsdtar(.*) - ([^|]*) \|/find \2 -print0 | LC_ALL=C sort --zero-terminated | bsdtar --null --files-from - --format=ustar --no-recursion \1 - |/
+ s/create_signature .*/&; return $?/ # do not procede to create symlinks
+}
+
+s|Making package:|Making source:|
+s|Checking runtime dependencies\.\.\.|Checking source dependencies...|
+ /Checking buildtime dependencies\.\.\./d
+
+s|srcdir=.*|&-libre|
+s|pkgdirbase=.*|&-libre|
+s|check_build_status$|:|