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 }