SPS · log · files · refs · tags · releases · people · languages · GitHub · commit
1b76f98
pkstat: add --count
Parents
Stat
README.md | 3 +- bin/pkstat | 14 +++++++ man/pkstat.1 | 7 ++++ tests/test_pkstat_count.sh | 94 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 117 insertions(+), 1 deletion(-)
Diff
diff --git a/README.md b/README.md
index 13c762c..5b09b38 100644
--- a/README.md
+++ b/README.md
@@ -41,7 +41,8 @@ SPS is a set of tools rather than one large front end:
- `mkpkg` builds a binary package from a recipe.
- `pkin` installs or upgrades one binary package.
- `pkdel` removes one installed package.
-- `pkstat` reads the installed package database.
+- `pkstat` reads the installed package database (`pkstat --count` prints
+ the number of installed packages).
- `pkcheck` checks installed files and database consistency.
- `pkmark` changes whether an installed package is explicit or dependency-only.
- `setup` is the SPS Linux (Splux) dialog(1) installer (Slackware/FreeBSD
diff --git a/bin/pkstat b/bin/pkstat
index 5f74a1e..9f0c781 100755
--- a/bin/pkstat
+++ b/bin/pkstat
@@ -24,6 +24,7 @@ usage: pkstat [PACKAGE]
pkstat --explicit
pkstat --orphans
pkstat --size PACKAGE
+ pkstat --count
EOF
}
@@ -194,6 +195,19 @@ case $sps_command in
}
' "$@" | LC_ALL=C sort
;;
+ --count)
+ [ "$#" -eq 1 ] || { sps_usage >&2; exit 2; }
+ sps_count=0
+ if [ -d "$SPS_DB/installed" ] && [ ! -L "$SPS_DB/installed" ]; then
+ for sps_record in "$SPS_DB/installed"/*; do
+ [ -d "$sps_record" ] || continue
+ [ ! -L "$sps_record" ] || continue
+ [ -f "$sps_record/meta" ] && [ ! -L "$sps_record/meta" ] || continue
+ sps_count=$((sps_count + 1))
+ done
+ fi
+ printf '%s\n' "$sps_count"
+ ;;
--size)
[ "$#" -eq 2 ] || { sps_usage >&2; exit 2; }
sps_record_for "$2"
diff --git a/man/pkstat.1 b/man/pkstat.1
index 3c2968f..8ad21a5 100644
--- a/man/pkstat.1
+++ b/man/pkstat.1
@@ -9,6 +9,7 @@ pkstat --owns PATH
pkstat --explicit
pkstat --orphans
pkstat --size PACKAGE
+pkstat --count
.fi
.SH DESCRIPTION
.B pkstat
@@ -32,6 +33,12 @@ entire abandoned dependency chains are reported.
.TP
.BI --size " package"
Print the current byte size of regular files in the package manifest.
+.TP
+.B --count
+Print the number of installed packages, one integer and a newline. Counts
+directories under the installed database that contain a
+.B meta
+file. Missing databases print 0.
.SH EXIT STATUS
Returns 0 on success, 2 for usage, 3 for missing package/owner, 8 for
unreadable filesystem state, and 11 for malformed/unavailable database state.
diff --git a/tests/test_pkstat_count.sh b/tests/test_pkstat_count.sh
new file mode 100644
index 0000000..c0e08f0
--- /dev/null
+++ b/tests/test_pkstat_count.sh
@@ -0,0 +1,94 @@
+#!/bin/sh
+# pkstat --count: integer of installed records with a regular meta file.
+
+set -eu
+
+case $0 in */*) test_dir=${0%/*} ;; *) test_dir=. ;; esac
+project_dir=$(CDPATH= cd "$test_dir/.." 2>/dev/null && pwd) || exit 1
+
+fail()
+{
+ printf 'test_pkstat_count: %s\n' "$*" >&2
+ exit 1
+}
+
+run_sps()
+{
+ SPS_ROOT=$root \
+ SPS_DB=$db \
+ SPS_CACHE=$cache \
+ SPS_BUILD=$build \
+ SPS_CONFIG=/dev/null \
+ SPS_REPOS_CONFIG=/dev/null \
+ SPS_LIBDIR=$project_dir/lib \
+ "$@"
+}
+
+install_named()
+{
+ package_name=$1
+ stage=$tmp/stage-$package_name
+ rm -rf "$stage"
+ mkdir -p "$stage/.SPS" "$stage/usr/share/$package_name"
+ printf '%s\n' "$package_name" >"$stage/usr/share/$package_name/id"
+ {
+ printf 'format\t1\n'
+ printf 'name\t%s\n' "$package_name"
+ printf 'version\t1.0\n'
+ printf 'release\t1\n'
+ printf 'arch\tany\n'
+ printf 'description\tcount fixture %s\n' "$package_name"
+ } >"$stage/.SPS/meta"
+ : >"$stage/.SPS/files.unsorted"
+ (CDPATH= cd "$stage" && find . ! -name . ! -path './.SPS' ! -path './.SPS/*' -print) |
+ sed 's#^\./##' | while IFS= read -r package_entry; do
+ if [ -d "$stage/$package_entry" ] && [ ! -L "$stage/$package_entry" ]; then
+ printf '%s/\n' "$package_entry"
+ else
+ printf '%s\n' "$package_entry"
+ fi
+ done >"$stage/.SPS/files.unsorted"
+ LC_ALL=C sort "$stage/.SPS/files.unsorted" >"$stage/.SPS/files"
+ rm -f "$stage/.SPS/files.unsorted"
+ : >"$stage/.SPS/hashes"
+ printf 'sha256\t%s\t%s\n' \
+ "$(sha256sum "$stage/usr/share/$package_name/id" | awk '{ print $1 }')" \
+ "usr/share/$package_name/id" >>"$stage/.SPS/hashes"
+ tar -C "$stage" -cf "$tmp/$package_name.pkg.tar" .
+ run_sps "$project_dir/bin/pkin" --dependency "$tmp/$package_name.pkg.tar" \
+ >/dev/null
+}
+
+tmp=$(mktemp -d "${TMPDIR:-/tmp}/sps-test-pkstat-count.XXXXXX") || fail mktemp
+trap 'rm -rf "$tmp"' 0 HUP INT TERM
+root=$tmp/root
+db=$tmp/db
+cache=$tmp/cache
+build=$tmp/build
+mkdir -p "$root" "$cache" "$build"
+
+[ "$(run_sps "$project_dir/bin/pkstat" --count)" = 0 ] ||
+ fail 'empty database must print 0'
+
+install_named one
+[ "$(run_sps "$project_dir/bin/pkstat" --count)" = 1 ] ||
+ fail 'one installed package must print 1'
+
+install_named two
+install_named three
+[ "$(run_sps "$project_dir/bin/pkstat" --count)" = 3 ] ||
+ fail 'three installed packages must print 3'
+
+# Junk next to real records is not a package.
+printf 'not a record\n' >"$db/installed/readme.txt"
+mkdir -p "$db/installed/empty-dir"
+ln -s one "$db/installed/alias"
+ln -s /tmp "$db/installed/outside"
+[ "$(run_sps "$project_dir/bin/pkstat" --count)" = 3 ] ||
+ fail 'files, empty dirs, and symlinks must not count'
+
+run_sps "$project_dir/bin/pkstat" --count >/dev/null
+run_sps "$project_dir/bin/pkstat" --count | grep -qx '3' ||
+ fail 'count must be a single integer line'
+
+printf '%s\n' 'test_pkstat_count: ok'