11/*-
22 * Copyright (c) 2015 Juan Romero Pardines.
3+ * Copyright (c) 2020 Duncan Overbruck <[email protected] >. 34 * All rights reserved.
45 *
56 * Redistribution and use in source and binary forms, with or without
@@ -41,16 +42,22 @@ usage(bool fail)
4142 fprintf (stdout ,
4243 "Usage: xbps-alternatives [OPTIONS] MODE\n\n"
4344 "OPTIONS\n"
44- " -C --config <dir> Path to confdir (xbps.d)\n"
45- " -d --debug Debug mode shown to stderr\n"
46- " -g --group <name> Group of alternatives to match\n"
47- " -h --help Show usage\n"
48- " -r --rootdir <dir> Full path to rootdir\n"
49- " -v --verbose Verbose messages\n"
50- " -V --version Show XBPS version\n"
45+ " -C --config <dir> Path to confdir (xbps.d)\n"
46+ " -d --debug Debug mode shown to stderr\n"
47+ " -g --group <name> Group of alternatives to match\n"
48+ " -h --help Show usage\n"
49+ " -i, --ignore-conf-repos Ignore repositories defined in xbps.d\n"
50+ " -R, --repository Enable repository mode. This mode explicitly\n"
51+ " looks for packages in repositories\n"
52+ " --repository=<url> Enable repository mode and add repository\n"
53+ " to the top of the list. This option can be\n"
54+ " specified multiple times\n"
55+ " -r --rootdir <dir> Full path to rootdir\n"
56+ " -v --verbose Verbose messages\n"
57+ " -V --version Show XBPS version\n"
5158 "MODE\n"
52- " -l --list [PKG] List all alternatives or from PKG\n"
53- " -s --set PKG Set alternatives for PKG\n" );
59+ " -l --list [PKG] List all alternatives or from PKG\n"
60+ " -s --set PKG Set alternatives for PKG\n" );
5461 exit (fail ? EXIT_FAILURE : EXIT_SUCCESS );
5562}
5663
@@ -107,27 +114,11 @@ list_pkg_alternatives(xbps_dictionary_t pkgd, const char *group, bool print_key)
107114 xbps_object_release (allkeys );
108115}
109116
110- static int
111- list_alternatives (struct xbps_handle * xhp , const char * pkgname , const char * grp )
117+ static void
118+ print_alternatives (struct xbps_handle * xhp , xbps_dictionary_t alternatives , const char * grp , bool repo_mode )
112119{
113- xbps_dictionary_t alternatives , pkgd ;
114120 xbps_array_t allkeys ;
115-
116- (void )xbps_pkgdb_get_pkg (xhp , "foo" );
117-
118- if (pkgname ) {
119- /* list alternatives for pkgname */
120- if ((pkgd = xbps_pkgdb_get_pkg (xhp , pkgname )) == NULL )
121- return ENOENT ;
122-
123- list_pkg_alternatives (pkgd , NULL , true);
124- return 0 ;
125- }
126- assert (xhp -> pkgdb );
127-
128- alternatives = xbps_dictionary_get (xhp -> pkgdb , "_XBPS_ALTERNATIVES_" );
129- if (alternatives == NULL )
130- return ENOENT ;
121+ xbps_dictionary_t pkgd ;
131122
132123 allkeys = xbps_dictionary_all_keys (alternatives );
133124 for (unsigned int i = 0 ; i < xbps_array_count (allkeys ); i ++ ) {
@@ -147,28 +138,136 @@ list_alternatives(struct xbps_handle *xhp, const char *pkgname, const char *grp)
147138 const char * str = NULL ;
148139
149140 xbps_array_get_cstring_nocopy (array , x , & str );
150- printf (" - %s%s\n" , str , x == 0 ? " (current)" : "" );
141+ printf (" - %s%s\n" , str , ! repo_mode && x == 0 ? " (current)" : "" );
151142 pkgd = xbps_pkgdb_get_pkg (xhp , str );
143+ if (pkgd == NULL && repo_mode )
144+ pkgd = xbps_rpool_get_pkg (xhp , str );
152145 assert (pkgd );
153146 list_pkg_alternatives (pkgd , keyname , false);
154147 }
155148 }
156149 xbps_object_release (allkeys );
150+ }
157151
152+ static int
153+ list_alternatives (struct xbps_handle * xhp , const char * pkgname , const char * grp )
154+ {
155+ xbps_dictionary_t alternatives , pkgd ;
156+
157+ if (pkgname ) {
158+ /* list alternatives for pkgname */
159+ if ((pkgd = xbps_pkgdb_get_pkg (xhp , pkgname )) == NULL )
160+ return - ENOENT ;
161+
162+ list_pkg_alternatives (pkgd , NULL , true);
163+ return 0 ;
164+ } else {
165+ // XXX: initializing the pkgdb.
166+ (void )xbps_pkgdb_get_pkg (xhp , "foo" );
167+ }
168+ assert (xhp -> pkgdb );
169+
170+ alternatives = xbps_dictionary_get (xhp -> pkgdb , "_XBPS_ALTERNATIVES_" );
171+ if (alternatives == NULL )
172+ return - ENOENT ;
173+
174+ print_alternatives (xhp , alternatives , grp , false);
158175 return 0 ;
159176}
160177
178+ struct search_data {
179+ const char * group ;
180+ xbps_dictionary_t result ;
181+ };
182+
183+ static int
184+ search_array_cb (struct xbps_handle * xhp UNUSED ,
185+ xbps_object_t obj ,
186+ const char * key UNUSED ,
187+ void * arg ,
188+ bool * done UNUSED )
189+ {
190+ xbps_object_iterator_t iter ;
191+ xbps_dictionary_t alternatives ;
192+ struct search_data * sd = arg ;
193+ const char * pkgver = NULL ;
194+
195+ if (!xbps_dictionary_get_cstring_nocopy (obj , "pkgver" , & pkgver ))
196+ return 0 ;
197+
198+ alternatives = xbps_dictionary_get (obj , "alternatives" );
199+ if (alternatives == NULL )
200+ return 0 ;
201+
202+ iter = xbps_dictionary_iterator (alternatives );
203+ assert (iter );
204+
205+ /*
206+ * Register all provided groups in the result dictionary.
207+ */
208+ while ((obj = xbps_object_iterator_next (iter ))) {
209+ xbps_array_t grouparr ;
210+ const char * group = xbps_dictionary_keysym_cstring_nocopy (obj );
211+ bool alloc = false;
212+
213+ /* skip the group if we search for a specific one */
214+ if (sd -> group != NULL && strcmp (sd -> group , group ) != 0 )
215+ continue ;
216+
217+ grouparr = xbps_dictionary_get (sd -> result , group );
218+ if (grouparr == NULL ) {
219+ if ((grouparr = xbps_array_create ()) == NULL ) {
220+ xbps_error_printf ("Failed to create array: %s\n" , strerror (errno ));
221+ exit (EXIT_FAILURE );
222+ }
223+ alloc = true;
224+ xbps_dictionary_set (sd -> result , group , grouparr );
225+ } else {
226+ /*
227+ * check if pkgver is already in the group array,
228+ * this only happens if multiple repositories provide
229+ * the same pkgver.
230+ */
231+ if (xbps_match_string_in_array (grouparr , pkgver ))
232+ continue ;
233+ }
234+ xbps_array_add_cstring_nocopy (grouparr , pkgver );
235+
236+ if (alloc )
237+ xbps_object_release (grouparr );
238+ }
239+
240+ return 0 ;
241+ }
242+
243+ static int
244+ search_repo_cb (struct xbps_repo * repo , void * arg , bool * done UNUSED )
245+ {
246+ xbps_array_t allkeys ;
247+ int rv ;
248+
249+ if (repo -> idx == NULL )
250+ return 0 ;
251+
252+ allkeys = xbps_dictionary_all_keys (repo -> idx );
253+ rv = xbps_array_foreach_cb (repo -> xhp , allkeys , repo -> idx , search_array_cb , arg );
254+ xbps_object_release (allkeys );
255+ return rv ;
256+ }
257+
161258int
162259main (int argc , char * * argv )
163260{
164- const char * shortopts = "C:dg:hls:r :Vv" ;
261+ const char * shortopts = "C:dg:hils:Rr :Vv" ;
165262 const struct option longopts [] = {
166263 { "config" , required_argument , NULL , 'C' },
167264 { "debug" , no_argument , NULL , 'd' },
168265 { "group" , required_argument , NULL , 'g' },
169266 { "help" , no_argument , NULL , 'h' },
267+ { "ignore-conf-repos" , no_argument , NULL , 'i' },
170268 { "list" , no_argument , NULL , 'l' },
171269 { "set" , required_argument , NULL , 's' },
270+ { "repository" , optional_argument , NULL , 'R' },
172271 { "rootdir" , required_argument , NULL , 'r' },
173272 { "verbose" , no_argument , NULL , 'v' },
174273 { "version" , no_argument , NULL , 'V' },
@@ -177,7 +276,7 @@ main(int argc, char **argv)
177276 struct xbps_handle xh ;
178277 const char * confdir , * rootdir , * group , * pkg ;
179278 int c , rv , flags = 0 ;
180- bool list_mode = false, set_mode = false;
279+ bool list_mode = false, set_mode = false, repo_mode = false ;
181280
182281 confdir = rootdir = group = pkg = NULL ;
183282
@@ -195,13 +294,22 @@ main(int argc, char **argv)
195294 case 'h' :
196295 usage (false);
197296 /* NOTREACHED */
297+ case 'i' :
298+ flags |= XBPS_FLAG_IGNORE_CONF_REPOS ;
299+ break ;
198300 case 'l' :
199301 list_mode = true;
200302 break ;
201303 case 's' :
202304 set_mode = true;
203305 pkg = optarg ;
204306 break ;
307+ case 'R' :
308+ if (optarg != NULL ) {
309+ xbps_repo_store (& xh , optarg );
310+ }
311+ repo_mode = true;
312+ break ;
205313 case 'r' :
206314 rootdir = optarg ;
207315 break ;
@@ -250,7 +358,26 @@ main(int argc, char **argv)
250358 rv = xbps_pkgdb_update (& xh , true, false);
251359 } else if (list_mode ) {
252360 /* list alternative groups */
253- rv = list_alternatives (& xh , pkg , group );
361+ if (repo_mode ) {
362+ struct search_data sd = { 0 };
363+ if ((sd .result = xbps_dictionary_create ()) == NULL ) {
364+ xbps_error_printf ("Failed to create dictionary: %s\n" , strerror (errno ));
365+ exit (EXIT_FAILURE );
366+ }
367+ sd .group = group ;
368+ rv = xbps_rpool_foreach (& xh , search_repo_cb , & sd );
369+ if (rv != 0 && rv != ENOTSUP ) {
370+ fprintf (stderr , "Failed to initialize rpool: %s\n" ,
371+ strerror (rv ));
372+ exit (EXIT_FAILURE );
373+ }
374+ if (xbps_dictionary_count (sd .result ) > 0 )
375+ print_alternatives (& xh , sd .result , group , true);
376+ else
377+ exit (EXIT_FAILURE );
378+ } else {
379+ rv = list_alternatives (& xh , pkg , group );
380+ }
254381 }
255382
256383 xbps_end (& xh );
0 commit comments