Skip to content

Instantly share code, notes, and snippets.

@iainlane
Created March 4, 2019 17:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iainlane/6360602ebd945f0f6c7a126091f02b79 to your computer and use it in GitHub Desktop.
Save iainlane/6360602ebd945f0f6c7a126091f02b79 to your computer and use it in GitHub Desktop.
#!/bin/bash
# Run me like this:
# Download all the Packages files
# update-output-helper -u
# Create a worldview that britney is trying to mutate us to
# update-output-helper package/version package2/version2/ ...
# outputs an apt-get commandline to use
# Then call apt with this world view
# <apt-get command> update
# <apt-get command> --dry-run install <some uninstallable package>
# and you can drill down as normal to find which package(s) need fixing
set -e
GETOPT=$(getopt --options uh --long update,help -n "${0}" -- "$@")
eval set -- "${GETOPT}"
ARCH=${ARCH:-$(dpkg-architecture -qDEB_HOST_ARCH)}
CACHEDIR=${XDG_CACHE_HOME:-$HOME/.cache}/brapt
APTDIR=${CACHEDIR}/aptroot
RELEASE=$(ubuntu-distro-info --devel)
RELEASE_PACKAGES="${CACHEDIR}/Packages_${RELEASE}"
PROPOSED_PACKAGES="${CACHEDIR}/Packages_${RELEASE}-proposed"
[ ! -d "${CACHEDIR}" ] && mkdir -p "${CACHEDIR}"
[ ! -d "${APTDIR}" ] && mkdir -p "${APTDIR}"
ensure_programs() {
if [ $# -gt 0 ] && ! type "${1}" >/dev/null 2>/dev/null; then
echo "Required program $1 not found."
exit 1
fi
shift
if [ $# -gt 0 ]; then
ensure_programs $*
fi
}
ensure_apt_structure() {
mkdir -p "${APTDIR}/etc/apt/preferences.d" \
"${APTDIR}/var/cache/apt/archives/partial" \
"${APTDIR}/var/lib/apt/lists"
[ ! -e "etc/apt/sources.list" ] && \
echo "deb [trusted=yes] file://${APTDIR} ./" > "${APTDIR}/etc/apt/sources.list"
touch "${APTDIR}/status"
}
update() {
case ${ARCH} in
i386|amd64)
local MIRROR="http://archive.ubuntu.com/ubuntu"
;;
*)
local MIRROR="http://ports.ubuntu.com"
;;
esac
local COMPONENTS=(main universe multiverse restricted)
for series in "${RELEASE}" "${RELEASE}-proposed"; do
local FILE="${CACHEDIR}/Packages_${series}"
[ -e "${FILE}" ] && rm "${FILE}"
for component in "${COMPONENTS[@]}"; do
local URL="${MIRROR}/dists/${series}/${component}/binary-${ARCH}/Packages.xz"
echo "Downloading ${URL}"
wget -q -O - "${URL}" | xzcat >> "${CACHEDIR}/Packages_${series}"
done
done
}
while true; do
case "$1" in
-u|--update)
update
shift
;;
-h|--help)
echo "Usage: $0 [-u] package/version ..."
shift
;;
--)
shift
break
;;
*)
echo "Error"
exit 1;
;;
esac
done
if [ $# -eq 0 ]; then
exit 0
fi
PROPOSED_PATTERN=()
RELEASE_PATTERN=()
while [ $# -gt 0 ]; do
PKG=${1%/*}
VERSION=${1#*/}
shift
echo "Looking at ${PKG}/${VERSION}"
if [ "${PKG}" = "${VERSION}" ]; then
echo "Error: ${PKG} is not in the format PACKAGE/VERSION" >&2
exit 1
fi
if [ $# -gt 0 ]; then
O="-o "
else
O=
fi
#PROPOSED_PATTERN="${PROPOSED_PATTERN:- }( -X -S ${PKG} -a -FVersion ${VERSION} ) ${O}"
#RELEASE_PATTERN="${RELEASE_PATTERN:- }( -X -S ${PKG} -a -! -FVersion ${VERSION} ) ${O}"
PKGVER="${PKG} (${VERSION})"
PROPOSED_PATTERN+=('(' -X -S ${PKG} -a -FVersion ${VERSION} ')' -o '(' -X -S "${PKGVER}" ')' ${O})
RELEASE_PATTERN+=('(' -X -S ${PKG} -a -! -FVersion ${VERSION} ')' -o '(' '(' -e -S "${PKG} " ')' -a '(' -! -X -S "${PKGVER}" ')' ')' ${O})
done
ensure_programs wget grep-dctrl xzcat
ensure_apt_structure
cat ${RELEASE_PACKAGES[@]} | grep-dctrl -v "${RELEASE_PATTERN[@]}" > ${APTDIR}/Packages
cat ${PROPOSED_PACKAGES[@]} | grep-dctrl "${PROPOSED_PATTERN[@]}" >> ${APTDIR}/Packages
apt-get -oDir=${APTDIR} -oDir::State::status=${APTDIR}/status update
echo "apt-get -oDir=${APTDIR} -oDir::State::status=${APTDIR}/status --dry-run install <some broken package> ..."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment