/[gentoo-projects]/portage-utils/qcache.c
Gentoo

Contents of /portage-utils/qcache.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.46 - (show annotations) (download) (as text)
Sun Sep 29 18:40:22 2013 UTC (13 months, 4 weeks ago) by vapier
Branch: MAIN
Changes since 1.45: +2 -2 lines
File MIME type: text/x-csrc
qcache: include errno when warning about cache read errors

1 /*
2 * Copyright 2005-2010 Gentoo Foundation
3 * Distributed under the terms of the GNU General Public License v2
4 * $Header: /var/cvsroot/gentoo-projects/portage-utils/qcache.c,v 1.42 2013/09/29 05:03:31 vapier Exp $
5 *
6 * Copyright 2006 Thomas A. Cort - <tcort@gentoo.org>
7 */
8
9 #ifdef APPLET_qcache
10
11 #include <dirent.h>
12 #include <fcntl.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <time.h>
19 #include <unistd.h>
20
21 /********************************************************************/
22 /* Required portage-utils stuff */
23 /********************************************************************/
24
25 #define QCACHE_FLAGS "p:c:idtans" COMMON_FLAGS
26 static struct option const qcache_long_opts[] = {
27 {"matchpkg", a_argument, NULL, 'p'},
28 {"matchcat", a_argument, NULL, 'c'},
29 {"imlate", no_argument, NULL, 'i'},
30 {"dropped", no_argument, NULL, 'd'},
31 {"testing", no_argument, NULL, 't'},
32 {"stats", no_argument, NULL, 's'},
33 {"all", no_argument, NULL, 'a'},
34 {"not", no_argument, NULL, 'n'},
35 COMMON_LONG_OPTS
36 };
37
38 static const char * const qcache_opts_help[] = {
39 "match pkgname",
40 "match catname",
41 "list packages that can be marked stable on a given arch",
42 "list packages that have dropped keywords on a version bump on a given arch",
43 "list packages that have ~arch versions, but no stable versions on a given arch",
44 "display statistics about the portage tree",
45 "list packages that have at least one version keyworded for on a given arch",
46 "list packages that aren't keyworded on a given arch.",
47 COMMON_OPTS_HELP
48 };
49
50 static const char qcache_rcsid[] = "$Id: qcache.c,v 1.42 2013/09/29 05:03:31 vapier Exp $";
51 #define qcache_usage(ret) usage(ret, QCACHE_FLAGS, qcache_long_opts, qcache_opts_help, lookup_applet_idx("qcache"))
52
53 /********************************************************************/
54 /* Constants */
55 /********************************************************************/
56
57 /* TODO: allow the user to override this value if s/he wishes */
58 #define QCACHE_EDB "/var/cache/edb/dep"
59
60 /********************************************************************/
61 /* Structs */
62 /********************************************************************/
63
64 typedef struct {
65 char *category;
66 char *package;
67 char *ebuild;
68 portage_cache *cache_data;
69 unsigned char cur;
70 unsigned char num;
71 } qcache_data;
72
73 /********************************************************************/
74 /* Global Variables */
75 /********************************************************************/
76
77 static char **archlist; /* Read from PORTDIR/profiles/arch.list in qcache_init() */
78 static int archlist_count;
79 const char status[3] = {'-', '~', '+'};
80 int qcache_skip, qcache_test_arch, qcache_last = 0;
81 char *qcache_matchpkg = NULL, *qcache_matchcat = NULL;
82
83 /********************************************************************/
84 /* Enumerations */
85 /********************************************************************/
86
87 enum { none = 0, testing, stable, minus };
88
89 /********************************************************************/
90 /* Keyword functions */
91 /********************************************************************/
92
93 /*
94 * int decode_status(char c);
95 *
96 * Decode keyword status
97 *
98 * IN:
99 * char c - status to check
100 * OUT:
101 * int - one of the following enum { none = 0, testing, stable, minus };
102 */
103 int decode_status(char c);
104 int decode_status(char c)
105 {
106 switch (c) {
107 case '-': return minus;
108 case '~': return testing;
109 default: return stable;
110 }
111 }
112
113 /*
114 * int decode_arch(const char *arch);
115 *
116 * Decode the architecture string
117 *
118 * IN:
119 * const char *arch - name of an arch (alpha, amd64, ...)
120 * OUT:
121 * int pos - location of arch in archlist[]
122 */
123 int decode_arch(const char *arch);
124 int decode_arch(const char *arch)
125 {
126 int a;
127 const char *p;
128
129 p = arch;
130 if (*p == '~' || *p == '-')
131 p++;
132
133 for (a = 0; a < archlist_count; ++a)
134 if (strcmp(archlist[a], p) == 0)
135 return a;
136
137 return -1;
138 }
139
140 /*
141 * void print_keywords(char *category, char *ebuild, int *keywords);
142 *
143 * Prints the keywords to stdout
144 *
145 * IN:
146 * char *category - current category of the current package
147 * int *keywords - an array of keywords that coincides with archlist
148 */
149 void print_keywords(char *category, char *ebuild, int *keywords);
150 void print_keywords(char *category, char *ebuild, int *keywords)
151 {
152 int a;
153 char *package;
154
155 package = xstrdup(ebuild);
156 package[strlen(ebuild)-7] = '\0';
157
158 printf("%s%s/%s%s%s ", BOLD, category, BLUE, package, NORM);
159 for (a = 0; a < archlist_count; ++a) {
160 switch (keywords[a]) {
161 case stable:
162 printf("%s%c%s%s ", GREEN, status[keywords[a]], archlist[a], NORM);
163 break;
164 case testing:
165 printf("%s%c%s%s ", YELLOW, status[keywords[a]], archlist[a], NORM);
166 break;
167 default:
168 break;
169 }
170 }
171
172 printf("\n");
173 free(package);
174 }
175
176 /*
177 * int read_keywords(char *s, int *keywords);
178 *
179 * Read the KEYWORDS string and decode the values
180 *
181 * IN:
182 * char *s - a keywords string (ex: "alpha ~amd64 -x86")
183 * int *keywords - the output
184 * ERR:
185 * int rc - -1 is returned on error (if !s || !keywords)
186 */
187 int read_keywords(char *s, int *keywords);
188 int read_keywords(char *s, int *keywords)
189 {
190 char *arch, delim[2] = { ' ', '\0' };
191 size_t slen;
192 int a;
193
194 if (!s)
195 return -1;
196
197 memset(keywords, 0, sizeof(*keywords) * archlist_count);
198
199 slen = strlen(s);
200 if (slen >= 2 && s[0] == '-' && s[1] == '*')
201 for (a = 0; a < archlist_count; ++a)
202 keywords[a] = minus;
203
204 if (!slen)
205 return 0;
206
207 arch = strtok(s, delim);
208 do {
209 a = decode_arch(arch);
210 if (a == -1)
211 continue;
212 keywords[a] = decode_status(arch[0]);
213 } while ((arch = strtok(NULL, delim)));
214
215 return 0;
216 }
217
218 /********************************************************************/
219 /* File reading helper functions */
220 /********************************************************************/
221
222 /*
223 * inline unsigned int qcache_count_lines(char *filename);
224 *
225 * Count the number of new line characters '\n' in a file.
226 *
227 * IN:
228 * char *filename - name of the file to read.
229 * OUT:
230 * unsigned int count - number of new lines counted.
231 * ERR:
232 * -1 is returned if the file cannot be read.
233 */
234 static unsigned int qcache_count_lines(char *filename)
235 {
236 int count, fd;
237 char c;
238
239 if ((fd = open(filename, O_RDONLY)) != -1) {
240 count = 0;
241
242 while (read(fd, &c, 1) == 1)
243 if (c == '\n')
244 count++;
245
246 close(fd);
247 return count;
248 }
249
250 return -1;
251 }
252
253 /*
254 * char **qcache_read_lines(char *filename);
255 *
256 * Reads in every line contained in a file
257 *
258 * IN:
259 * char *filename - name of the file to read.
260 * OUT:
261 * char **lines - number of new lines counted.
262 * ERR:
263 * NULL is returned if an error occurs.
264 */
265 char **qcache_read_lines(char *filename);
266 char **qcache_read_lines(char *filename)
267 {
268 int len, fd, count, i, num_lines;
269 char **lines, c;
270
271 if (-1 == (num_lines = qcache_count_lines(filename)))
272 return NULL;
273
274 len = sizeof(char*) * (num_lines + 1);
275 lines = xzalloc(len);
276
277 if ((fd = open(filename, O_RDONLY)) != -1) {
278 for (i = 0; i < num_lines; i++) {
279 count = 0;
280
281 /* determine the space needed for storing the line */
282 while (read(fd, &c, 1) == 1 && c != '\n')
283 count++;
284 lseek(fd, (lseek(fd, 0, SEEK_CUR) - count - 1), SEEK_SET);
285
286 lines[i] = xzalloc(sizeof(char) * (count+1));
287
288 /* copy the line into lines[i] */
289 assert(read(fd, lines[i], count) == count);
290 assert(read(fd, &c, 1) == 1); /* skip '\n' */
291 }
292
293 close(fd);
294 return lines;
295 }
296
297 return NULL;
298 }
299
300 /*
301 * void qcache_free_lines(char **lines);
302 *
303 * free()'s memory allocated by qcache_read_lines
304 */
305 void qcache_free_lines(char **lines);
306 void qcache_free_lines(char **lines)
307 {
308 int i;
309
310 for (i = 0; lines[i]; i++)
311 free(lines[i]);
312
313 free(lines);
314 }
315
316 /*
317 * portage_cache *qcache_read_cache_file(const char *file);
318 *
319 * Read a file from the edb cache and store data in portage_cache.
320 *
321 * IN:
322 * const char *filename - cache file to read
323 * OUT:
324 * portage_cache *pkg - cache data
325 * ERR:
326 * NULL is returned when an error occurs.
327 */
328 portage_cache *qcache_read_cache_file(const char *filename);
329 portage_cache *qcache_read_cache_file(const char *filename)
330 {
331 struct stat s;
332 char *ptr, *buf;
333 FILE *f;
334 portage_cache *ret = NULL;
335 size_t len, buflen;
336
337 if ((f = fopen(filename, "r")) == NULL)
338 goto err;
339
340 if (fstat(fileno(f), &s) != 0) {
341 fclose(f);
342 goto err;
343 }
344
345 buf = NULL;
346 len = sizeof(*ret) + s.st_size + 1;
347 ret = xzalloc(len);
348
349 while (getline(&buf, &buflen, f) != -1) {
350 if ((ptr = strrchr(buf, '\n')) != NULL)
351 *ptr = 0;
352
353 if (strncmp(buf, "DEPEND=", 7) == 0)
354 ret->DEPEND = xstrdup(buf + 7);
355
356 if (strncmp(buf, "DESCRIPTION=", 12) == 0)
357 ret->DESCRIPTION = xstrdup(buf + 12);
358
359 if (strncmp(buf, "HOMEPAGE=", 9) == 0)
360 ret->HOMEPAGE = xstrdup(buf + 9);
361
362 if (strncmp(buf, "INHERITED=", 10) == 0)
363 ret->INHERITED = xstrdup(buf + 10);
364
365 if (strncmp(buf, "IUSE=", 4) == 0)
366 ret->IUSE = xstrdup(buf + 4);
367
368 if (strncmp(buf, "KEYWORDS=", 9) == 0)
369 ret->KEYWORDS = xstrdup(buf + 9);
370
371 if (strncmp(buf, "LICENSE=", 8) == 0)
372 ret->LICENSE = xstrdup(buf + 8);
373
374 if (strncmp(buf, "PDEPEND=", 8) == 0)
375 ret->PDEPEND = xstrdup(buf + 8);
376
377 if (strncmp(buf, "PROVIDE=", 8) == 0)
378 ret->PROVIDE = xstrdup(buf + 8);
379
380 if (strncmp(buf, "RDEPEND=", 8) == 0)
381 ret->RDEPEND = xstrdup(buf + 8);
382
383 if (strncmp(buf, "RESTRICT=", 9) == 0)
384 ret->RESTRICT = xstrdup(buf + 9);
385
386 if (strncmp(buf, "SLOT=", 5) == 0)
387 ret->SLOT = xstrdup(buf + 5);
388
389 if (strncmp(buf, "SRC_URI=", 8) == 0)
390 ret->SRC_URI = xstrdup(buf + 8);
391 }
392
393 free(buf);
394 ret->atom = atom_explode(filename);
395 fclose(f);
396
397 return ret;
398
399 err:
400 if (ret)
401 cache_free(ret);
402 return NULL;
403 }
404
405 /*
406 * void qcache_free_data(portage_cache *cache);
407 *
408 * free()'s a portage_cache
409 *
410 * IN:
411 * portage_cache *cache - the portage_cache to be free()'d
412 */
413 void qcache_free_data(portage_cache *cache);
414 void qcache_free_data(portage_cache *cache)
415 {
416 int i;
417 char **c;
418
419 if (!cache)
420 errf("Cache is empty !");
421
422 for (i = 0, c = (char**) cache; i < 15; i++)
423 if (c[i])
424 free(c[i]);
425
426 atom_implode(cache->atom);
427 free(cache);
428 }
429
430 /********************************************************************/
431 /* Comparison functions */
432 /********************************************************************/
433
434 /*
435 * int qcache_vercmp(const void *x, const void *y);
436 *
437 * Compare 2 struct dirent d_name strings based with atom_compare_str().
438 * Used with dirscan() to sort ebuild filenames by version.
439 *
440 * IN:
441 * 2 (const struct dirent **) with d_name filled in
442 * OUT:
443 * -1 (NEWER)
444 * 1 (OLDER)
445 * 0 (SAME)
446 */
447 int qcache_vercmp(const struct dirent **x, const struct dirent **y);
448 int qcache_vercmp(const struct dirent **x, const struct dirent **y)
449 {
450 switch (atom_compare_str((*x)->d_name, (*y)->d_name)) {
451 case NEWER: return -1;
452 case OLDER: return 1;
453 default: return 0;
454 }
455 }
456
457 /********************************************************************/
458 /* Selection functions */
459 /********************************************************************/
460
461 /*
462 * int qcache_file_select(const struct dirent *entry);
463 *
464 * Selects filenames that do not begin with '.' and are not name "metadata.xml"
465 * or that file matches ".cpickle"
466 *
467 * IN:
468 * const struct dirent *entry - entry to check
469 * OUT:
470 * int - 0 if filename begins with '.' or is "metadata.xml", otherwise 1
471 */
472 int qcache_file_select(const struct dirent *entry);
473 int qcache_file_select(const struct dirent *entry)
474 {
475 return !(entry->d_name[0] == '.' || (strcmp(entry->d_name, "metadata.xml") == 0) || (strstr(entry->d_name, ".cpickle") != 0));
476 }
477
478 /*
479 * int qcache_ebuild_select(const struct dirent *entry);
480 *
481 * Select filenames that end in ".ebuild"
482 *
483 * IN:
484 * const struct dirent *entry - entry to check
485 * OUT:
486 * int - 1 if the filename ends in ".ebuild", otherwise 0
487 */
488 int qcache_ebuild_select(const struct dirent *entry);
489 int qcache_ebuild_select(const struct dirent *entry)
490 {
491 return ((strlen(entry->d_name) > 7) && !strcmp(entry->d_name+strlen(entry->d_name)-7, ".ebuild"));
492 }
493
494 /********************************************************************/
495 /* Traversal function */
496 /********************************************************************/
497
498 /*
499 * int qcache_traverse(void (*func)(qcache_data*));
500 *
501 * visit every version of every package of every category in the tree
502 *
503 * IN:
504 * void (*func)(qcache_data*) - function to call
505 * OUT:
506 * int - 0 on success.
507 * ERR:
508 * exit or return -1 on failure.
509 */
510 int qcache_traverse(void (*func)(qcache_data*));
511 int qcache_traverse(void (*func)(qcache_data*))
512 {
513 qcache_data data;
514 char *catpath, *pkgpath, *ebuildpath, *cachepath;
515 int i, j, k, len, num_cat, num_pkg, num_ebuild;
516 struct dirent **categories, **packages, **ebuilds;
517
518 xasprintf(&catpath, "%s%s", QCACHE_EDB, portdir);
519
520 if (-1 == (num_cat = scandir(catpath, &categories, qcache_file_select, alphasort))) {
521 errp("%s", catpath);
522 free(catpath);
523 }
524
525 if (!num_cat)
526 warn("%s is empty!", catpath);
527
528 /* traverse categories */
529 for (i = 0; i < num_cat; i++) {
530 xasprintf(&pkgpath, "%s/%s", portdir, categories[i]->d_name);
531
532 if (-1 == (num_pkg = scandir(pkgpath, &packages, qcache_file_select, alphasort))) {
533 if (errno != ENOENT)
534 warnp("Found a cache dir, but unable to process %s", pkgpath);
535 free(categories[i]);
536 free(pkgpath);
537 continue;
538 }
539
540 if (qcache_matchcat) {
541 if (strcmp(categories[i]->d_name, qcache_matchcat) != 0) {
542 for (j = 0; j < num_pkg; j++)
543 free(packages[j]);
544 free(categories[i]);
545 free(packages);
546 free(pkgpath);
547 continue;
548 }
549 }
550
551 /* traverse packages */
552 for (j = 0; j < num_pkg; j++) {
553 len = sizeof(char) * (strlen(portdir) + strlen("/") + strlen(categories[i]->d_name) + strlen("/") + strlen(packages[j]->d_name) + 1);
554 ebuildpath = xzalloc(len);
555 snprintf(ebuildpath, len, "%s/%s/%s", portdir, categories[i]->d_name, packages[j]->d_name);
556
557 if (-1 == (num_ebuild = scandir(ebuildpath, &ebuilds, qcache_ebuild_select, qcache_vercmp))) {
558 warnp("%s", ebuildpath);
559 free(packages[i]);
560 free(pkgpath);
561 continue;
562 }
563
564 if (qcache_matchpkg) {
565 if (strcmp(packages[j]->d_name, qcache_matchpkg) != 0) {
566 for (k = 0; k < num_ebuild; k++)
567 free(ebuilds[k]);
568 free(packages[j]);
569 free(ebuilds);
570 free(ebuildpath);
571 continue;
572 }
573 }
574
575 qcache_skip = 0;
576
577 /* traverse ebuilds */
578 for (k = 0; k < num_ebuild; k++) {
579 len = sizeof(char) * (strlen(catpath) + strlen("/") + strlen(categories[i]->d_name) + strlen("/") + strlen(ebuilds[k]->d_name) + 1);
580 cachepath = xzalloc(len);
581 snprintf(cachepath, len, "%s/%s/%s", catpath, categories[i]->d_name, ebuilds[k]->d_name);
582 cachepath[len-8] = '\0'; /* remove ".ebuild" */
583
584 data.category = categories[i]->d_name;
585 data.package = packages[j]->d_name;
586 data.ebuild = ebuilds[k]->d_name;
587 data.cur = k + 1;
588 data.num = num_ebuild;
589 data.cache_data = qcache_read_cache_file(cachepath);
590
591 if (data.cache_data != NULL) {
592 /* is this the last ebuild? */
593 if (i+1 == num_cat && j+1 == num_pkg && k+1 == num_ebuild)
594 qcache_last = 1;
595
596 if (!qcache_skip)
597 func(&data);
598
599 qcache_free_data(data.cache_data);
600 } else
601 warnp("unable to read cache '%s'\n"
602 "\tperhaps you need to `egencache -j 4` ?", cachepath);
603
604 free(ebuilds[k]);
605 free(cachepath);
606 }
607
608 free(packages[j]);
609 free(ebuilds);
610 free(ebuildpath);
611 }
612
613 free(categories[i]);
614 free(packages);
615 free(pkgpath);
616 }
617
618 free(categories);
619 free(catpath);
620
621 return 0;
622 }
623
624 /********************************************************************/
625 /* functors */
626 /********************************************************************/
627
628 void qcache_imlate(qcache_data *data);
629 void qcache_imlate(qcache_data *data)
630 {
631 int *keywords;
632 int a;
633
634 keywords = xmalloc(sizeof(*keywords) * archlist_count);
635
636 if (read_keywords(data->cache_data->KEYWORDS, keywords) < 0) {
637 warn("Failed to read keywords for %s%s/%s%s%s", BOLD, data->category, BLUE, data->ebuild, NORM);
638 free(keywords);
639 return;
640 }
641
642 switch (keywords[qcache_test_arch]) {
643 case stable:
644 qcache_skip = 1;
645 case none:
646 case minus:
647 break;
648
649 default:
650 for (a = 0; a < archlist_count && !qcache_skip; ++a) {
651 if (keywords[a] != stable)
652 continue;
653 qcache_skip = 1;
654 print_keywords(data->category, data->ebuild, keywords);
655 }
656 }
657 free(keywords);
658 }
659
660 void qcache_not(qcache_data *data);
661 void qcache_not(qcache_data *data)
662 {
663 int *keywords;
664
665 keywords = xmalloc(sizeof(*keywords) * archlist_count);
666
667 if (read_keywords(data->cache_data->KEYWORDS, keywords) < 0) {
668 warn("Failed to read keywords for %s%s/%s%s%s", BOLD, data->category, BLUE, data->ebuild, NORM);
669 free(keywords);
670 return;
671 }
672
673 if (keywords[qcache_test_arch] == testing || keywords[qcache_test_arch] == stable) {
674 qcache_skip = 1;
675 } else if (data->cur == data->num) {
676 printf("%s%s/%s%s%s\n", BOLD, data->category, BLUE, data->package, NORM);
677 }
678
679 free(keywords);
680 }
681
682 void qcache_all(qcache_data *data);
683 void qcache_all(qcache_data *data)
684 {
685 int *keywords;
686
687 keywords = xmalloc(sizeof(*keywords) * archlist_count);
688
689 if (read_keywords(data->cache_data->KEYWORDS, keywords) < 0) {
690 warn("Failed to read keywords for %s%s/%s%s%s", BOLD, data->category, BLUE, data->ebuild, NORM);
691 free(keywords);
692 return;
693 }
694
695 if (keywords[qcache_test_arch] == stable || keywords[qcache_test_arch] == testing) {
696 qcache_skip = 1;
697 printf("%s%s/%s%s%s\n", BOLD, data->category, BLUE, data->package, NORM);
698 }
699
700 free(keywords);
701 }
702
703 void qcache_dropped(qcache_data *data);
704 void qcache_dropped(qcache_data *data)
705 {
706 static int possible = 0;
707 int *keywords, i;
708
709 if (data->cur == 1)
710 possible = 0;
711
712 keywords = xmalloc(sizeof(*keywords) * archlist_count);
713
714 if (read_keywords(data->cache_data->KEYWORDS, keywords) < 0) {
715 warn("Failed to read keywords for %s%s/%s%s%s", BOLD, data->category, BLUE, data->ebuild, NORM);
716 free(keywords);
717 return;
718 }
719
720 if (keywords[qcache_test_arch] == testing || keywords[qcache_test_arch] == stable) {
721 qcache_skip = 1;
722
723 if (possible) {
724 printf("%s%s/%s%s%s\n", BOLD, data->category, BLUE, data->package, NORM);
725 }
726
727 free(keywords);
728 return;
729 }
730
731 if (!possible) {
732 /* don't count newer versions with "-*" keywords */
733 for (i = 0; i < archlist_count; ++i) {
734 if (keywords[i] == stable || keywords[i] == testing) {
735 possible = 1;
736 break;
737 }
738 }
739 }
740
741 free(keywords);
742 }
743
744 void qcache_stats(qcache_data *data);
745 void qcache_stats(qcache_data *data)
746 {
747 static time_t runtime;
748 static int numpkg = 0;
749 static int numebld = 0;
750 static int numcat;
751 static int *packages_stable;
752 static int *packages_testing;
753 static int *current_package_keywords;
754 static int *keywords;
755 int a, i;
756
757 if (!numpkg) {
758 struct dirent **categories;
759 char *catpath;
760 int len;
761
762 len = sizeof(char) * (strlen(QCACHE_EDB) + strlen(portdir) + 1);
763 catpath = xzalloc(len);
764 snprintf(catpath, len, "%s%s", QCACHE_EDB, portdir);
765
766 if (-1 == (numcat = scandir(catpath, &categories, qcache_file_select, alphasort))) {
767 errp("%s", catpath);
768 free(catpath);
769 }
770
771 for (i = 0; i < numcat; i++)
772 free(categories[i]);
773 free(categories);
774
775 runtime = time(NULL);
776
777 packages_stable = xcalloc(archlist_count, sizeof(*packages_stable));
778 packages_testing = xcalloc(archlist_count, sizeof(*packages_testing));
779 keywords = xcalloc(archlist_count, sizeof(*keywords));
780 current_package_keywords = xcalloc(archlist_count, sizeof(*current_package_keywords));
781 }
782
783 if (data->cur == 1) {
784 numpkg++;
785 memset(current_package_keywords, 0, archlist_count * sizeof(*current_package_keywords));
786 }
787 ++numebld;
788
789 memset(keywords, 0, archlist_count * sizeof(*keywords));
790 if (read_keywords(data->cache_data->KEYWORDS, keywords) < 0) {
791 warn("Failed to read keywords for %s%s/%s%s%s", BOLD, data->category, BLUE, data->ebuild, NORM);
792 return;
793 }
794
795 for (a = 0; a < archlist_count; ++a) {
796 switch (keywords[a]) {
797 case stable:
798 current_package_keywords[a] = stable;
799 break;
800 case testing:
801 if (current_package_keywords[a] != stable)
802 current_package_keywords[a] = testing;
803 default:
804 break;
805 }
806 }
807
808 if (data->cur == data->num) {
809 for (a = 0; a < archlist_count; ++a) {
810 switch (current_package_keywords[a]) {
811 case stable:
812 packages_stable[a]++;
813 break;
814 case testing:
815 packages_testing[a]++;
816 default:
817 break;
818 }
819 }
820 }
821
822 if (qcache_last) {
823 printf("+-------------------------+\n");
824 printf("| general statistics |\n");
825 printf("+-------------------------+\n");
826 printf("| %s%13s%s | %s%7d%s |\n", GREEN, "architectures", NORM, BLUE, archlist_count, NORM);
827 printf("| %s%13s%s | %s%7d%s |\n", GREEN, "categories", NORM, BLUE, numcat, NORM);
828 printf("| %s%13s%s | %s%7d%s |\n", GREEN, "packages", NORM, BLUE, numpkg, NORM);
829 printf("| %s%13s%s | %s%7d%s |\n", GREEN, "ebuilds", NORM, BLUE, numebld, NORM);
830 printf("+-------------------------+\n\n");
831
832 printf("+----------------------------------------------------------+\n");
833 printf("| keyword distribution |\n");
834 printf("+----------------------------------------------------------+\n");
835 printf("| %s%12s%s |%s%8s%s |%s%8s%s |%s%8s%s | %s%8s%s |\n", RED, "architecture", NORM, RED, "stable", NORM, RED, "~arch", NORM, RED, "total", NORM, RED, "total/#pkgs", NORM);
836 printf("| | |%s%8s%s | | |\n", RED, "only", NORM);
837 printf("+----------------------------------------------------------+\n");
838
839 for (a = 0; a < archlist_count; ++a) {
840 printf("| %s%12s%s |", GREEN, archlist[a], NORM);
841 printf("%s%8d%s |", BLUE, packages_stable[a], NORM);
842 printf("%s%8d%s |", BLUE, packages_testing[a], NORM);
843 printf("%s%8d%s |", BLUE, packages_testing[a]+packages_stable[a], NORM);
844 printf("%s%11.2f%s%% |\n", BLUE, (100.0*(packages_testing[a]+packages_stable[a]))/numpkg, NORM);
845 }
846
847 printf("+----------------------------------------------------------+\n\n");
848
849 printf("Completed in %s%d%s seconds.\n", BLUE, (int)(time(NULL)-runtime), NORM);
850
851 free(packages_stable);
852 free(packages_testing);
853 free(keywords);
854 free(current_package_keywords);
855 }
856 }
857
858 void qcache_testing_only(qcache_data *data);
859 void qcache_testing_only(qcache_data *data)
860 {
861 static int possible = 0;
862 int *keywords;
863
864 if (data->cur == 1)
865 possible = 0;
866
867 keywords = xmalloc(sizeof(*keywords) * archlist_count);
868
869 if (read_keywords(data->cache_data->KEYWORDS, keywords) < 0) {
870 warn("Failed to read keywords for %s%s/%s%s%s", BOLD, data->category, BLUE, data->ebuild, NORM);
871 free(keywords);
872 return;
873 }
874
875 if (keywords[qcache_test_arch] == stable) {
876 qcache_skip = 1;
877 free(keywords);
878 return;
879 }
880
881 /* the qcache_test_arch must have at least 1 ~arch keyword */
882 if (keywords[qcache_test_arch] == testing)
883 possible = 1;
884
885 if (data->cur == data->num && possible) {
886 printf("%s%s/%s%s%s\n", BOLD, data->category, BLUE, data->package, NORM);
887 }
888
889 free(keywords);
890 }
891
892 /********************************************************************/
893 /* Misc functions */
894 /********************************************************************/
895
896 /*
897 * int qcache_init();
898 *
899 * Initialize variables (archlist, num_arches)
900 *
901 * OUT:
902 * 0 is return on success.
903 * ERR:
904 * -1 is returned on error.
905 */
906 int qcache_init();
907 int qcache_init()
908 {
909 char *filename;
910 unsigned int len;
911
912 len = sizeof(char) * (strlen(portdir) + strlen("/profiles/arch.list") + 1);
913 filename = xzalloc(len);
914
915 snprintf(filename, len, "%s/profiles/arch.list", portdir);
916
917 if (NULL == (archlist = qcache_read_lines(filename))) {
918 free(filename);
919 return -1;
920 }
921
922 len = 0;
923 while (archlist[len])
924 ++len;
925 archlist_count = len;
926
927 free(filename);
928 return 0;
929 }
930
931 /*
932 * int qcache_free();
933 *
934 * Deallocate variables (archlist)
935 */
936 void qcache_free();
937 void qcache_free()
938 {
939 qcache_free_lines(archlist);
940 }
941
942 /********************************************************************/
943 /* main */
944 /********************************************************************/
945
946 int qcache_main(int argc, char **argv)
947 {
948 int i, action = 0;
949
950 DBG("argc=%d argv[0]=%s argv[1]=%s",
951 argc, argv[0], argc > 1 ? argv[1] : "NULL?");
952
953 while ((i = GETOPT_LONG(QCACHE, qcache, "")) != -1) {
954 switch (i) {
955 case 'p': qcache_matchpkg = optarg; break;
956 case 'c': qcache_matchcat = optarg; break;
957 case 'i':
958 case 'd':
959 case 't':
960 case 's':
961 case 'a':
962 case 'n':
963 if (action)
964 qcache_usage(EXIT_FAILURE); /* trying to use more than 1 action */
965 action = i;
966 break;
967
968 COMMON_GETOPTS_CASES(qcache)
969 }
970 }
971
972 if (-1 == qcache_init())
973 err("Could not initialize arch list");
974
975 if (optind < argc)
976 qcache_test_arch = decode_arch(argv[optind]);
977
978 if ((qcache_test_arch == -1 && action != 's') || optind + 1 < argc)
979 qcache_usage(EXIT_FAILURE);
980
981 switch (action) {
982 case 'i': return qcache_traverse(qcache_imlate);
983 case 'd': return qcache_traverse(qcache_dropped);
984 case 't': return qcache_traverse(qcache_testing_only);
985 case 's': return qcache_traverse(qcache_stats);
986 case 'a': return qcache_traverse(qcache_all);
987 case 'n': return qcache_traverse(qcache_not);
988 }
989
990 qcache_free();
991 qcache_usage(EXIT_FAILURE);
992 return EXIT_FAILURE;
993 }
994
995 #else
996 DEFINE_APPLET_STUB(qcache)
997 #endif

  ViewVC Help
Powered by ViewVC 1.1.20