Posts Tagged ‘archlinux’

Holy crap. This “blog” is almost dead. Lemme give it some love.

While finishing up a rewrite of our database scripts at ArchAudio I had to figure out a solution to clear out old packages in the repositories. The way our stuff works is actually dependent solely on Subversion, and there is no SSH involved. You can guess that this means our binary packages are just SVN commits.

As such, without getting too hacky, you are not going to get a list of packages being “uploaded”. You are going to need to work with an arbitrary number of packages at a time, so fellow Arch Linux user Bluewind‘s script for his personal repositories is not going to cut it (note: this is false and is actually an excuse for my inability to read Perl). I also want to keep our scripts in Bash (aside from the mailer which is in Python and is just a copy-paste from a template) to allow potentially more people to contribute.

I figured I would just need something like Pacman‘s clean function, but for the makepkg cache instead. I thought something like that might already exist, but a search through the AUR, ArchWiki and Arch Forums turned up nothing. In not wanting to waste any more time, I figured reinventing the wheel wouldn’t be that great of a loss if I couldn’t find the wheel in the first place. So here it is:


# Copyright (c) 2011 Ray Rashif  - GNU GPL

get_fext() {
	echo $1 | rev | awk -F "-" '{print $1}' | rev

get_pver() {
	echo $1 | rev | awk -F "-" '{print $2"-"$3}' | rev

get_pname() {
	local fext pver

	fext=$(get_fext $1)
	pver=$(get_pver $1)

	echo ${1/-$pver-$fext}

# clean package extensions first
echo -n "Getting rid of old package formats..."

for pfile in *.pkg.tar.*; do
	# exit cleanly if nothing was found
	if [[ "$pfile" = '*.pkg.tar.*' ]]; then
		echo "none found"
		echo "No packages found, nothing to do."
		exit 0

	fext=$(get_fext $pfile)
	pver=$(get_pver $pfile)

	# just edit the RE for more formats
	pext_matches=($(\ls -v $id.[gx]z))

	if [[ ${#pext_matches[@]} -gt 1 ]]; then
		for match in ${pext_matches[@]}; do
			[[ "$match" != "$id.xz" ]] && \
				rm -f $match && oldremoved=1

[[ $oldremoved -eq 1 ]] && echo "done" || echo "none found"

# now clean the rest
for pfile in *.pkg.tar.*; do
	fext=$(get_fext $pfile)
	pver=$(get_pver $pfile)

	matches=($(\ls -v $pname-*-$parch.*))

	# for cases like foo, foo-bar, prevent mixing them up
	for oldpkg in $(seq 0 $((${#matches[@]} - 1))); do
		oldname=$(get_pname ${matches[$oldpkg]})
		[[ "$oldname" != "$pname" ]] && unset matches[$oldpkg]


	# if only one match then obviously nothing to do
	[[ $t_matches -eq 1 ]] && continue

	# get oldest and newest versions
	oldest=$(get_pver ${matches[0]})
	newest=$(get_pver ${matches[$t_matches-1]})

	echo "Cleaning $pname [$oldest -> $newest] ($parch)"

	# WARNING: logic based on ls natural version sort order;
	#   some types of versioning may fail this order
	#   last item is assumed latest
	for oldpkg in $(seq 0 $(($t_matches - 2))); do
		rm -f ${matches[$oldpkg]} && pkgremoved=1

[[ $pkgremoved -ne 1 ]] && echo "All clear, nothing to clean."

# vim:set ts=4 sw=4 noet:

Nicely highlighted here:

It removes all but the latest one for every package found in the current directory. It also checks for and removes older package formats for eg. those in .gz instead of .xz. Caveats apply (read through the code), and it’s also not optimised for speed. For instance, getting the name of the package via a functon is really expensive. Sort order may be a problem if your locale is not a form of English, but I’m not sure. Just test it out in a copy of the directory you want manipulated.