Script to set/unset "automatic" status in PKGNG database

John Nielsen lists at
Thu Aug 30 21:19:49 UTC 2012

I today noticed the "pkg autoremove" command for the first time, which does much the same thing as pkg_cutleaves but relies on the "automatic" flag in the pkgng database rather than user input to determine which "leaf" ports can be removed. Unfortunately, the pkg2ng utility has no way of knowing which old-style packages it converts were installed automatically as dependencies, so they are all marked as non-automatic (i.e. user-requested). In my case, this was not true for the majority of installed ports. Since I really like this functionality, I decided to update my local package database to match my preferences.

Having succeeded, I decided a tool to make doing so easy could well benefit others (as well as my future self). (Plus I wanted an excuse to play with dialog(1) and "pkg query" a bit.) So here's the result. I'm not too attached to the name. It shouldn't eat your package database or steal your lunch money, but I'm not responsible if it does. Other than that, feedback is welcome.

-------------- next part --------------

# Copyright (c) 2012 John Nielsen <john at>

# This script presents a checklist of all PKGNG packages registered on
# the system, showing for each whether or not it is marked as "automatic"
# (i.e. not explicitly requested by the user). Any changes are recorded
# in the PKGNG database. I wrote it to make "pkg autoremove" useful
# following a pkg2ng migration, but other uses are conceivable.

# The PKGNG database file to use

# Terminal geometry
sz=`stty size`
rows=`echo ${sz} | cut -d ' ' -f 1`
cols=`echo ${sz} | cut -d ' ' -f 2`
drows=$(( ${rows} - 3 ))
dcols=$(( ${cols} - 6 ))

# Dialog results are stored here
tmpfile=`mktemp -t set_pkg_auto`

# We always want the same style checklist
export DIALOGOPTS="--extra-button --extra-label \"Select All\" --cancel-label \"Deselect All\" --help-button --help-label Exit --separator ,"

# Exit with an error message
die() {
	rm -f ${tmpfile}
	echo "${1}"
	exit 1

# Don't leave tmpfile behind even if we are killed/interrupted
trap "die \"Interrupt received.\"" 2 15

# Run dialog to present the checklist and save the results in tmpfile
run_dialog() {
	dialog --checklist "Select packages to consider for auto-removal" ${drows} ${dcols} ${drows} $* 2>${tmpfile}
	return $?

# Show the current status from the package database in the checklist
select_current() {
	run_dialog `pkg query '%n %o %a' | sed -e 's/1$/on/g' -e 's/0$/off/g'`
	return $?

# Select all packages in the checklist
select_all() {
	run_dialog `pkg query '%n %o' | sed -e 's/$/ on/g'`
	return $?

# De-select all packages in the checklist
select_none() {
	run_dialog `pkg query '%n %o' | sed -e 's/$/ off/g'`
	return $?

# Update the package database to match selections in the specified file
do_update() {
	autopkgs=`sed -e "s/^,//g" -e "s/\"/'/g" ${1}`
	sqlite3 ${DB} "update packages set automatic=1 where name in (${autopkgs});" \
		|| die "SQlite error."
	sqlite3 ${DB} "update packages set automatic=0 where name not in (${autopkgs});" \
		|| die "SQlite error."

# Run select_current for the first checklist

# Show the checklist until "OK" or "Exit" is selected
while : ; do
	case $? in
		0) # OK, continue with updates
		3) # Extra (Select all), show the checklist again
		1) # Cancel (Deselect all), show the checklist again
		*) # 4-Help (Exit) or ESC or error, exit.
			die "No changes made."

# If we got this far then tmpfile has a list of 'automatic' packages
do_update ${tmpfile}

# Clean up
rm -f ${tmpfile}
echo "Updated successfully."
-------------- next part --------------

More information about the freebsd-ports mailing list