-
Notifications
You must be signed in to change notification settings - Fork 125
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
bin/xbps-alternatives: add repository mode to list repo alternatives
- Loading branch information
Showing
2 changed files
with
174 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
|
@@ -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); | ||
} | ||
|
||
|
@@ -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++) { | ||
|
@@ -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); | ||
} | ||
|
@@ -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' }, | ||
|
@@ -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; | ||
|
||
|
@@ -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; | ||
|
@@ -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); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters