Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bin/xbps-alternatives: add repository mode to list repo alternatives #340

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 <mail@duncano.de>.
* 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
Loading