diff options
Diffstat (limited to 'drain')
-rwxr-xr-x | drain | 128 |
1 files changed, 128 insertions, 0 deletions
@@ -0,0 +1,128 @@ +#!/usr/bin/env bash +# Copyright 2016-2017 Luke Shumaker +# This work is free. You can redistribute it and/or modify it under the +# terms of the Do What The Fuck You Want To Public License, Version 2, +# as published by Sam Hocevar. See the COPYING file for more details. + +# The user should not call this script directly. + +declare -r workdir=/var/lib/pristine-etc + +watchdirs=( + /etc + /usr/share/holo/files +) +readonly watchdirs + +pacman-watched-name-ver-dirs() { + local dir dirs + dirs=() + for dir in "${watchdirs[@]}"; do + if [[ -d "$dir" ]]; then + dirs+=("$dir") + fi + done + LC_ALL=C pacman -Qo "${dirs[@]}" | sed -r 's| is owned by | |' | + awk '{i=$2" "$3; a[i]=a[i]" "$1} END{for(i in a){print i " " a[i]}}' +} + +pacman-all-name-arch() { + LC_ALL=C pacman -Qni | tr $'\n' $'\r' | sed 's/\r\r/\n/g' | sed -r 's|(.*\r)?Name\s*:\s*(\S+)(\r.*)?\rArchitecture\s*:\s*(\S+)\r.*|\2 \4|' +} + +pacman-watched-name-arch-ver-dirs() { + join <(pacman-all-name-arch|sort) <(pacman-watched-name-ver-dirs|sort) +} + +commit() ( + msg="$1" + + cd "$workdir" + if ! [[ -d etc.git ]]; then + mkdir -p chroot/etc + (cd chroot/etc && etckeeper init -d "$PWD") + mv chroot/etc/.git etc.git + fi + rm -rf chroot + mkdir chroot + cd chroot + + err=false + files=() + while IFS=' ' read -r pkgname arch pkgver dirs; do + file=("/var/cache/pacman/pkg/$pkgname-$pkgver-$arch".pkg.tar.*) + if ! test -f "$file"; then + printf "ERROR: no cached package for %s %s %s\n" "$pkgname" "$pkgver" "$arch" + err=true + fi + files+=("$file $dirs") + done < <(pacman-watched-name-arch-ver-dirs) + if $err; then + return 1 + fi + for filespec in "${files[@]}"; do + read file dirs_str <<<"$filespec" + read -a dirs <<<"$dirs_str" + printf " -> %s\n" "$file" + bsdtar xpvf "$file" "${dirs[@]#/}" + done + + ln -srT ../etc.git etc/.git + + if type holo &>/dev/null; then + mkdir -p -- run usr/lib + ln -sT /usr/lib/holo usr/lib/holo + if [ -f /etc/os-release ]; then + ln -sT /etc/os-release usr/lib/os-release + else + ln -sT /usr/lib/os-release usr/lib/os-release + fi + HOLO_ROOT_DIR=. holo apply + fi + cd etc/ + etckeeper update-ignore -d "$PWD" + if etckeeper unclean -d "$PWD"; then + etckeeper commit -d "$PWD" "$msg" + fi +) + +pull() ( + cd /etc + git remote add pristine "${workdir}/chroot/etc" &>/dev/null || true + git fetch pristine +) + +lock() { + local fd=$1 + local file=$2 + eval "exec $fd>"'"$file"' + flock "${@:3}" "$fd" +} + +unlock() { + local fd=$1 + exec {fd}>&- +} + +main() { + set -e -o pipefail + umask 0022 + + if ! lock 7 "${workdir}/chroot.lock" -n; then + return 0 + fi + while true; do + lock 8 "${workdir}/spool.lock" + if ! [[ -f "${workdir}/spool" ]]; then + return 0 + fi + msg="$(cat "${workdir}/spool")" + rm -f "${workdir}/spool" + unlock 8 + + commit "$msg" + pull + done +} + +main "$@" |