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

Contents of /portage-utils/qcache.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.41 - (show annotations) (download) (as text)
Sun Oct 28 04:16:19 2012 UTC (21 months ago) by vapier
Branch: MAIN
Changes since 1.40: +15 -15 lines
File MIME type: text/x-csrc
kill off more spurious/useless parens

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.40 2012/08/13 22:23:35 robbat2 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.40 2012/08/13 22:23:35 robbat2 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 len = sizeof(*ret) + s.st_size + 1;
346 ret = xzalloc(len);
347
348 while (getline(&buf, &buflen, f) != -1) {
349 if ((ptr = strrchr(buf, '\n')) != NULL)
350 *ptr = 0;
351
352 if (strncmp(buf, "DEPEND=", 7) == 0)
353 ret->DEPEND = xstrdup(buf + 7);
354
355 if (strncmp(buf, "DESCRIPTION=", 12) == 0)
356 ret->DESCRIPTION = xstrdup(buf + 12);
357
358 if (strncmp(buf, "HOMEPAGE=", 9) == 0)
359 ret->HOMEPAGE = xstrdup(buf + 9);
360
361 if (strncmp(buf, "INHERITED=", 10) == 0)
362 ret->INHERITED = xstrdup(buf + 10);
363
364 if (strncmp(buf, "IUSE=", 4) == 0)
365 ret->IUSE = xstrdup(buf + 4);
366
367 if (strncmp(buf, "KEYWORDS=", 9) == 0)
368 ret->KEYWORDS = xstrdup(buf + 9);
369
370 if (strncmp(buf, "LICENSE=", 8) == 0)
371 ret->LICENSE = xstrdup(buf + 8);
372
373 if (strncmp(buf, "PDEPEND=", 8) == 0)
374 ret->PDEPEND = xstrdup(buf + 8);
375
376 if (strncmp(buf, "PROVIDE=", 8) == 0)
377 ret->PROVIDE = xstrdup(buf + 8);
378
379 if (strncmp(buf, "RDEPEND=", 8) == 0)
380 ret->RDEPEND = xstrdup(buf + 8);
381
382 if (strncmp(buf, "RESTRICT=", 9) == 0)
383 ret->RESTRICT = xstrdup(buf + 9);
384
385 if (strncmp(buf, "SLOT=", 5) == 0)
386 ret->SLOT = xstrdup(buf + 5);
387
388 if (strncmp(buf, "SRC_URI=", 8) == 0)
389 ret->SRC_URI = xstrdup(buf + 8);
390 }
391
392 free(buf);
393 ret->atom = atom_explode(filename);
394 fclose(f);
395
396 return ret;
397
398 err:
399 if (ret)
400 cache_free(ret);
401 return NULL;
402 }
403
404 /*
405 * void qcache_free_data(portage_cache *cache);
406 *
407 * free()'s a portage_cache
408 *
409 * IN:
410 * portage_cache *cache - the portage_cache to be free()'d
411 */
412 void qcache_free_data(portage_cache *cache);
413 void qcache_free_data(portage_cache *cache)
414 {
415 int i;
416 char **c;
417
418 if (!cache)
419 errf("Cache is empty !");
420
421 for (i = 0, c = (char**) cache; i < 15; i++)
422 if (c[i])
423 free(c[i]);
424
425 atom_implode(cache->atom);
426 free(cache);
427 }
428
429 /********************************************************************/
430 /* Comparison functions */
431 /********************************************************************/
432
433 /*
434 * int qcache_vercmp(const void *x, const void *y);
435 *
436 * Compare 2 struct dirent d_name strings based with atom_compare_str().
437 * Used with dirscan() to sort ebuild filenames by version.
438 *
439 * IN:
440 * 2 (const struct dirent **) with d_name filled in
441 * OUT:
442 * -1 (NEWER)
443 * 1 (OLDER)
444 * 0 (SAME)
445 */
446 int qcache_vercmp(const struct dirent **x, const struct dirent **y);
447 int qcache_vercmp(const struct dirent **x, const struct dirent **y)
448 {
449 switch (atom_compare_str((*x)->d_name, (*y)->d_name)) {
450 case NEWER: return -1;
451 case OLDER: return 1;
452 default: return 0;
453 }
454 }
455
456 /********************************************************************/
457 /* Selection functions */
458 /********************************************************************/
459
460 /*
461 * int qcache_file_select(const struct dirent *entry);
462 *
463 * Selects filenames that do not begin with '.' and are not name "metadata.xml"
464 * or that file matches ".cpickle"
465 *
466 * IN:
467 * const struct dirent *entry - entry to check
468 * OUT:
469 * int - 0 if filename begins with '.' or is "metadata.xml", otherwise 1
470 */
471 int qcache_file_select(const struct dirent *entry);
472 int qcache_file_select(const struct dirent *entry)
473 {
474 return !(entry->d_name[0] == '.' || (strcmp(entry->d_name, "metadata.xml") == 0) || (strstr(entry->d_name, ".cpickle") != 0));
475 }
476
477 /*
478 * int qcache_ebuild_select(const struct dirent *entry);
479 *
480 * Select filenames that end in ".ebuild"
481 *
482 * IN:
483 * const struct dirent *entry - entry to check
484 * OUT:
485 * int - 1 if the filename ends in ".ebuild", otherwise 0
486 */
487 int qcache_ebuild_select(const struct dirent *entry);
488 int qcache_ebuild_select(const struct dirent *entry)
489 {
490 return ((strlen(entry->d_name) > 7) && !strcmp(entry->d_name+strlen(entry->d_name)-7, ".ebuild"));
491 }
492
493 /********************************************************************/
494 /* Traversal function */
495 /********************************************************************/
496
497 /*
498 * int qcache_traverse(void (*func)(qcache_data*));
499 *
500 * visit every version of every package of every category in the tree
501 *
502 * IN:
503 * void (*func)(qcache_data*) - function to call
504 * OUT:
505 * int - 0 on success.
506 * ERR:
507 * exit or return -1 on failure.
508 */
509 int qcache_traverse(void (*func)(qcache_data*));
510 int qcache_traverse(void (*func)(qcache_data*))
511 {
512 qcache_data data;
513 char *catpath, *pkgpath, *ebuildpath, *cachepath;
514 int i, j, k, len, num_cat, num_pkg, num_ebuild;
515 struct dirent **categories, **packages, **ebuilds;
516
517 xasprintf(&catpath, "%s%s", QCACHE_EDB, portdir);
518
519 if (-1 == (num_cat = scandir(catpath, &categories, qcache_file_select, alphasort))) {
520 errp("%s", catpath);
521 free(catpath);
522 }
523
524 if (!num_cat)
525 warn("%s is empty!", catpath);
526
527 /* traverse categories */
528 for (i = 0; i < num_cat; i++) {
529 xasprintf(&pkgpath, "%s/%s", portdir, categories[i]->d_name);
530
531 if (-1 == (num_pkg = scandir(pkgpath, &packages, qcache_file_select, alphasort))) {
532 warnp("Found a cache dir, but unable to process %s", pkgpath);
533 free(categories[i]);
534 free(pkgpath);
535 continue;
536 }
537
538 if (qcache_matchcat) {
539 if (strcmp(categories[i]->d_name, qcache_matchcat) != 0) {
540 for (j = 0; j < num_pkg; j++)
541 free(packages[j]);
542 free(categories[i]);
543 free(packages);
544 free(pkgpath);
545 continue;
546 }
547 }
548
549 /* traverse packages */
550 for (j = 0; j < num_pkg; j++) {
551 len = sizeof(char) * (strlen(portdir) + strlen("/") + strlen(categories[i]->d_name) + strlen("/") + strlen(packages[j]->d_name) + 1);
552 ebuildpath = xzalloc(len);
553 snprintf(ebuildpath, len, "%s/%s/%s", portdir, categories[i]->d_name, packages[j]->d_name);
554
555 if (-1 == (num_ebuild = scandir(ebuildpath, &ebuilds, qcache_ebuild_select, qcache_vercmp))) {
556 warnp("%s", ebuildpath);
557 free(packages[i]);
558 free(pkgpath);
559 continue;
560 }
561
562 if (qcache_matchpkg) {
563 if (strcmp(packages[j]->d_name, qcache_matchpkg) != 0) {
564 for (k = 0; k < num_ebuild; k++)
565 free(ebuilds[k]);
566 free(packages[j]);
567 free(ebuilds);
568 free(ebuildpath);
569 continue;
570 }
571 }
572
573 qcache_skip = 0;
574
575 /* traverse ebuilds */
576 for (k = 0; k < num_ebuild; k++) {
577 len = sizeof(char) * (strlen(catpath) + strlen("/") + strlen(categories[i]->d_name) + strlen("/") + strlen(ebuilds[k]->d_name) + 1);
578 cachepath = xzalloc(len);
579 snprintf(cachepath, len, "%s/%s/%s", catpath, categories[i]->d_name, ebuilds[k]->d_name);
580 cachepath[len-8] = '\0'; /* remove ".ebuild" */
581
582 data.category = categories[i]->d_name;
583 data.package = packages[j]->d_name;
584 data.ebuild = ebuilds[k]->d_name;
585 data.cur = k + 1;
586 data.num = num_ebuild;
587 data.cache_data = qcache_read_cache_file(cachepath);
588
589 if (data.cache_data != NULL) {
590 /* is this the last ebuild? */
591 if (i+1 == num_cat && j+1 == num_pkg && k+1 == num_ebuild)
592 qcache_last = 1;
593
594 if (!qcache_skip)
595 func(&data);
596
597 qcache_free_data(data.cache_data);
598 } else
599 warn("unable to read cache '%s'\n\tperhaps you need to `emerge --metadata` or `emerge --regen` ?", cachepath);
600
601 free(ebuilds[k]);
602 free(cachepath);
603 }
604
605 free(packages[j]);
606 free(ebuilds);
607 free(ebuildpath);
608 }
609
610 free(categories[i]);
611 free(packages);
612 free(pkgpath);
613 }
614
615 free(categories);
616 free(catpath);
617
618 return 0;
619 }
620
621 /********************************************************************/
622 /* functors */
623 /********************************************************************/
624
625 void qcache_imlate(qcache_data *data);
626 void qcache_imlate(qcache_data *data)
627 {
628 int *keywords;
629 int a;
630
631 keywords = xmalloc(sizeof(*keywords) * archlist_count);
632
633 if (read_keywords(data->cache_data->KEYWORDS, keywords) < 0) {
634 warn("Failed to read keywords for %s%s/%s%s%s", BOLD, data->category, BLUE, data->ebuild, NORM);
635 free(keywords);
636 return;
637 }
638
639 switch (keywords[qcache_test_arch]) {
640 case stable:
641 qcache_skip = 1;
642 case none:
643 case minus:
644 break;
645
646 default:
647 for (a = 0; a < archlist_count && !qcache_skip; ++a) {
648 if (keywords[a] != stable)
649 continue;
650 qcache_skip = 1;
651 print_keywords(data->category, data->ebuild, keywords);
652 }
653 }
654 free(keywords);
655 }
656
657 void qcache_not(qcache_data *data);
658 void qcache_not(qcache_data *data)
659 {
660 int *keywords;
661
662 keywords = xmalloc(sizeof(*keywords) * archlist_count);
663
664 if (read_keywords(data->cache_data->KEYWORDS, keywords) < 0) {
665 warn("Failed to read keywords for %s%s/%s%s%s", BOLD, data->category, BLUE, data->ebuild, NORM);
666 free(keywords);
667 return;
668 }
669
670 if (keywords[qcache_test_arch] == testing || keywords[qcache_test_arch] == stable) {
671 qcache_skip = 1;
672 } else if (data->cur == data->num) {
673 printf("%s%s/%s%s%s\n", BOLD, data->category, BLUE, data->package, NORM);
674 }
675
676 free(keywords);
677 }
678
679 void qcache_all(qcache_data *data);
680 void qcache_all(qcache_data *data)
681 {
682 int *keywords;
683
684 keywords = xmalloc(sizeof(*keywords) * archlist_count);
685
686 if (read_keywords(data->cache_data->KEYWORDS, keywords) < 0) {
687 warn("Failed to read keywords for %s%s/%s%s%s", BOLD, data->category, BLUE, data->ebuild, NORM);
688 free(keywords);
689 return;
690 }
691
692 if (keywords[qcache_test_arch] == stable || keywords[qcache_test_arch] == testing) {
693 qcache_skip = 1;
694 printf("%s%s/%s%s%s\n", BOLD, data->category, BLUE, data->package, NORM);
695 }
696
697 free(keywords);
698 }
699
700 void qcache_dropped(qcache_data *data);
701 void qcache_dropped(qcache_data *data)
702 {
703 static int possible = 0;
704 int *keywords, i;
705
706 if (data->cur == 1)
707 possible = 0;
708
709 keywords = xmalloc(sizeof(*keywords) * archlist_count);
710
711 if (read_keywords(data->cache_data->KEYWORDS, keywords) < 0) {
712 warn("Failed to read keywords for %s%s/%s%s%s", BOLD, data->category, BLUE, data->ebuild, NORM);
713 free(keywords);
714 return;
715 }
716
717 if (keywords[qcache_test_arch] == testing || keywords[qcache_test_arch] == stable) {
718 qcache_skip = 1;
719
720 if (possible) {
721 printf("%s%s/%s%s%s\n", BOLD, data->category, BLUE, data->package, NORM);
722 }
723
724 free(keywords);
725 return;
726 }
727
728 if (!possible) {
729 /* don't count newer versions with "-*" keywords */
730 for (i = 0; i < archlist_count; ++i) {
731 if (keywords[i] == stable || keywords[i] == testing) {
732 possible = 1;
733 break;
734 }
735 }
736 }
737
738 free(keywords);
739 }
740
741 void qcache_stats(qcache_data *data);
742 void qcache_stats(qcache_data *data)
743 {
744 static time_t runtime;
745 static int numpkg = 0;
746 static int numebld = 0;
747 static int numcat;
748 static int *packages_stable;
749 static int *packages_testing;
750 static int *current_package_keywords;
751 static int *keywords;
752 int a, i;
753
754 if (!numpkg) {
755 struct dirent **categories;
756 char *catpath;
757 int len;
758
759 len = sizeof(char) * (strlen(QCACHE_EDB) + strlen(portdir) + 1);
760 catpath = xzalloc(len);
761 snprintf(catpath, len, "%s%s", QCACHE_EDB, portdir);
762
763 if (-1 == (numcat = scandir(catpath, &categories, qcache_file_select, alphasort))) {
764 errp("%s", catpath);
765 free(catpath);
766 }
767
768 for (i = 0; i < numcat; i++)
769 free(categories[i]);
770 free(categories);
771
772 runtime = time(NULL);
773
774 packages_stable = xcalloc(archlist_count, sizeof(*packages_stable));
775 packages_testing = xcalloc(archlist_count, sizeof(*packages_testing));
776 keywords = xcalloc(archlist_count, sizeof(*keywords));
777 current_package_keywords = xcalloc(archlist_count, sizeof(*current_package_keywords));
778 }
779
780 if (data->cur == 1) {
781 numpkg++;
782 memset(current_package_keywords, 0, archlist_count * sizeof(*current_package_keywords));
783 }
784 ++numebld;
785
786 memset(keywords, 0, archlist_count * sizeof(*keywords));
787 if (read_keywords(data->cache_data->KEYWORDS, keywords) < 0) {
788 warn("Failed to read keywords for %s%s/%s%s%s", BOLD, data->category, BLUE, data->ebuild, NORM);
789 free(keywords);
790 return;
791 }
792
793 for (a = 0; a < archlist_count; ++a) {
794 switch (keywords[a]) {
795 case stable:
796 current_package_keywords[a] = stable;
797 break;
798 case testing:
799 if (current_package_keywords[a] != stable)
800 current_package_keywords[a] = testing;
801 default:
802 break;
803 }
804 }
805
806 if (data->cur == data->num) {
807 for (a = 0; a < archlist_count; ++a) {
808 switch (current_package_keywords[a]) {
809 case stable:
810 packages_stable[a]++;
811 break;
812 case testing:
813 packages_testing[a]++;
814 default:
815 break;
816 }
817 }
818 }
819
820 if (qcache_last) {
821 printf("+-------------------------+\n");
822 printf("| general statistics |\n");
823 printf("+-------------------------+\n");
824 printf("| %s%13s%s | %s%7d%s |\n", GREEN, "architectures", NORM, BLUE, archlist_count, NORM);
825 printf("| %s%13s%s | %s%7d%s |\n", GREEN, "categories", NORM, BLUE, numcat, NORM);
826 printf("| %s%13s%s | %s%7d%s |\n", GREEN, "packages", NORM, BLUE, numpkg, NORM);
827 printf("| %s%13s%s | %s%7d%s |\n", GREEN, "ebuilds", NORM, BLUE, numebld, NORM);
828 printf("+-------------------------+\n\n");
829
830 printf("+----------------------------------------------------------+\n");
831 printf("| keyword distribution |\n");
832 printf("+----------------------------------------------------------+\n");
833 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);
834 printf("| | |%s%8s%s | | |\n", RED, "only", NORM);
835 printf("+----------------------------------------------------------+\n");
836
837 for (a = 0; a < archlist_count; ++a) {
838 printf("| %s%12s%s |", GREEN, archlist[a], NORM);
839 printf("%s%8d%s |", BLUE, packages_stable[a], NORM);
840 printf("%s%8d%s |", BLUE, packages_testing[a], NORM);
841 printf("%s%8d%s |", BLUE, packages_testing[a]+packages_stable[a], NORM);
842 printf("%s%11.2f%s%% |\n", BLUE, (100.0*(packages_testing[a]+packages_stable[a]))/numpkg, NORM);
843 }
844
845 printf("+----------------------------------------------------------+\n\n");
846
847 printf("Completed in %s%d%s seconds.\n", BLUE, (int)(time(NULL)-runtime), NORM);
848
849 free(packages_stable);
850 free(packages_testing);
851 free(keywords);
852 free(current_package_keywords);
853 }
854 }
855
856 void qcache_testing_only(qcache_data *data);
857 void qcache_testing_only(qcache_data *data)
858 {
859 static int possible = 0;
860 int *keywords;
861
862 if (data->cur == 1)
863 possible = 0;
864
865 keywords = xmalloc(sizeof(*keywords) * archlist_count);
866
867 if (read_keywords(data->cache_data->KEYWORDS, keywords) < 0) {
868 warn("Failed to read keywords for %s%s/%s%s%s", BOLD, data->category, BLUE, data->ebuild, NORM);
869 free(keywords);
870 return;
871 }
872
873 if (keywords[qcache_test_arch] == stable) {
874 qcache_skip = 1;
875 free(keywords);
876 return;
877 }
878
879 /* the qcache_test_arch must have at least 1 ~arch keyword */
880 if (keywords[qcache_test_arch] == testing)
881 possible = 1;
882
883 if (data->cur == data->num && possible) {
884 printf("%s%s/%s%s%s\n", BOLD, data->category, BLUE, data->package, NORM);
885 }
886
887 free(keywords);
888 }
889
890 /********************************************************************/
891 /* Misc functions */
892 /********************************************************************/
893
894 /*
895 * int qcache_init();
896 *
897 * Initialize variables (archlist, num_arches)
898 *
899 * OUT:
900 * 0 is return on success.
901 * ERR:
902 * -1 is returned on error.
903 */
904 int qcache_init();
905 int qcache_init()
906 {
907 char *filename;
908 unsigned int len;
909
910 len = sizeof(char) * (strlen(portdir) + strlen("/profiles/arch.list") + 1);
911 filename = xzalloc(len);
912
913 snprintf(filename, len, "%s/profiles/arch.list", portdir);
914
915 if (NULL == (archlist = qcache_read_lines(filename))) {
916 free(filename);
917 return -1;
918 }
919
920 len = 0;
921 while (archlist[len])
922 ++len;
923 archlist_count = len;
924
925 free(filename);
926 return 0;
927 }
928
929 /*
930 * int qcache_free();
931 *
932 * Deallocate variables (archlist)
933 */
934 void qcache_free();
935 void qcache_free()
936 {
937 qcache_free_lines(archlist);
938 }
939
940 /********************************************************************/
941 /* main */
942 /********************************************************************/
943
944 int qcache_main(int argc, char **argv)
945 {
946 int i, action = 0;
947
948 DBG("argc=%d argv[0]=%s argv[1]=%s",
949 argc, argv[0], argc > 1 ? argv[1] : "NULL?");
950
951 while ((i = GETOPT_LONG(QCACHE, qcache, "")) != -1) {
952 switch (i) {
953 case 'p': qcache_matchpkg = optarg; break;
954 case 'c': qcache_matchcat = optarg; break;
955 case 'i':
956 case 'd':
957 case 't':
958 case 's':
959 case 'a':
960 case 'n':
961 if (action)
962 qcache_usage(EXIT_FAILURE); /* trying to use more than 1 action */
963 action = i;
964 break;
965
966 COMMON_GETOPTS_CASES(qcache)
967 }
968 }
969
970 if (-1 == qcache_init())
971 err("Could not initialize arch list");
972
973 if (optind < argc)
974 qcache_test_arch = decode_arch(argv[optind]);
975
976 if ((qcache_test_arch == -1 && action != 's') || optind + 1 < argc)
977 qcache_usage(EXIT_FAILURE);
978
979 switch (action) {
980 case 'i': return qcache_traverse(qcache_imlate);
981 case 'd': return qcache_traverse(qcache_dropped);
982 case 't': return qcache_traverse(qcache_testing_only);
983 case 's': return qcache_traverse(qcache_stats);
984 case 'a': return qcache_traverse(qcache_all);
985 case 'n': return qcache_traverse(qcache_not);
986 }
987
988 qcache_free();
989 qcache_usage(EXIT_FAILURE);
990 return EXIT_FAILURE;
991 }
992
993 #else
994 DEFINE_APPLET_STUB(qcache)
995 #endif

  ViewVC Help
Powered by ViewVC 1.1.20