Gentoo Archives: gentoo-commits

From: Fabian Groffen <grobian@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/portage-utils:master commit in: man/include/, /, man/
Date: Fri, 27 Dec 2019 16:57:11
Message-Id: 1577465758.032bd7e9200d1071b79f3a5d33906020fc805048.grobian@gentoo
1 commit: 032bd7e9200d1071b79f3a5d33906020fc805048
2 Author: Fabian Groffen <grobian <AT> gentoo <DOT> org>
3 AuthorDate: Fri Dec 27 16:55:58 2019 +0000
4 Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org>
5 CommitDate: Fri Dec 27 16:55:58 2019 +0000
6 URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=032bd7e9
7
8 main: add masks support
9
10 Expose masks via q -m, store masks in preparation for applying masks
11 when listing available ebuilds.
12
13 Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org>
14
15 main.c | 221 +++++++++++++++++++++++++++++++++--------------------
16 main.h | 2 +
17 man/include/q.desc | 2 +
18 man/q.1 | 13 +++-
19 q.c | 56 +++++++++++++-
20 5 files changed, 209 insertions(+), 85 deletions(-)
21
22 diff --git a/main.c b/main.c
23 index 869bf31..b5404cb 100644
24 --- a/main.c
25 +++ b/main.c
26 @@ -22,6 +22,7 @@
27 #include "eat_file.h"
28 #include "rmspace.h"
29 #include "scandirat.h"
30 +#include "set.h"
31 #include "xasprintf.h"
32
33 /* variables to control runtime behavior */
34 @@ -354,10 +355,12 @@ set_portage_env_var(env_vars *var, const char *value, const char *src)
35 }
36 }
37
38 -/* Helper to read a portage env file (e.g. make.conf), or recursively if
39 - * it points to a directory */
40 +/* Helper to read a portage file (e.g. make.conf, package.mask), or
41 + * recursively if it points to a directory (we don't care about EAPI for
42 + * dirs, basically PMS 5.2.5 EAPI restriction is ignored) */
43 +enum portage_file_type { ENV_FILE, PMASK_FILE };
44 static void
45 -read_portage_env_file(const char *file, env_vars vars[])
46 +read_portage_file(const char *file, enum portage_file_type type, void *data)
47 {
48 FILE *fp;
49 struct dirent **dents;
50 @@ -368,6 +371,8 @@ read_portage_env_file(const char *file, env_vars vars[])
51 size_t buflen = 0;
52 size_t line;
53 int i;
54 + env_vars *vars = data;
55 + set *masks = data;
56
57 if (getenv("DEBUG"))
58 fprintf(stderr, "profile %s\n", file);
59 @@ -384,7 +389,7 @@ read_portage_env_file(const char *file, env_vars vars[])
60 d->d_name[strlen(d->d_name) - 1] == '~')
61 continue;
62 snprintf(npath, sizeof(npath), "%s/%s", file, d->d_name);
63 - read_portage_env_file(npath, vars);
64 + read_portage_file(npath, type, data);
65 }
66 scandir_free(dents, dentslen);
67 goto done;
68 @@ -402,84 +407,107 @@ read_portage_env_file(const char *file, env_vars vars[])
69 continue;
70
71 /* Handle "source" keyword */
72 - if (strncmp(buf, "source ", 7) == 0) {
73 - const char *sfile = buf + 7;
74 - char npath[_Q_PATH_MAX * 2];
75 + if (type == ENV_FILE) {
76 + if (strncmp(buf, "source ", 7) == 0) {
77 + const char *sfile = buf + 7;
78 + char npath[_Q_PATH_MAX * 2];
79
80 - if (sfile[0] != '/') {
81 - /* handle relative paths */
82 - size_t file_path_len;
83 + if (sfile[0] != '/') {
84 + /* handle relative paths */
85 + size_t file_path_len;
86
87 - s = strrchr(file, '/');
88 - file_path_len = s - file + 1;
89 + s = strrchr(file, '/');
90 + file_path_len = s - file + 1;
91
92 - snprintf(npath, sizeof(npath), "%.*s/%s",
93 - (int)file_path_len, file, sfile);
94 - sfile = npath;
95 - }
96 -
97 - read_portage_env_file(sfile, vars);
98 - continue;
99 - }
100 + snprintf(npath, sizeof(npath), "%.*s/%s",
101 + (int)file_path_len, file, sfile);
102 + sfile = npath;
103 + }
104
105 - /* look for our desired variables and grab their value */
106 - for (i = 0; vars[i].name; ++i) {
107 - if (buf[vars[i].name_len] != '=' && buf[vars[i].name_len] != ' ')
108 - continue;
109 - if (strncmp(buf, vars[i].name, vars[i].name_len))
110 + read_portage_file(sfile, type, data);
111 continue;
112 + }
113
114 - /* make sure we handle spaces between the varname, the =,
115 - * and the value:
116 - * VAR=val VAR = val VAR="val"
117 - */
118 - s = buf + vars[i].name_len;
119 - if ((p = strchr(s, '=')) != NULL)
120 - s = p + 1;
121 - while (isspace(*s))
122 - ++s;
123 - if (*s == '"' || *s == '\'') {
124 - char *endq;
125 - char q = *s;
126 -
127 - /* make sure we handle spacing/comments after the quote */
128 - endq = strchr(s + 1, q);
129 - if (!endq) {
130 - /* If the last char is not a quote, then we span lines */
131 - size_t abuflen;
132 - char *abuf;
133 -
134 - abuf = NULL;
135 - while (getline(&abuf, &abuflen, fp) != -1) {
136 - buf = xrealloc(buf, buflen + abuflen);
137 - endq = strchr(abuf, q);
138 - if (endq)
139 - *endq = '\0';
140 -
141 - strcat(buf, abuf);
142 - buflen += abuflen;
143 -
144 - if (endq)
145 - break;
146 - }
147 - free(abuf);
148 -
149 - if (!endq)
150 - warn("%s:%zu: %s: quote mismatch",
151 - file, line, vars[i].name);
152 + /* look for our desired variables and grab their value */
153 + for (i = 0; vars[i].name; i++) {
154 + if (buf[vars[i].name_len] != '=' &&
155 + buf[vars[i].name_len] != ' ')
156 + continue;
157 + if (strncmp(buf, vars[i].name, vars[i].name_len))
158 + continue;
159
160 - s = buf + vars[i].name_len + 2;
161 + /* make sure we handle spaces between the varname, the =,
162 + * and the value:
163 + * VAR=val VAR = val VAR="val"
164 + */
165 + s = buf + vars[i].name_len;
166 + if ((p = strchr(s, '=')) != NULL)
167 + s = p + 1;
168 + while (isspace(*s))
169 + s++;
170 + if (*s == '"' || *s == '\'') {
171 + char *endq;
172 + char q = *s;
173 +
174 + /* make sure we handle spacing/comments after the quote */
175 + endq = strchr(s + 1, q);
176 + if (!endq) {
177 + /* if the last char is not a quote,
178 + * then we span lines */
179 + size_t abuflen;
180 + char *abuf;
181 +
182 + abuf = NULL;
183 + while (getline(&abuf, &abuflen, fp) != -1) {
184 + buf = xrealloc(buf, buflen + abuflen);
185 + endq = strchr(abuf, q);
186 + if (endq)
187 + *endq = '\0';
188 +
189 + strcat(buf, abuf);
190 + buflen += abuflen;
191 +
192 + if (endq)
193 + break;
194 + }
195 + free(abuf);
196 +
197 + if (!endq)
198 + warn("%s:%zu: %s: quote mismatch",
199 + file, line, vars[i].name);
200 +
201 + s = buf + vars[i].name_len + 2;
202 + } else {
203 + *endq = '\0';
204 + s++;
205 + }
206 } else {
207 - *endq = '\0';
208 - ++s;
209 + /* no quotes, so chop the spacing/comments ourselves */
210 + size_t off = strcspn(s, "# \t\n");
211 + s[off] = '\0';
212 }
213 +
214 + set_portage_env_var(&vars[i], s, file);
215 + }
216 + } else if (type == PMASK_FILE) {
217 + /* trim leading space */
218 + for (s = buf; isspace((int)*s); s++)
219 + ;
220 + if (*s == '\0')
221 + continue;
222 + if (*s == '-') {
223 + /* negation/removal, lookup and drop mask if it exists;
224 + * note that this only supports exact matches (PMS
225 + * 5.2.5) so we don't even have to parse and use
226 + * atom-compare here */
227 + s++;
228 + if ((p = del_set(s, masks, NULL)) != NULL)
229 + free(p);
230 } else {
231 - /* no quotes, so chop the spacing/comments ourselves */
232 - size_t off = strcspn(s, "# \t\n");
233 - s[off] = '\0';
234 + p = xstrdup(file);
235 + if (add_set_value(s, p, masks) != NULL)
236 + free(p);
237 }
238 -
239 - set_portage_env_var(&vars[i], s, file);
240 }
241 }
242
243 @@ -490,9 +518,10 @@ read_portage_env_file(const char *file, env_vars vars[])
244
245 /* Helper to recursively read stacked make.defaults in profiles */
246 static void
247 -read_portage_profile(const char *profile, env_vars vars[])
248 +read_portage_profile(const char *profile, env_vars vars[], set *masks)
249 {
250 char profile_file[_Q_PATH_MAX * 3];
251 + char rpath[_Q_PATH_MAX];
252 size_t profile_len;
253 char *s;
254 char *p;
255 @@ -548,7 +577,9 @@ read_portage_profile(const char *profile, env_vars vars[])
256 snprintf(profile_file + profile_len,
257 sizeof(profile_file) - profile_len, "%s", s);
258 }
259 - read_portage_profile(profile_file, vars);
260 + read_portage_profile(
261 + realpath(profile_file, rpath) == NULL ? profile_file : rpath,
262 + vars, masks);
263 /* restore original path in case we were repointed by profile */
264 if (p != NULL)
265 snprintf(profile_file, sizeof(profile_file), "%s/", profile);
266 @@ -557,9 +588,11 @@ read_portage_profile(const char *profile, env_vars vars[])
267
268 free(buf);
269
270 - /* now consume *this* profile's make.defaults */
271 + /* now consume *this* profile's make.defaults and package.mask */
272 strcpy(profile_file + profile_len, "make.defaults");
273 - read_portage_env_file(profile_file, vars);
274 + read_portage_file(profile_file, ENV_FILE, vars);
275 + strcpy(profile_file + profile_len, "package.mask");
276 + read_portage_file(profile_file, PMASK_FILE, masks);
277 }
278
279 static bool nocolor = 0;
280 @@ -598,6 +631,7 @@ env_vars vars_to_read[] = {
281
282 #undef _Q_EV
283 };
284 +set *package_masks = NULL;
285
286 /* Handle a single file in the repos.conf format. */
287 static void
288 @@ -716,10 +750,11 @@ initialize_portage_env(void)
289 const char *s;
290 env_vars *var;
291 char pathbuf[_Q_PATH_MAX];
292 + char rpathbuf[_Q_PATH_MAX];
293 const char *configroot = getenv("PORTAGE_CONFIGROOT");
294 char *primary_overlay = NULL;
295
296 - /* initialize all the strings with their default value */
297 + /* initialize all the properties with their default value */
298 for (i = 0; vars_to_read[i].name; ++i) {
299 var = &vars_to_read[i];
300 if (var->type != _Q_BOOL)
301 @@ -727,6 +762,8 @@ initialize_portage_env(void)
302 var->src = xstrdup(STR_DEFAULT);
303 }
304
305 + package_masks = create_set();
306 +
307 /* figure out where to find our config files */
308 if (!configroot)
309 configroot = CONFIG_EPREFIX;
310 @@ -737,7 +774,7 @@ initialize_portage_env(void)
311 i--;
312
313 /* read overlays first so we can resolve repo references in profile
314 - * parent files */
315 + * parent files (non PMS feature?) */
316 snprintf(pathbuf, sizeof(pathbuf), "%.*s", (int)i, configroot);
317 read_repos_conf(pathbuf, "/usr/share/portage/config/repos.conf",
318 &primary_overlay);
319 @@ -747,23 +784,41 @@ initialize_portage_env(void)
320 snprintf(pathbuf, sizeof(pathbuf),
321 "%.*s/usr/share/portage/config/make.globals",
322 (int)i, configroot);
323 - read_portage_env_file(pathbuf, vars_to_read);
324 + read_portage_file(pathbuf, ENV_FILE, vars_to_read);
325 +
326 + /* start with base masks, Portage behaviour PMS 5.2.8 */
327 + if (primary_overlay != NULL) {
328 + char *overlay;
329 + size_t n;
330 + array_for_each(overlay_names, n, overlay) {
331 + if (overlay == primary_overlay) {
332 + snprintf(pathbuf, sizeof(pathbuf), "%s/profiles/package.mask",
333 + (char *)array_get_elem(overlays, n));
334 + read_portage_file(pathbuf, PMASK_FILE, package_masks);
335 + break;
336 + }
337 + }
338 + }
339
340 /* walk all the stacked profiles */
341 snprintf(pathbuf, sizeof(pathbuf), "%.*s/etc/make.profile",
342 (int)i, configroot);
343 - read_portage_profile(pathbuf, vars_to_read);
344 + read_portage_profile(
345 + realpath(pathbuf, rpathbuf) == NULL ? pathbuf : rpathbuf,
346 + vars_to_read, package_masks);
347 snprintf(pathbuf, sizeof(pathbuf), "%.*s/etc/portage/make.profile",
348 (int)i, configroot);
349 - read_portage_profile(pathbuf, vars_to_read);
350 + read_portage_profile(
351 + realpath(pathbuf, rpathbuf) == NULL ? pathbuf : rpathbuf,
352 + vars_to_read, package_masks);
353
354 - /* now read all the config files */
355 + /* now read all Portage's config files */
356 snprintf(pathbuf, sizeof(pathbuf), "%.*s/etc/make.conf",
357 (int)i, configroot);
358 - read_portage_env_file(pathbuf, vars_to_read);
359 + read_portage_file(pathbuf, ENV_FILE, vars_to_read);
360 snprintf(pathbuf, sizeof(pathbuf), "%.*s/etc/portage/make.conf",
361 (int)i, configroot);
362 - read_portage_env_file(pathbuf, vars_to_read);
363 + read_portage_file(pathbuf, ENV_FILE, vars_to_read);
364
365 /* finally, check the env */
366 for (i = 0; vars_to_read[i].name; i++) {
367
368 diff --git a/main.h b/main.h
369 index 98e5cbb..68b9795 100644
370 --- a/main.h
371 +++ b/main.h
372 @@ -24,6 +24,7 @@
373
374 #include "colors.h"
375 #include "i18n.h"
376 +#include "set.h"
377
378 extern const char *argv0;
379
380 @@ -152,5 +153,6 @@ typedef struct {
381 char *src;
382 } env_vars;
383 extern env_vars vars_to_read[];
384 +extern set *package_masks;
385
386 #endif
387
388 diff --git a/man/include/q.desc b/man/include/q.desc
389 index 7109c46..7d38ba2 100644
390 --- a/man/include/q.desc
391 +++ b/man/include/q.desc
392 @@ -6,3 +6,5 @@ After version 0.74 of portage-utils, the cache functionality was removed
393 in favour of using various trees directly, and optionally the caches
394 therein. As such the \fB-r\fR and \fB-m\fR options were removed. It is
395 no longer necessary to initialise the cache at any time.
396 +.P
397 +After version 0.82, the \fB-m\fR flag got repurposed for listing masks.
398
399 diff --git a/man/q.1 b/man/q.1
400 index 886b00f..21a09b3 100644
401 --- a/man/q.1
402 +++ b/man/q.1
403 @@ -1,5 +1,5 @@
404 .\" generated by mkman.py, please do NOT edit!
405 -.TH q "1" "Nov 2019" "Gentoo Foundation" "q"
406 +.TH q "1" "Dec 2019" "Gentoo Foundation" "q"
407 .SH NAME
408 q \- invoke a portage utility applet
409 .SH SYNOPSIS
410 @@ -14,6 +14,8 @@ After version 0.74 of portage-utils, the cache functionality was removed
411 in favour of using various trees directly, and optionally the caches
412 therein. As such the \fB-r\fR and \fB-m\fR options were removed. It is
413 no longer necessary to initialise the cache at any time.
414 +.P
415 +After version 0.82, the \fB-m\fR flag got repurposed for listing masks.
416 .SH OPTIONS
417 .TP
418 \fB\-i\fR, \fB\-\-install\fR
419 @@ -26,6 +28,15 @@ see the source (file) where the overlay was declared.
420 \fB\-e\fR, \fB\-\-envvar\fR
421 Print used environment variables and found values. Use \fI-v\fR to
422 see the source (file, environment) where the variable was declared.
423 +Additional arguments are treated as variable names to print the
424 +values for. If just one name is given, only the value is printed if
425 +matched. When no arguments or more than one argument is given, the
426 +variable name and the value is printed as a shell-style declaration.
427 +.TP
428 +\fB\-m\fR, \fB\-\-masks\fR
429 +Print the masks from package.mask files found. Use \fI-v\fR to see
430 +the source (file) where the mask was declared. Additional arguments
431 +are treated as atom selectors which must match the masks.
432 .TP
433 \fB\-\-root\fR \fI<arg>\fR
434 Set the ROOT env var.
435
436 diff --git a/q.c b/q.c
437 index f137b04..4a2fd62 100644
438 --- a/q.c
439 +++ b/q.c
440 @@ -19,21 +19,24 @@
441 #include <libproc.h>
442 #endif
443
444 +#include "atom.h"
445 #include "basename.h"
446 #include "eat_file.h"
447 #include "rmspace.h"
448
449 -#define Q_FLAGS "ioe" COMMON_FLAGS
450 +#define Q_FLAGS "ioem" COMMON_FLAGS
451 static struct option const q_long_opts[] = {
452 {"install", no_argument, NULL, 'i'},
453 {"overlays", no_argument, NULL, 'o'},
454 {"envvar", no_argument, NULL, 'e'},
455 + {"masks", no_argument, NULL, 'm'},
456 COMMON_LONG_OPTS
457 };
458 static const char * const q_opts_help[] = {
459 "Install symlinks for applets",
460 "Print available overlays (read from repos.conf)",
461 "Print used variables and their found values",
462 + "Print (package.)masks for the current profile",
463 COMMON_OPTS_HELP
464 };
465 #define q_usage(ret) usage(ret, Q_FLAGS, q_long_opts, q_opts_help, NULL, lookup_applet_idx("q"))
466 @@ -81,6 +84,7 @@ int q_main(int argc, char **argv)
467 bool install;
468 bool print_overlays;
469 bool print_vars;
470 + bool print_masks;
471 const char *p;
472 APPLET func;
473
474 @@ -100,12 +104,14 @@ int q_main(int argc, char **argv)
475 install = false;
476 print_overlays = false;
477 print_vars = false;
478 + print_masks = false;
479 while ((i = GETOPT_LONG(Q, q, "+")) != -1) {
480 switch (i) {
481 COMMON_GETOPTS_CASES(q)
482 case 'i': install = true; break;
483 case 'o': print_overlays = true; break;
484 case 'e': print_vars = true; break;
485 + case 'm': print_masks = true; break;
486 }
487 }
488
489 @@ -258,6 +264,54 @@ int q_main(int argc, char **argv)
490 return 0;
491 }
492
493 + if (print_masks) {
494 + DECLARE_ARRAY(masks);
495 + DECLARE_ARRAY(files);
496 + char *mask;
497 + size_t n;
498 + int j;
499 + bool match;
500 + depend_atom *atom;
501 + depend_atom *qatom;
502 +
503 + array_set(package_masks, masks);
504 + values_set(package_masks, files);
505 +
506 + array_for_each(masks, n, mask) {
507 + if ((atom = atom_explode(mask)) == NULL)
508 + continue;
509 +
510 + match = true;
511 + if (argc > optind) {
512 + match = false;
513 + for (j = optind; j < argc; j++) {
514 + qatom = atom_explode(argv[j]);
515 + if (qatom != NULL && atom_compare(atom, qatom) == EQUAL)
516 + match = true;
517 + atom_implode(qatom);
518 + if (match)
519 + break;
520 + }
521 + }
522 + if (!match)
523 + continue;
524 +
525 + printf("%s", atom_format(
526 + "%[pfx]%[CAT]%[PF]%[SLOT]%[SUBSLOT]%[sfx]%[USE]%[REPO]",
527 + atom));
528 + if (verbose)
529 + printf(" [%s]\n", (char *)array_get_elem(files, n));
530 + else
531 + printf("\n");
532 + atom_implode(atom);
533 + }
534 +
535 + xarrayfree_int(masks);
536 + xarrayfree_int(files);
537 +
538 + return 0;
539 + }
540 +
541 if (argc == optind)
542 q_usage(EXIT_FAILURE);
543 if ((func = lookup_applet(argv[optind])) == NULL)