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

Contents of /portage-utils/qcache.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.48 - (show annotations) (download) (as text)
Tue Feb 18 07:30:30 2014 UTC (2 months ago) by vapier
Branch: MAIN
Changes since 1.47: +28 -27 lines
File MIME type: text/x-csrc
qcache: mark everything static

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

  ViewVC Help
Powered by ViewVC 1.1.20