Skip to content

Commit

Permalink
bin/xbps-alternatives: add repository mode to list repo alternatives
Browse files Browse the repository at this point in the history
  • Loading branch information
Duncaen committed Aug 31, 2023
1 parent f68893e commit 281e1b7
Show file tree
Hide file tree
Showing 2 changed files with 174 additions and 32 deletions.
189 changes: 158 additions & 31 deletions bin/xbps-alternatives/main.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2015 Juan Romero Pardines.
* Copyright (c) 2020 Duncan Overbruck <[email protected]>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -41,16 +42,22 @@ usage(bool fail)
fprintf(stdout,
"Usage: xbps-alternatives [OPTIONS] MODE\n\n"
"OPTIONS\n"
" -C --config <dir> Path to confdir (xbps.d)\n"
" -d --debug Debug mode shown to stderr\n"
" -g --group <name> Group of alternatives to match\n"
" -h --help Show usage\n"
" -r --rootdir <dir> Full path to rootdir\n"
" -v --verbose Verbose messages\n"
" -V --version Show XBPS version\n"
" -C --config <dir> Path to confdir (xbps.d)\n"
" -d --debug Debug mode shown to stderr\n"
" -g --group <name> Group of alternatives to match\n"
" -h --help Show usage\n"
" -i, --ignore-conf-repos Ignore repositories defined in xbps.d\n"
" -R, --repository Enable repository mode. This mode explicitly\n"
" looks for packages in repositories\n"
" --repository=<url> Enable repository mode and add repository\n"
" to the top of the list. This option can be\n"
" specified multiple times\n"
" -r --rootdir <dir> Full path to rootdir\n"
" -v --verbose Verbose messages\n"
" -V --version Show XBPS version\n"
"MODE\n"
" -l --list [PKG] List all alternatives or from PKG\n"
" -s --set PKG Set alternatives for PKG\n");
" -l --list [PKG] List all alternatives or from PKG\n"
" -s --set PKG Set alternatives for PKG\n");
exit(fail ? EXIT_FAILURE : EXIT_SUCCESS);
}

Expand Down Expand Up @@ -108,26 +115,10 @@ list_pkg_alternatives(xbps_dictionary_t pkgd, const char *group, bool print_key)
}

static int
list_alternatives(struct xbps_handle *xhp, const char *pkgname, const char *grp)
print_alternatives(struct xbps_handle *xhp, xbps_dictionary_t alternatives, const char *grp, bool repo_mode)
{
xbps_dictionary_t alternatives, pkgd;
xbps_array_t allkeys;

(void)xbps_pkgdb_get_pkg(xhp, "foo");

if (pkgname) {
/* list alternatives for pkgname */
if ((pkgd = xbps_pkgdb_get_pkg(xhp, pkgname)) == NULL)
return ENOENT;

list_pkg_alternatives(pkgd, NULL, true);
return 0;
}
assert(xhp->pkgdb);

alternatives = xbps_dictionary_get(xhp->pkgdb, "_XBPS_ALTERNATIVES_");
if (alternatives == NULL)
return ENOENT;
xbps_dictionary_t pkgd;

allkeys = xbps_dictionary_all_keys(alternatives);
for (unsigned int i = 0; i < xbps_array_count(allkeys); i++) {
Expand All @@ -147,8 +138,10 @@ list_alternatives(struct xbps_handle *xhp, const char *pkgname, const char *grp)
const char *str = NULL;

xbps_array_get_cstring_nocopy(array, x, &str);
printf(" - %s%s\n", str, x == 0 ? " (current)" : "");
printf(" - %s%s\n", str, !repo_mode && x == 0 ? " (current)" : "");
pkgd = xbps_pkgdb_get_pkg(xhp, str);
if (pkgd == NULL && repo_mode)
pkgd = xbps_rpool_get_pkg(xhp, str);
assert(pkgd);
list_pkg_alternatives(pkgd, keyname, false);
}
Expand All @@ -158,17 +151,123 @@ list_alternatives(struct xbps_handle *xhp, const char *pkgname, const char *grp)
return 0;
}

static int
list_alternatives(struct xbps_handle *xhp, const char *pkgname, const char *grp)
{
xbps_dictionary_t alternatives, pkgd;

(void)xbps_pkgdb_get_pkg(xhp, "foo");

if (pkgname) {
/* list alternatives for pkgname */
if ((pkgd = xbps_pkgdb_get_pkg(xhp, pkgname)) == NULL)
return ENOENT;

list_pkg_alternatives(pkgd, NULL, true);
return 0;
}
assert(xhp->pkgdb);

alternatives = xbps_dictionary_get(xhp->pkgdb, "_XBPS_ALTERNATIVES_");
if (alternatives == NULL)
return ENOENT;

return print_alternatives(xhp, alternatives, grp, false);
}

struct search_data {
const char *group;
xbps_dictionary_t result;
};

static int
search_array_cb(struct xbps_handle *xhp UNUSED,
xbps_object_t obj,
const char *key UNUSED,
void *arg,
bool *done UNUSED)
{
xbps_object_iterator_t iter;
xbps_dictionary_t alternatives;
struct search_data *sd = arg;
const char *pkgver = NULL;

if (!xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver))
return 0;

alternatives = xbps_dictionary_get(obj, "alternatives");
if (alternatives == NULL)
return 0;

