How to Keep Archlinux Up to Date
Archlinux has been my linux distribution of choice for many years now. It is my favourite development environment; I like its simplicity, but more specifically, I enjoy having the latest version of the programming languages installed to test new features out.
Although the rolling-release model allows frequent software updates and security fixes, it requires nevertheless regular maintenance that can sometimes feel burdensome. To be able to upgrade the system regularly and quickly, I wanted to make the process as straightforward as possible. With a couple of bash scripts, I automated the most common tasks and facilitated the system maintenance.
Since there are only a few tutorials out there discussing how to maintain the system, I thought it would be interesting to share my experience. This article is not about providing an out-of-the-box solution, but rather, about sharing a simple methodology for maintaining a desktop environment.
Note: If you are not familiar with this linux distribution, pacman is the package manager and AUR is the Arch User Repository which contains packages maintained by the community.
Updating the list of mirrors
Pacman uses a list of mirrors to know which servers packages can be downloaded from. I could use the default list, but I prefer customizing it to fit my needs. I use the Pacman Mirrorlist Generator which is an HTTP endpoint that can be called to get a list of servers. I only run this script a couple of times a year or whenever a server returns an HTTP error.
main() {
# Ask for user confirmation
printf "Do you want to update the mirror list? [Y/n]: "
read -r update_mirrors
# The default answer is yes
[[ -z "$update_mirrors" ]] && update_mirrors=y
if [[ "$update_mirrors" = y ]]; then
info "Updating mirror list"
# We keep a copy of the previous list in case something bad happens
local new_file_path=/etc/pacman.d/mirrorlist
local old_file_path=/etc/pacman.d/mirrorlist.pacold
msg "Moving current mirror list to \\x1b[33m${old_file_path}\\x1b[39m..."
sudo mv "$new_file_path" "$old_file_path"
# We use curl to call the endpoint with the following parameters:
# - country: France & Germany
# - protocol: https
# - ip_version: IPv4 & IPv6
# - use_mirror_status: is the server on?
msg "Downloading custom mirror list..."
sudo curl -v "https://www.archlinux.org/mirrorlist/?country=FR&country=DE&protocol=https&ip_version=4&ip_version=6&use_mirror_status=on" -o "$new_file_path"
# The servers list is commented out by default
msg "Uncommenting servers..."
sudo sed -i 's/^#Server/Server/' "$new_file_path"
# We set the correct owner and permissions
msg "Changing file's owner and permissions..."
sudo chown root.root "$new_file_path"
sudo chmod 0644 "$new_file_path"
# Do we want to delete the previous files?
printf "Do you want to delete the previous mirror list? [y/N]: "
read -r delete_prev_list
# If the user's answer is y and the file exists
if [[ "$delete_prev_list" = y && -f "${old_file_path}" ]]; then
sudo rm "${old_file_path}"
else
info "The previous mirror list was not deleted."
fi
fi
}
main
Upgrading official packages
As recommended in the wiki, I always run a full upgrade of the system. Depending on my needs, I upgrade the system about once a week to keep the update small and quick. Usually, I take a look at the latest news on the arch website beforehand to check whether the upgrade requires any manual interventions; I also run pacdiff after each upgrade to update the configuration files when it is necessary.
update_arch_packages() {
info "Updating Arch packages..."
# There might be a manual intervention
# so let's check the latest news
printf "Shall we check the Archlinux news? [Y/n]: "
read -r check_news
# The default answer is yes
[[ -z "$check_news" ]] && check_news=y
if [[ "$check_news" = y ]]; then
# Open the website in the default browser
xdg-open https://www.archlinux.org
fi
# Start a full upgrade
sudo pacman -Syu
printf "Do you need to run pacdiff? [y/N]: "
read -r run_pacdiff
if [[ "$run_pacdiff" = y ]]; then
# Run pacdiff to fix conflicted files if needed
sudo pacdiff
fi
}
Upgrading AUR packages
The Archlinux team provides a dedicated repository called the Arch User Repository where the community can upload non-official packages. Being not part of the official release, those packages are not updated during a system upgrade so they must be maintained separately. There are a few helpers available out there but I find it simpler to install and upgrade them manually.
I always clone the source of those packages in the same directory, for instance ~/my-aur-packages
. To perform an upgrade, I simply check whether the remote repository has been updated, pull the latest changes, and rebuild the package. Using makepkg, we can build the package as well as resolve its dependencies.
update_aur_packages() {
# $AUR_PKG is the place where I clone AUR packages,
# for instance in my home directory ~/my-aur-packages
info "Updating AUR packages..."
msg "Working directory \\x1b[33m${AUR_PKG}\\x1b[39m"
# Get the list of directories
local repositories=$(find "$AUR_PKG" -maxdepth 1 -type d ! -path "$AUR_PKG")
# Iterate over the list to update each package
for repository in ${repositories[*]}; do
update_aur_package "$repository"
done
}
update_aur_package() {
# The first argument is the directory path
local path="${1}"
# Get the directory name which is also the package name in this case
local dirname=$(basename "$path")
msg "Updating \\x1b[33m${dirname}\\x1b[39m..."
# Move into the directory
cd "$path" || error "Could not enter directory '$path'"
# If it's a git repository
if [[ -d .git ]]; then
# Fetch remote repository updates
git remote update
# Get the local and remote commit ID
local local_id=$(git rev-parse master)
local remote_id=$(git rev-parse origin/master)
# If the local commit ID and the remote commit ID don't match,
if [[ "$local_id" != "$remote_id" ]]; then
# We pull the latest changes...
msg "Pulling latest changes..."
git pull
# ...and rebuild the package with the following options:
# syncdeps: automatically resolves and installs any dependencies
# install: install the package
# rmdeps: removes build-time dependencies after the build
# clean: cleans up temporary build files after the build
msg "Building package..."
makepkg --syncdeps --install --rmdeps --clean
else
msg "\\x1b[33m${dirname}\\x1b[39m is up-to-date"
fi
else
warning "\\x1b[33m${dirname}\\x1b[39m is not a git repository. Skipping."
fi
}
Removing orphaned packages
Constantly rebuilding AUR packages might leave orphaned packages in the system. There is a neat trick to clean them up. I run the following function to look up orphans and remove them right after upgrading AUR packages.
check_orphans() {
info "Looking up orphans..."
local orphans=()
# Get the list of orphans
IFS=" " read -r -a orphans <<<"$(sudo pacman -Qtdq)"
if [[ ${#orphans[@]} -eq 0 ]]; then
msg "No orphans found"
else
printf "The following orphaned packages have been found: "
echo -e "${orphans[@]}"
printf "Do you want to remove them? [y/N]: "
read -r remove_pkgs
if [[ "$remove_pkgs" = y ]]; then
# Remove orphaned packages
sudo pacman -Rns "${orphans[@]}"
fi
fi
}
Cleaning up the cache
Pacman keeps all versions of a package in its cache, which is really handy if you need to downgrade a package; however, the cache can get pretty big over time so we need to clean it up every once in a while.
The script paccache helps us do exactly that. We can specify how many versions we want to keep in the cache. I only keep the current and the previous version just in case I need to downgrade a package.
clean_cache() {
local keep=2
# We first run a dry run of paccache
# to check where there are any candidates for removal
info "Looking up unnecessary packages in cache..."
sudo paccache -dk "$keep"
printf "Do you want to clean up the cache (keeping %s last version(s))? [y/N]: " $keep
read -r clean_cache
if [[ "$clean_cache" = y ]]; then
# Remove the old packages,
# we only keep the last 2 versions of each package
sudo paccache -rk "$keep"
fi
}
Conclusion
Archlinux certainly requires a bit of maintenance, however, I still have the feeling that it is the most stable operating system I have ever used. I have followed this method for years now and I have never had any weird dependency issues. Moreover, besides the download time, it only takes a few minutes to perform a full upgrade of the system. If you are interested and want to find out a bit more, you can find a complete version of the scripts to update the list of mirrors and to upgrade the system in my dotfiles
repository.