diff --git a/bin/xbps-checkvers/main.c b/bin/xbps-checkvers/main.c
index 121114fc..f9ae4866 100644
--- a/bin/xbps-checkvers/main.c
+++ b/bin/xbps-checkvers/main.c
@@ -50,10 +50,11 @@ typedef struct _rcv_t {
char *xbps_conf, *rootdir, *distdir, *buf, *ptr, *cachefile;
size_t bufsz, len;
uint8_t have_vars;
- bool show_all, manual, installed;
+ bool show_all, manual, installed, removed, show_removed;
xbps_dictionary_t env;
xbps_dictionary_t pkgd;
xbps_dictionary_t cache;
+ xbps_dictionary_t templates;
struct xbps_handle xhp;
} rcv_t;
@@ -82,6 +83,7 @@ show_usage(const char *prog)
" -D --distdir
Set (or override) the path to void-packages\n"
" (defaults to ~/void-packages).\n"
" -d --debug Enable debug output to stderr.\n"
+" -e --removed List packages present in repos, but not in distdir.\n"
" -f --format Output format.\n"
" -I --installed Check for outdated packages in rootdir, rather\n"
" than in the XBPS repositories.\n"
@@ -116,6 +118,7 @@ rcv_init(rcv_t *rcv, const char *prog)
}
if (xbps_init(&rcv->xhp) != 0)
abort();
+ rcv->templates = xbps_dictionary_create();
}
static void
@@ -140,6 +143,8 @@ rcv_end(rcv_t *rcv)
free(rcv->distdir);
free(rcv->cachefile);
+ xbps_object_release(rcv->templates);
+ rcv->templates = NULL;
}
static bool
@@ -273,7 +278,7 @@ rcv_sh_substitute(rcv_t *rcv, const char *str, size_t len)
xbps_string_append_cstring(out, b);
}
}
-
+
ret = xbps_string_cstring(out);
xbps_object_release(out);
return ret;
@@ -558,7 +563,11 @@ rcv_check_version(rcv_t *rcv)
reverts = NULL;
xbps_dictionary_get_cstring_nocopy(rcv->env, "reverts", &reverts);
- sz = snprintf(srcver, sizeof srcver, "%s_%s", version, revision);
+ if (rcv->removed)
+ sz = snprintf(srcver, sizeof srcver, "?");
+ else
+ sz = snprintf(srcver, sizeof srcver, "%s_%s", version, revision);
+
if (sz < 0 || (size_t)sz >= sizeof srcver)
exit(EXIT_FAILURE);
@@ -584,6 +593,10 @@ rcv_check_version(rcv_t *rcv)
;
else if (rcv->show_all)
;
+ else if (rcv->show_removed && rcv->removed)
+ ;
+ else if (rcv->show_removed && !rcv->removed)
+ return 0;
else if (repover && (xbps_cmpver(repover, srcver) < 0 ||
(reverts && check_reverts(repover, reverts))))
;
@@ -620,6 +633,10 @@ rcv_process_dir(rcv_t *rcv, rcv_proc_func process)
continue;
if ((lstat(result->d_name, &st)) != 0)
goto error;
+
+ if (rcv->show_removed)
+ xbps_dictionary_set_bool(rcv->templates, result->d_name, true);
+
if (S_ISLNK(st.st_mode) != 0)
continue;
@@ -635,16 +652,63 @@ error:
exit(1);
}
+static int
+template_removed_cb(struct xbps_handle *xhp UNUSED,
+ xbps_object_t obj UNUSED,
+ const char *key,
+ void *arg,
+ bool *done UNUSED)
+{
+ char *pkgname;
+ char *last_dash;
+ bool dummy_bool = false;
+ rcv_t *rcv = arg;
+
+ last_dash = strrchr(key, '-');
+ if (last_dash && (strcmp(last_dash, "-32bit") == 0 || strcmp(last_dash, "-dbg") == 0)) {
+ pkgname = strndup(key, last_dash - key);
+ } else {
+ pkgname = strdup(key);
+ }
+ if (!xbps_dictionary_get_bool(rcv->templates, pkgname, &dummy_bool)) {
+ rcv->removed = true;
+ rcv->env = xbps_dictionary_create();
+ xbps_dictionary_set_cstring_nocopy(rcv->env, "pkgname", key);
+ xbps_dictionary_set_cstring_nocopy(rcv->env, "version", "-");
+ xbps_dictionary_set_cstring_nocopy(rcv->env, "revision", "-");
+ rcv->have_vars = GOT_PKGNAME_VAR | GOT_VERSION_VAR | GOT_REVISION_VAR;
+ rcv->fname = key;
+ rcv_check_version(rcv);
+ rcv->removed = false;
+ xbps_object_release(rcv->env);
+ rcv->env = NULL;
+ }
+ free(pkgname);
+ return 0;
+}
+
+static int
+repo_templates_removed_cb(struct xbps_repo *repo, void *arg, bool *done UNUSED)
+{
+ xbps_array_t allkeys;
+
+ allkeys = xbps_dictionary_all_keys(repo->idx);
+ xbps_array_foreach_cb(repo->xhp, allkeys, repo->idx, template_removed_cb, arg);
+ xbps_object_release(allkeys);
+ return 0;
+}
+
int
main(int argc, char **argv)
{
int i, c;
rcv_t rcv;
- const char *prog = argv[0], *sopts = "hC:D:df:iImR:r:sV";
+ const char *prog = argv[0], *sopts = "hC:D:def:iImR:r:sV";
const struct option lopts[] = {
{ "help", no_argument, NULL, 'h' },
{ "config", required_argument, NULL, 'C' },
{ "distdir", required_argument, NULL, 'D' },
+ { "removed", no_argument, NULL, 'e' },
{ "debug", no_argument, NULL, 'd' },
{ "format", required_argument, NULL, 'f' },
{ "installed", no_argument, NULL, 'I' },
@@ -674,6 +738,9 @@ main(int argc, char **argv)
case 'd':
rcv.xhp.flags |= XBPS_FLAG_DEBUG;
break;
+ case 'e':
+ rcv.show_removed = true;
+ break;
case 'f':
rcv.format = optarg;
break;
@@ -734,6 +801,14 @@ main(int argc, char **argv)
if (!rcv.manual)
rcv_process_dir(&rcv, rcv_process_file);
+ if (rcv.show_removed) {
+ if (rcv.installed) {
+ xbps_pkgdb_foreach_cb(&rcv.xhp, template_removed_cb, &rcv);
+ } else {
+ xbps_rpool_foreach(&rcv.xhp, repo_templates_removed_cb, &rcv);
+ }
+ }
+
rcv.manual = true;
for (i = 0; i < argc; i++) {
char tmp[PATH_MAX] = {0}, *tmpl, *p;
diff --git a/bin/xbps-checkvers/xbps-checkvers.1 b/bin/xbps-checkvers/xbps-checkvers.1
index 2be0c77e..c2a994cb 100644
--- a/bin/xbps-checkvers/xbps-checkvers.1
+++ b/bin/xbps-checkvers/xbps-checkvers.1
@@ -32,6 +32,9 @@ If the first character is not '/' then it's a relative path of
.It Fl D, Fl -distdir Ar dir
Specifies a full path to the void-packages repository. By default set to
.Nm ~/void-packages .
+.It Fl e, Fl -removed
+List packages present in repos, but not in distdir.
+Srcver is a dash for them.
.It Fl d, Fl -debug
Enables extra debugging shown to stderr.
.It Fl f, Fl -format Ar format
diff --git a/tests/xbps/xbps-checkvers/checkvers_test.sh b/tests/xbps/xbps-checkvers/checkvers_test.sh
index 0d45ff9c..27c36395 100755
--- a/tests/xbps/xbps-checkvers/checkvers_test.sh
+++ b/tests/xbps/xbps-checkvers/checkvers_test.sh
@@ -497,6 +497,101 @@ EOF
atf_check_equal "$out" "A ? 1.0_1 A ?"
}
+atf_test_case removed
+
+removed_head() {
+ atf_set "descr" "xbps-checkvers(1): test removed"
+}
+
+removed_body() {
+ mkdir -p some_repo
+ for pkg in same updated removed
+ do
+ mkdir -p void-packages/srcpkgs/$pkg
+ cat > void-packages/srcpkgs/$pkg/template < void-packages/srcpkgs/$pkg/template < expected < out
+ atf_check_equal $? 0
+ sort < out > out.sorted
+ atf_check_equal $? 0
+ atf_check_equal "$(tr '\n' ' ' < out.sorted)" "$(tr '\n' ' ' < expected)"
+}
+
atf_init_test_cases() {
atf_add_test_case srcpkg_newer
atf_add_test_case srcpkg_newer_with_refs
@@ -515,4 +610,6 @@ atf_init_test_cases() {
atf_add_test_case reverts_many
atf_add_test_case manual_mode
atf_add_test_case subpkg
+ atf_add_test_case removed
+ atf_add_test_case removed_subpkgs
}