iter = xbps_dictionary_iterator(alternatives);
assert(iter);

/*
* Register all provided groups in the result dictionary.
*/
while ((obj = xbps_object_iterator_next(iter))) {
xbps_array_t grouparr;
const char *group = xbps_dictionary_keysym_cstring_nocopy(obj);
bool alloc = false;

/* skip the group if we search for a specific one */
if (sd->group != NULL && strcmp(sd->group, group) != 0)
continue;

grouparr = xbps_dictionary_get(sd->result, group);
if (grouparr == NULL) {
if ((grouparr = xbps_array_create()) == NULL) {
xbps_error_printf("Failed to create array: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
alloc = true;
xbps_dictionary_set(sd->result, group, grouparr);
} else {
/*
* check if pkgver is already in the group array,
* this only happens if multiple repositories provide
* the same pkgver.
*/
if (xbps_match_string_in_array(grouparr, pkgver))
continue;
}
xbps_array_add_cstring_nocopy(grouparr, pkgver);

if (alloc)
xbps_object_release(grouparr);
}

return 0;
}

static int
search_repo_cb(struct xbps_repo *repo, void *arg, bool *done UNUSED)
{
xbps_array_t allkeys;
int rv;

if (repo->idx == NULL)
return 0;

allkeys = xbps_dictionary_all_keys(repo->idx);
rv = xbps_array_foreach_cb(repo->xhp, allkeys, repo->idx, search_array_cb, arg);
xbps_object_release(allkeys);
return rv;
}

int
main(int argc, char **argv)
{
const char *shortopts = "C:dg:hls:r:Vv";
const char *shortopts = "C:dg:hils:Rr:Vv";
const struct option longopts[] = {
{ "config", required_argument, NULL, 'C' },
{ "debug", no_argument, NULL, 'd' },
{ "group", required_argument, NULL, 'g' },
{ "help", no_argument, NULL, 'h' },
{ "ignore-conf-repos", no_argument, NULL, 'i' },
{ "list", no_argument, NULL, 'l' },
{ "set", required_argument, NULL, 's' },
{ "repository", optional_argument, NULL, 'R' },
{ "rootdir", required_argument, NULL, 'r' },
{ "verbose", no_argument, NULL, 'v' },
{ "version", no_argument, NULL, 'V' },
Expand All @@ -177,7 +276,7 @@ main(int argc, char **argv)
struct xbps_handle xh;
const char *confdir, *rootdir, *group, *pkg;
int c, rv, flags = 0;
bool list_mode = false, set_mode = false;
bool list_mode = false, set_mode = false, repo_mode = false;

confdir = rootdir = group = pkg = NULL;

Expand All @@ -195,13 +294,22 @@ main(int argc, char **argv)
case 'h':
usage(false);
/* NOTREACHED */
case 'i':
flags |= XBPS_FLAG_IGNORE_CONF_REPOS;
break;
case 'l':
list_mode = true;
break;
case 's':
set_mode = true;
pkg = optarg;
break;
case 'R':
if (optarg != NULL) {
xbps_repo_store(&xh, optarg);
}
repo_mode = true;
break;
case 'r':
rootdir = optarg;
break;
Expand Down Expand Up @@ -250,7 +358,26 @@ main(int argc, char **argv)
rv = xbps_pkgdb_update(&xh, true, false);
} else if (list_mode) {
/* list alternative groups */
rv = list_alternatives(&xh, pkg, group);
if (repo_mode) {
struct search_data sd = { 0 };
if ((sd.result = xbps_dictionary_create()) == NULL) {
xbps_error_printf("Failed to create dictionary: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
sd.group = group;
rv = xbps_rpool_foreach(&xh, search_repo_cb, &sd);
if (rv != 0 && rv != ENOTSUP) {
fprintf(stderr, "Failed to initialize rpool: %s\n",
strerror(rv));
exit(EXIT_FAILURE);
}
if (xbps_dictionary_count(sd.result) > 0)
print_alternatives(&xh, sd.result, group, true);
else
exit(EXIT_FAILURE);
} else {
rv = list_alternatives(&xh, pkg, group);
}
}

xbps_end(&xh);
Expand Down
17 changes: 16 additions & 1 deletion bin/xbps-alternatives/xbps-alternatives.1
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.Dd Feb 9, 2023
.Dd Aug 31, 2023
.Dt XBPS-ALTERNATIVES 1
.Os
.Sh NAME
Expand Down Expand Up @@ -34,6 +34,21 @@ Alternative group name to match. To be used with the
mode.
.It Fl h, Fl -help
Show the help message.
.It Fl i, Fl -ignore-conf-repos
Ignore repositories defined in configuration files.
Only repositories specified in the command line via
.Ar --repository
will be used.
.It Fl R
Enable repository mode when listing alternatives.
This mode explicitly looks for all alternatives available
in repositories rather than looking for installed alternatives.
.It Fl -repository Ar url
Appends the specified repository to the top of the list.
The
.Ar url
argument expects a URL to the repository for remote repositories or
a path for local repositories.
.It Fl r, Fl -rootdir Ar dir
Specifies a full path for the target root directory.
.It Fl v, Fl -verbose
Expand Down

0 comments on commit 281e1b7

Please sign in to comment.