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: /, tests/qlop/, man/include/, man/
Date: Wed, 27 Feb 2019 20:53:43
Message-Id: 1551300621.c74a5abf3fd8db03adb531f95ecff5316d997ab3.grobian@gentoo
1 commit: c74a5abf3fd8db03adb531f95ecff5316d997ab3
2 Author: Fabian Groffen <grobian <AT> gentoo <DOT> org>
3 AuthorDate: Wed Feb 27 20:41:45 2019 +0000
4 Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org>
5 CommitDate: Wed Feb 27 20:50:21 2019 +0000
6 URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=c74a5abf
7
8 qlop: rewrite from scratch
9
10 This new implementation achieves a few things:
11 - unified code path for all modes of operation (thus consistent results)
12 - more flexibility to implement new features
13 - simplification of the codebase
14
15 Short version of what this commit changes:
16 - existing flags -t -g have been replaced with -a and -t
17 - -c has been been replaced with -r and no longer uses proc processing
18 code (thus works everywhere)
19 - addition of an ETA for running emerges (subject to improvements)
20 - allow reading a file of atoms (e.g. /var/lib/portage/world)
21 - summary mode -c to compute grand total, e.g. to compute world compile
22 time
23
24 Bug: https://bugs.gentoo.org/161244
25 Bug: https://bugs.gentoo.org/603024
26 Bug: https://bugs.gentoo.org/636334
27 Bug: https://bugs.gentoo.org/658824
28 Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org>
29
30 man/include/qlop.desc | 25 +-
31 man/include/qlop.optdesc.yaml | 23 +-
32 man/qlop.1 | 66 +-
33 qlop.c | 1479 +++++++++++++++++++++--------------------
34 tests/qlop/dotest | 20 +-
35 tests/qlop/list01.good | 4 +-
36 tests/qlop/list02.good | 6 +-
37 tests/qlop/list03.good | 8 +-
38 tests/qlop/list04.good | 2 +-
39 tests/qlop/list05.good | 2 +-
40 tests/qlop/list06.good | 4 +-
41 tests/qlop/list07.good | 4 +-
42 tests/qlop/list08.good | 4 +-
43 tests/qlop/list09.good | 6 +-
44 14 files changed, 892 insertions(+), 761 deletions(-)
45
46 diff --git a/man/include/qlop.desc b/man/include/qlop.desc
47 index d99cc94..0c14e00 100644
48 --- a/man/include/qlop.desc
49 +++ b/man/include/qlop.desc
50 @@ -1,4 +1,25 @@
51 .I qlop
52 reads from $EMERGE_LOG_DIR/emerge.log and tries to extract
53 -information about merges, unmerges and syncs. For packages, it can
54 -calculate average merge times or just list them.
55 +information about merges, unmerges and syncs. It can
56 +calculate average merge times or just list them. When given no
57 +arguments or just \fB-v\fR, \fIqlop\fR acts as if \fB-must\fR was given
58 +and thus lists the time taken for all occurrances of merges, unmerges
59 +and sync operations found in the log.
60 +.P
61 +By default, packages are printed as CATEGORY/PN. Use \fB-v\fR to print
62 +the package version and revision numbers, e.g\. CATEGORY/PF. Note that
63 +when using this option, averages (\fB-a\fR) are reported per version
64 +instead of per package.
65 +.P
66 +The non-option arguments to \fIqlop\fR can be any valid atoms. Multiple
67 +can be given to match. Since all of these are treated as atoms, version
68 +specifications can be used such as \fB<bash-5\fR. This allows to zoom
69 +in further on specific packages.
70 +.P
71 +After version \fB0.74\fR of portage-utils, \fIqlop\fR was changed
72 +considerably to be more consistent and more advanced. Most notably,
73 +this has changed default date output and commmand line flags. Instead
74 +of reporting the time the operation finished, \fIqlop\fR now reports the
75 +time the operation started. The behaviour of the old \fB-q\fR flag is
76 +best matched by the new \fB-t\fR flag. Similar, the old \fB-t\fR flag
77 +is matched by the new \fB-a\fR flag.
78
79 diff --git a/man/include/qlop.optdesc.yaml b/man/include/qlop.optdesc.yaml
80 index 3ff62c3..a8fae61 100644
81 --- a/man/include/qlop.optdesc.yaml
82 +++ b/man/include/qlop.optdesc.yaml
83 @@ -18,18 +18,27 @@ date: |
84 .IP FORMAT|DATE
85 Use \fIFORMAT\fR as input for \fBstrptime\fR(3) to parse \fIDATE\fR.
86 .RE
87 -gauge: |
88 - Gauge number of times a package has been merged. This shows the
89 - merge time for each individual merge of package.
90 time: |
91 - Calculate merge time for a specific package. This is the average
92 - time for all merges of package.
93 + Show the time it took to merge, unmerge or sync.
94 +average: |
95 + Calculate average merge, unmerge or sync time. This is the average
96 + time for all occurrences found respecting any date limits.
97 +summary: |
98 + Show a grand total for averages. This option implies \fB-a\fR.
99 + Useful to compute time it takes to recompile all packages or a set
100 + of packages (e.g\. world).
101 human: |
102 - Print seconds in human readable format (needs \fB\-t\fR), using
103 + Print elapssed time in human readable format. This form uses
104 minutes, hours and days instead of just seconds.
105 current: |
106 Show current emerging packages. This relies on
107 .I FEATURES=sandbox
108 in order to detect running merges.
109 verbose: |
110 - Print package versions and revisions.
111 + Print package versions and revisions (PF) instead of package (PN).
112 +running: |
113 + Print operations currently in progress. An ETA is calculated based
114 + on the average for the operation. If the elapsed exceeds the
115 + average, the ETA is calculated against the longest time observed for
116 + the operation. If the elapsed time exceeds this too, or no previous
117 + occurrences for the operation exist, \fIunknown\fR is printed.
118
119 diff --git a/man/qlop.1 b/man/qlop.1
120 index bdfe3af..46a6f94 100644
121 --- a/man/qlop.1
122 +++ b/man/qlop.1
123 @@ -8,35 +8,68 @@ qlop \- emerge log analyzer
124 .SH DESCRIPTION
125 .I qlop
126 reads from $EMERGE_LOG_DIR/emerge.log and tries to extract
127 -information about merges, unmerges and syncs. For packages, it can
128 -calculate average merge times or just list them.
129 +information about merges, unmerges and syncs. It can
130 +calculate average merge times or just list them. When given no
131 +arguments or just \fB-v\fR, \fIqlop\fR acts as if \fB-must\fR was given
132 +and thus lists the time taken for all occurrances of merges, unmerges
133 +and sync operations found in the log.
134 +.P
135 +By default, packages are printed as CATEGORY/PN. Use \fB-v\fR to print
136 +the package version and revision numbers, e.g\. CATEGORY/PF. Note that
137 +when using this option, averages (\fB-a\fR) are reported per version
138 +instead of per package.
139 +.P
140 +The non-option arguments to \fIqlop\fR can be any valid atoms. Multiple
141 +can be given to match. Since all of these are treated as atoms, version
142 +specifications can be used such as \fB<bash-5\fR. This allows to zoom
143 +in further on specific packages.
144 +.P
145 +After version \fB0.74\fR of portage-utils, \fIqlop\fR was changed
146 +considerably to be more consistent and more advanced. Most notably,
147 +this has changed default date output and commmand line flags. Instead
148 +of reporting the time the operation finished, \fIqlop\fR now reports the
149 +time the operation started. The behaviour of the old \fB-q\fR flag is
150 +best matched by the new \fB-t\fR flag. Similar, the old \fB-t\fR flag
151 +is matched by the new \fB-a\fR flag.
152 .SH OPTIONS
153 .TP
154 -\fB\-g\fR, \fB\-\-gauge\fR
155 -Gauge number of times a package has been merged. This shows the
156 -merge time for each individual merge of package.
157 +\fB\-c\fR, \fB\-\-summary\fR
158 +Show a grand total for averages. This option implies \fB-a\fR.
159 +Useful to compute time it takes to recompile all packages or a set
160 +of packages (e.g\. world).
161 .TP
162 \fB\-t\fR, \fB\-\-time\fR
163 -Calculate merge time for a specific package. This is the average
164 -time for all merges of package.
165 +Show the time it took to merge, unmerge or sync.
166 +.TP
167 +\fB\-a\fR, \fB\-\-average\fR
168 +Calculate average merge, unmerge or sync time. This is the average
169 +time for all occurrences found respecting any date limits.
170 .TP
171 \fB\-H\fR, \fB\-\-human\fR
172 -Print seconds in human readable format (needs \fB\-t\fR), using
173 +Print elaspsed time in human readable format. This form uses
174 minutes, hours and days instead of just seconds.
175 .TP
176 -\fB\-l\fR, \fB\-\-list\fR
177 +\fB\-m\fR, \fB\-\-merge\fR
178 Show merge history.
179 .TP
180 -\fB\-u\fR, \fB\-\-unlist\fR
181 +\fB\-u\fR, \fB\-\-unmerge\fR
182 Show unmerge history.
183 .TP
184 +\fB\-U\fR, \fB\-\-autoclean\fR
185 +Show autoclean unmerge history.
186 +.TP
187 \fB\-s\fR, \fB\-\-sync\fR
188 Show sync history.
189 .TP
190 -\fB\-c\fR, \fB\-\-current\fR
191 -Show current emerging packages. This relies on
192 -.I FEATURES=sandbox
193 -in order to detect running merges.
194 +\fB\-e\fR, \fB\-\-endtime\fR
195 +Report time at which the operation finished (iso started).
196 +.TP
197 +\fB\-r\fR, \fB\-\-running\fR
198 +Print operations currently in progress. An ETA is calculated based
199 +on the average for the operation. If the elapsed exceeds the
200 +average, the ETA is calculated against the longest time observed for
201 +the operation. If the elapsed time exceeds this too, or no previous
202 +occurrences for the operation exist, \fIunknown\fR is printed.
203 .TP
204 \fB\-d\fR \fI<arg>\fR, \fB\-\-date\fR \fI<arg>\fR
205 Limit the selection of packages to the date given, or to the range
206 @@ -62,11 +95,14 @@ Use \fIFORMAT\fR as input for \fBstrptime\fR(3) to parse \fIDATE\fR.
207 \fB\-f\fR \fI<arg>\fR, \fB\-\-logfile\fR \fI<arg>\fR
208 Read emerge logfile instead of $EMERGE_LOG_DIR/emerge.log.
209 .TP
210 +\fB\-w\fR \fI<arg>\fR, \fB\-\-atoms\fR \fI<arg>\fR
211 +Read package atoms to report from file.
212 +.TP
213 \fB\-\-root\fR \fI<arg>\fR
214 Set the ROOT env var.
215 .TP
216 \fB\-v\fR, \fB\-\-verbose\fR
217 -Print package versions and revisions.
218 +Print package versions and revisions (PF) instead of package (PN).
219 .TP
220 \fB\-q\fR, \fB\-\-quiet\fR
221 Tighter output; suppress warnings.
222
223 diff --git a/qlop.c b/qlop.c
224 index a042fa7..26b27b2 100644
225 --- a/qlop.c
226 +++ b/qlop.c
227 @@ -1,38 +1,47 @@
228 /*
229 - * Copyright 2005-2018 Gentoo Foundation
230 + * Copyright 2005-2019 Gentoo Foundation
231 * Distributed under the terms of the GNU General Public License v2
232 *
233 * Copyright 2005-2010 Ned Ludd - <solar@g.o>
234 * Copyright 2005-2014 Mike Frysinger - <vapier@g.o>
235 + * Copyright 2018- Fabian Groffen - <grobian@g.o>
236 */
237
238 #ifdef APPLET_qlop
239
240 #define QLOP_DEFAULT_LOGFILE "emerge.log"
241
242 -#define QLOP_FLAGS "gtHluscd:f:" COMMON_FLAGS
243 +#define QLOP_FLAGS "ctaHmuUserd:f:w:" COMMON_FLAGS
244 static struct option const qlop_long_opts[] = {
245 - {"gauge", no_argument, NULL, 'g'},
246 + {"summary", no_argument, NULL, 'c'},
247 {"time", no_argument, NULL, 't'},
248 + {"average", no_argument, NULL, 'a'},
249 {"human", no_argument, NULL, 'H'},
250 - {"list", no_argument, NULL, 'l'},
251 - {"unlist", no_argument, NULL, 'u'},
252 + {"merge", no_argument, NULL, 'm'},
253 + {"unmerge", no_argument, NULL, 'u'},
254 + {"autoclean", no_argument, NULL, 'U'},
255 {"sync", no_argument, NULL, 's'},
256 - {"current", no_argument, NULL, 'c'},
257 + {"endtime", no_argument, NULL, 'e'},
258 + {"running", no_argument, NULL, 'r'},
259 {"date", a_argument, NULL, 'd'},
260 {"logfile", a_argument, NULL, 'f'},
261 + {"atoms", a_argument, NULL, 'w'},
262 COMMON_LONG_OPTS
263 };
264 static const char * const qlop_opts_help[] = {
265 - "Gauge number of times a package has been merged",
266 - "Calculate merge time for a specific package",
267 - "Print seconds in human readable format (needs -t)",
268 + "Print summary of average merges (implies -a)",
269 + "Print time taken to complete action",
270 + "Print average time taken to complete action",
271 + "Print elapsed time in human readable format (use with -t or -a)",
272 "Show merge history",
273 "Show unmerge history",
274 + "Show autoclean unmerge history",
275 "Show sync history",
276 + "Report time at which the operation finished (iso started)",
277 "Show current emerging packages",
278 "Limit selection to this time (1st -d is start, 2nd -d is end)",
279 "Read emerge logfile instead of $EMERGE_LOG_DIR/" QLOP_DEFAULT_LOGFILE,
280 + "Read package atoms to report from file",
281 COMMON_OPTS_HELP
282 };
283 static const char qlop_desc[] =
284 @@ -44,672 +53,18 @@ static const char qlop_desc[] =
285 " -d '%d.%m.%Y|25.12.2015' (format is specified)";
286 #define qlop_usage(ret) usage(ret, QLOP_FLAGS, qlop_long_opts, qlop_opts_help, qlop_desc, lookup_applet_idx("qlop"))
287
288 -#define QLOP_LIST 0x01
289 -#define QLOP_UNLIST 0x02
290 -
291 -static void
292 -print_seconds_for_earthlings(const unsigned long t)
293 -{
294 - unsigned dd, hh, mm, ss;
295 - unsigned long tt = t;
296 - ss = tt % 60; tt /= 60;
297 - mm = tt % 60; tt /= 60;
298 - hh = tt % 24; tt /= 24;
299 - dd = tt;
300 - if (dd) printf("%s%u%s day%s, ", GREEN, dd, NORM, (dd == 1 ? "" : "s"));
301 - if (hh) printf("%s%u%s hour%s, ", GREEN, hh, NORM, (hh == 1 ? "" : "s"));
302 - if (mm) printf("%s%u%s minute%s, ", GREEN, mm, NORM, (mm == 1 ? "" : "s"));
303 - printf("%s%u%s second%s", GREEN, ss, NORM, (ss == 1 ? "" : "s"));
304 -}
305 -
306 -static const char *
307 -chop_ctime(time_t t)
308 -{
309 - static char ctime_out[50];
310 - int ret = snprintf(ctime_out, sizeof(ctime_out), "%s", ctime(&t));
311 - /* Assume no error! */
312 - ctime_out[ret - 1] = '\0';
313 - return ctime_out;
314 -}
315 -
316 -static unsigned long
317 -show_merge_times(char *package, const char *logfile, int average, char human_readable,
318 - time_t start_time, time_t end_time)
319 -{
320 - FILE *fp;
321 - char cat[126], buf[2][BUFSIZ];
322 - char *pkg, *p, *q;
323 - char ep[BUFSIZ];
324 - unsigned long count, merge_time;
325 - time_t t[2];
326 - depend_atom *atom;
327 - unsigned int parallel_emerge;
328 -
329 - t[0] = t[1] = 0UL;
330 - count = merge_time = 0;
331 - cat[0] = 0;
332 -
333 - /* setup cat and pkg vars */
334 - if ((p = strchr(package, '/')) != NULL) {
335 - pkg = p + 1;
336 - strncpy(cat, package, sizeof(cat));
337 - if ((p = strchr(cat, '/')) != NULL)
338 - *p = 0;
339 - } else {
340 - pkg = package;
341 - }
342 -
343 - if ((fp = fopen(logfile, "r")) == NULL) {
344 - warnp("Could not open logfile '%s'", logfile);
345 - return 1;
346 - }
347 -
348 - /* loop over lines searching for cat/pkg */
349 - parallel_emerge = 0;
350 - while (fgets(buf[0], sizeof(buf[0]), fp) != NULL) {
351 - if ((p = strchr(buf[0], '\n')) != NULL)
352 - *p = '\0';
353 - if ((p = strchr(buf[0], ':')) == NULL)
354 - continue;
355 - *p++ = '\0';
356 - if (strstr(p, pkg) == NULL)
357 - continue;
358 -
359 - t[0] = atol(buf[0]);
360 - if (t[0] < start_time || t[0] > end_time)
361 - continue;
362 -
363 - /* copy message (stripping timestamp) */
364 - strncpy(buf[1], p, BUFSIZ);
365 - rmspace(buf[1]);
366 -
367 - if (strncmp(buf[1], "Started emerge on:", 18) == 0) {
368 - /* a parallel emerge was launched */
369 - parallel_emerge++;
370 - continue;
371 - }
372 -
373 - if (strncmp(buf[1], "*** terminating.", 16) == 0) {
374 - if (parallel_emerge > 0) {
375 - /* a parallel emerge has finished */
376 - parallel_emerge--;
377 - continue;
378 - } else {
379 - /* the main emerge was stopped? if there's more lines
380 - * this file is just corrupt or truncated at the front */
381 - continue;
382 - }
383 - }
384 -
385 - if (strncmp(buf[1], ">>> emerge (", 12) == 0) {
386 - /* construct the matching end marker */
387 - snprintf(ep, BUFSIZ, "completed %s", &buf[1][4]);
388 -
389 - /* skip over "(X of Y)" */
390 - if ((p = strchr(buf[1], ')')) == NULL) {
391 - *ep = '\0';
392 - continue;
393 - }
394 - *p++ = '\0';
395 -
396 - /* get the package as atom */
397 - strncpy(buf[0], p, BUFSIZ);
398 - rmspace(buf[0]);
399 - if ((p = strchr(buf[0], ' ')) == NULL) {
400 - *ep = '\0';
401 - continue;
402 - }
403 - *p = '\0';
404 - if ((atom = atom_explode(buf[0])) == NULL) {
405 - *ep = '\0';
406 - continue;
407 - }
408 -
409 - /* match atom against our search */
410 - if ((*cat && ((strcmp(cat, atom->CATEGORY) == 0) &&
411 - (strcmp(pkg, atom->PN) == 0))) ||
412 - (strcmp(pkg, atom->PN) == 0))
413 - {
414 - while (fgets(buf[0], sizeof(buf[0]), fp) != NULL) {
415 - if ((p = strchr(buf[0], '\n')) != NULL)
416 - *p = '\0';
417 - if ((p = strchr(buf[0], ':')) == NULL)
418 - continue;
419 - *p++ = '\0';
420 -
421 - t[1] = atol(buf[0]);
422 - strcpy(buf[1], p);
423 - rmspace(buf[1]);
424 -
425 - if (strncmp(buf[1], "Started emerge on:", 18) == 0) {
426 - /* a parallel emerge was launched */
427 - parallel_emerge++;
428 - continue;
429 - }
430 -
431 - if (strncmp(buf[1], "*** terminating.", 16) == 0) {
432 - if (parallel_emerge > 0) {
433 - /* a parallel emerge has finished */
434 - parallel_emerge--;
435 - continue;
436 - } else {
437 - /* the main emerge was stopped? if there's
438 - * more lines this file is just corrupt or
439 - * truncated at the front */
440 - break;
441 - }
442 - }
443 -
444 - /* pay attention to malformed log files (when the
445 - * end of an emerge process is not indicated by the
446 - * line '*** terminating'). We assume that the log
447 - * is malformed when we find a parallel emerge
448 - * process which is trying to emerge the same
449 - * package
450 - */
451 - if (strncmp(buf[1], ">>> emerge (", 12) == 0 &&
452 - parallel_emerge > 0)
453 - {
454 - /* find package name */
455 - p = strchr(buf[1], ')');
456 - q = strchr(ep, ')');
457 - if (!p || !q)
458 - continue;
459 -
460 - /* is this emerge doing the same thing as we're
461 - * looking for? that means we failed */
462 - if (strcmp(p, q) == 0) {
463 - parallel_emerge--;
464 - /* update the main emerge reference data */
465 - snprintf(ep, BUFSIZ, "completed %s", &buf[1][4]);
466 - t[0] = t[1];
467 - continue;
468 - }
469 - }
470 -
471 - /* if this line matches "completed emerge (X of Y) ..."
472 - * we're finally somewhere */
473 - if (strncmp(&buf[1][4], ep, BUFSIZ - 4) == 0) {
474 - if (!average) {
475 - buf[1][0] = '\0';
476 - if (verbose) {
477 - if (atom->PR_int)
478 - snprintf(buf[1], sizeof(buf[1]),
479 - "-%s-r%i", atom->PV, atom->PR_int);
480 - else
481 - snprintf(buf[1], sizeof(buf[1]),
482 - "-%s", atom->PV);
483 - }
484 - printf("%s%s%s%s: %s: ",
485 - BLUE, atom->PN, buf[1], NORM,
486 - chop_ctime(t[0]));
487 - if (human_readable)
488 - print_seconds_for_earthlings(t[1] - t[0]);
489 - else
490 - printf("%s%"PRIu64"%s seconds",
491 - GREEN, (uint64_t)(t[1] - t[0]), NORM);
492 - printf("\n");
493 - }
494 - merge_time += (t[1] - t[0]);
495 - count++;
496 - break;
497 - }
498 - }
499 - }
500 - atom_implode(atom);
501 - }
502 - }
503 - fclose(fp);
504 - if (count == 0)
505 - return 0;
506 - if (average == 1) {
507 - printf("%s%s%s: ", BLUE, pkg, NORM);
508 - if (human_readable)
509 - print_seconds_for_earthlings(merge_time / count);
510 - else
511 - printf("%s%lu%s seconds average", GREEN, merge_time / count, NORM);
512 - printf(" for %s%lu%s merges\n", GREEN, count, NORM);
513 - } else {
514 - printf("%s%s%s: %s%lu%s times\n", BLUE, pkg, NORM, GREEN, count, NORM);
515 - }
516 - return 0;
517 -}
518 -
519 -static void
520 -show_emerge_history(int listflag, array_t *atoms, const char *logfile,
521 - time_t start_time, time_t end_time)
522 -{
523 - FILE *fp;
524 - int linelen;
525 - size_t buflen;
526 - char *buf, merged;
527 - char *p, *q;
528 - bool showit;
529 - size_t i;
530 - time_t t;
531 - depend_atom *atom, *logatom;
532 -
533 - if ((fp = fopen(logfile, "r")) == NULL) {
534 - warnp("Could not open logfile '%s'", logfile);
535 - return;
536 - }
537 -
538 - buf = NULL;
539 - while ((linelen = getline(&buf, &buflen, fp)) >= 0) {
540 - if (linelen < 30)
541 - continue;
542 -
543 - rmspace_len(buf, (size_t)linelen);
544 - if ((p = strchr(buf, ':')) == NULL)
545 - continue;
546 - *p = 0;
547 - q = p + 3;
548 - /* Make sure there's leading white space and not a truncated
549 - * string. #573106 */
550 - if (p[1] != ' ' || p[2] != ' ')
551 - continue;
552 -
553 - t = (time_t) atol(buf);
554 - if (t < start_time || t > end_time)
555 - continue;
556 -
557 - if ((listflag & QLOP_LIST) && !strncmp(q, "::: completed emerge (", 22)) {
558 - merged = 1;
559 - if ((p = strchr(q, ')')) == NULL)
560 - continue;
561 - q = p + 2;
562 - if ((p = strchr(q, ' ')) == NULL)
563 - continue;
564 - *p = 0;
565 - } else if ((listflag & QLOP_UNLIST) && !strncmp(q, ">>> unmerge success: ", 21)) {
566 - merged = 0;
567 - if ((p = strchr(q, ':')) == NULL)
568 - continue;
569 - q = p + 2;
570 - } else
571 - continue;
572 -
573 - logatom = atom_explode(q);
574 - if (array_cnt(atoms)) {
575 - showit = false;
576 - array_for_each(atoms, i, atom)
577 - if (atom_compare(atom, logatom) == EQUAL) {
578 - showit = true;
579 - break;
580 - }
581 - } else
582 - showit = true;
583 -
584 - if (showit) {
585 - if (!quiet)
586 - printf("%s %s %s%s%s\n", chop_ctime(t), (merged ? ">>>" : "<<<"), (merged ? GREEN : RED), q, NORM);
587 - else {
588 - if (quiet == 1)
589 - printf("%s ", chop_ctime(t));
590 - if (quiet <= 2)
591 - printf("%s ", (merged ? ">>>" : "<<<"));
592 - printf("%s%s/%s%s\n", (merged ? GREEN : RED), logatom->CATEGORY, logatom->PN, NORM);
593 - }
594 - }
595 - atom_implode(logatom);
596 - }
597 -
598 - free(buf);
599 - fclose(fp);
600 -}
601 -
602 -/* The format of the sync log has changed over time.
603 -
604 -Old format:
605 -1106804103: Started emerge on: Jan 27, 2005 05:35:03
606 -1106804103: *** emerge sync
607 -1106804103: === sync
608 -1106804103: >>> starting rsync with rsync://192.168.0.5/gentoo-portage
609 -1106804537: === Sync completed with rsync://192.168.0.5/gentoo-portage
610 -1106804538: *** terminating.
611 -
612 -New format:
613 -1431764402: Started emerge on: May 16, 2015 04:20:01
614 -1431764402: *** emerge --quiet --keep-going --verbose --nospinner --oneshot --quiet-build=n --sync
615 -1431764402: === sync
616 -1431764402: >>> Syncing repository 'gentoo' into '/usr/portage'...
617 -1431764402: >>> Starting rsync with rsync://[2a01:90:200:10::1a]/gentoo-portage
618 -1431764460: === Sync completed for gentoo
619 -1431764493: *** terminating.
620 -*/
621 -static void
622 -show_sync_history(const char *logfile, time_t start_time, time_t end_time)
623 -{
624 - FILE *fp;
625 - int linelen;
626 - size_t buflen;
627 - char *buf, *p;
628 - time_t t;
629 -
630 - if ((fp = fopen(logfile, "r")) == NULL) {
631 - warnp("Could not open logfile '%s'", logfile);
632 - return;
633 - }
634 -
635 - buf = NULL;
636 - /* Just find the finish lines. */
637 - while ((linelen = getline(&buf, &buflen, fp)) >= 0) {
638 - /* This cuts out like ~10% of the log. */
639 - if (linelen < 35)
640 - continue;
641 -
642 - /* Make sure there's a timestamp in here. */
643 - if ((p = strchr(buf, ':')) == NULL)
644 - continue;
645 - p += 2;
646 -
647 - if (strncmp(p, "=== Sync completed ", 19) != 0)
648 - continue;
649 - p += 19;
650 -
651 - rmspace_len(buf, (size_t)linelen);
652 -
653 - t = (time_t)atol(buf);
654 - if (t < start_time || t > end_time)
655 - continue;
656 -
657 - if (!strncmp(p, "with ", 5))
658 - p += 5;
659 - else if (!strncmp(p, "for ", 4))
660 - /* This shows just the repo name not the remote host ... */
661 - p += 4;
662 - else
663 - continue;
664 - printf("%s >>> %s%s%s\n", chop_ctime(t), GREEN, p, NORM);
665 - }
666 -
667 - free(buf);
668 - fclose(fp);
669 -}
670 -
671 -static void show_current_emerge(void);
672 -#ifdef __linux__
673 -# include <asm/param.h>
674 -#endif
675 -#if defined __linux__ || defined __GNU__
676 -# include <elf.h>
677 -static unsigned long hz = 0;
678 -static void init_hz(void)
679 -{
680 -#ifdef HZ
681 - hz = HZ;
682 -#endif
683 - /* kernel pushes elf notes onto stack */
684 - unsigned long *elf_note = (unsigned long *)environ;
685 - while (!*elf_note++)
686 - continue;
687 - while (elf_note[0]) {
688 - if (elf_note[0] == AT_CLKTCK) {
689 - hz = elf_note[1];
690 - break;
691 - }
692 - elf_note += 2;
693 - }
694 - if (!hz)
695 - hz = 100;
696 -}
697 -
698 -static char *
699 -root_readlink(const int pid)
700 -{
701 - static char path[_Q_PATH_MAX];
702 - char buf[_Q_PATH_MAX];
703 - memset(&path, 0, sizeof(path));
704 - snprintf(buf, sizeof(buf), "/proc/%d/root", pid);
705 - if (readlink(buf, path, sizeof(path) - 1) == -1)
706 - return NULL;
707 - else
708 - return path;
709 -}
710 -
711 -void show_current_emerge(void)
712 -{
713 - DIR *proc;
714 - struct dirent *de;
715 - pid_t pid;
716 - static char *cmdline, *bufstat;
717 - static size_t cmdline_len, bufstat_len;
718 - char path[50];
719 - char *p, *q;
720 - unsigned long long start_time = 0;
721 - double uptime_secs;
722 - time_t start_date;
723 -
724 - if ((proc = opendir("/proc")) == NULL) {
725 - warnp("Could not open /proc");
726 - return;
727 - }
728 -
729 - if (!hz)
730 - init_hz();
731 -
732 - while ((de = readdir(proc)) != NULL) {
733 -
734 - if ((pid = (pid_t)atol(de->d_name)) == 0)
735 - continue;
736 -
737 - /* portage renames the cmdline so the package name is first */
738 - snprintf(path, sizeof(path), "/proc/%i/cmdline", pid);
739 - if (!eat_file(path, &cmdline, &cmdline_len))
740 - continue;
741 -
742 - if (cmdline[0] == '[' && (p = strchr(cmdline, ']')) != NULL &&
743 - strstr(cmdline, "sandbox") != NULL)
744 - {
745 - *p = '\0';
746 - p = cmdline + 1;
747 - q = p + strlen(p) + 1;
748 -
749 - /* open the stat file to figure out how long we have been running */
750 - snprintf(path, sizeof(path), "/proc/%i/stat", pid);
751 - if (!eat_file(path, &bufstat, &bufstat_len))
752 - continue;
753 -
754 - /* ripped from procps/proc/readproc.c */
755 - if ((q = strchr(bufstat, ')')) == NULL)
756 - continue;
757 - /* grab the start time */
758 - sscanf(q + 2,
759 - "%*c "
760 - "%*d %*d %*d %*d %*d "
761 - "%*u %*u %*u %*u %*u "
762 - "%*u %*u %*u %*u "
763 - "%*d %*d "
764 - "%*d "
765 - "%*d "
766 - "%llu ",
767 - &start_time);
768 - /* get uptime */
769 - if (!eat_file("/proc/uptime", &bufstat, &bufstat_len))
770 - continue;
771 - sscanf(bufstat, "%lf", &uptime_secs);
772 -
773 - /* figure out when this thing started and then show it */
774 - start_date = time(0) - (uptime_secs - (start_time / hz));
775 - printf(
776 - " %s*%s %s%s%s\n"
777 - " started: %s%s%s\n"
778 - " elapsed: ", /*%s%llu%s seconds\n",*/
779 - BOLD, NORM, BLUE, p, NORM,
780 - GREEN, chop_ctime(start_date), NORM);
781 - print_seconds_for_earthlings(uptime_secs - (start_time / hz));
782 - puts(NORM);
783 - p = root_readlink(pid);
784 - if (p && strcmp(p, "/"))
785 - printf(" chroot: %s%s%s\n", GREEN, p, NORM);
786 - }
787 - }
788 -
789 - closedir(proc);
790 -
791 - if (start_time == 0 && verbose)
792 - puts("No emerge processes located");
793 -}
794 -#elif defined(__FreeBSD__)
795 -# include <kvm.h>
796 -# include <sys/param.h>
797 -# include <sys/sysctl.h>
798 -# include <sys/user.h>
799 -void show_current_emerge(void)
800 -{
801 - kvm_t *kd = NULL;
802 - struct kinfo_proc *ip;
803 - int i; int total_processes;
804 - char *p, *q;
805 - time_t start_date = 0;
806 -
807 - if (! (kd = kvm_open("/dev/null", "/dev/null", "/dev/null",
808 - O_RDONLY, "kvm_open")))
809 - {
810 - warnp("Could not open kvm: %s", kvm_geterr(kd));
811 - return;
812 - }
813 -
814 - ip = kvm_getprocs(kd, KERN_PROC_PROC, 0, &total_processes);
815 -
816 - for (i = 0; i < total_processes; i++) {
817 - char **proc_argv = NULL;
818 - char *buf = NULL;
819 -
820 - if (strcmp(ip[i].ki_comm, "sandbox") != 0)
821 - continue;
822 -
823 - proc_argv = kvm_getargv(kd, &(ip[i]), 0);
824 -
825 - if (!proc_argv || (buf = xstrdup(proc_argv[0])) == NULL ||
826 - buf[0] != '[' || (p = strchr(buf, ']')) == NULL) {
827 - free(buf);
828 - continue;
829 - }
830 -
831 - *p = '\0';
832 - p = buf+1;
833 - q = p + strlen(p) + 1;
834 -
835 - printf(
836 - " %s*%s %s%s%s\n"
837 - " started: %s%s%s\n"
838 - " elapsed: ", /*%s%llu%s seconds\n",*/
839 - BOLD, NORM, BLUE, p, NORM,
840 - GREEN, chop_ctime(ip[i].ki_start.tv_sec), NORM);
841 - print_seconds_for_earthlings(time(0) - ip[i].ki_start.tv_sec);
842 - puts(NORM);
843 -
844 - free(buf);
845 - }
846 -
847 - if (start_date == 0 && verbose)
848 - puts("No emerge processes located");
849 -}
850 -#elif defined(__MACH__)
851 -# include <sys/sysctl.h>
852 -void show_current_emerge(void)
853 -{
854 - int mib[3];
855 - size_t size = 0;
856 - struct kinfo_proc *ip, *raip;
857 - int ret, total_processes, i;
858 - char *p, *q;
859 - time_t start_date = 0;
860 - char args[512];
861 -
862 - mib[0] = CTL_KERN;
863 - mib[1] = KERN_PROC;
864 - mib[2] = KERN_PROC_ALL; /* could restrict to _UID (effective uid) */
865 -
866 - /* probe once to get the current size; estimate only, but OS tries
867 - * to round up if it can predict a sudden growth, so optimise below
868 - * for the optimistic case */
869 - ret = sysctl(mib, 3, NULL, &size, NULL, 0);
870 - ip = xmalloc(sizeof(*ip) * size);
871 - while (1) {
872 - ret = sysctl(mib, 3, ip, &size, NULL, 0);
873 - if (ret >= 0 && errno == ENOMEM) {
874 - size += size / 10; /* may be a bit overdone... */
875 - raip = realloc(ip, sizeof(struct kinfo_proc) * size);
876 - if (raip == NULL) {
877 - free(ip);
878 - warnp("Could not extend allocated block to "
879 - "%zd bytes for process information",
880 - sizeof(struct kinfo_proc) * size);
881 - return;
882 - }
883 - ip = raip;
884 - } else if (ret < 0) {
885 - free(ip);
886 - warnp("Could not retrieve process information");
887 - return;
888 - } else {
889 - break;
890 - }
891 - }
892 -
893 - total_processes = size / sizeof(struct kinfo_proc);
894 -
895 - /* initialise mib for argv retrieval calls */
896 - mib[0] = CTL_KERN;
897 - mib[1] = KERN_PROCARGS;
898 -
899 - for (i = 0; i < total_processes; i++) {
900 - char *buf = NULL;
901 - size_t argssize = sizeof(args);
902 -
903 - if (strcmp(ip[i].kp_proc.p_comm, "sandbox") != 0)
904 - continue;
905 -
906 - mib[2] = ip[i].kp_proc.p_pid;
907 - if (sysctl(mib, 3, args, &argssize, NULL, 0) != 0) {
908 - free(ip);
909 - return;
910 - }
911 -
912 - /* this is magic to get back up in the stack where the arguments
913 - * start */
914 - for (buf = args; buf < &args[argssize]; buf++)
915 - if (*buf == '\0')
916 - break;
917 - if (buf == &args[argssize]) {
918 - free(ip);
919 - continue;
920 - }
921 - if ((buf = xstrdup(buf)) == NULL ||
922 - buf[0] != '[' || (p = strchr(buf, ']')) == NULL) {
923 - free(buf);
924 - continue;
925 - }
926 -
927 - *p = '\0';
928 - p = buf+1;
929 - q = p + strlen(p) + 1;
930 -
931 - printf(
932 - " %s*%s %s%s%s\n"
933 - " started: %s%s%s\n"
934 - " elapsed: ", /*%s%llu%s seconds\n",*/
935 - BOLD, NORM, BLUE, p, NORM,
936 - GREEN, chop_ctime(ip[i].kp_proc.p_starttime.tv_sec), NORM);
937 - print_seconds_for_earthlings(time(0) - ip[i].kp_proc.p_starttime.tv_sec);
938 - puts(NORM);
939 -
940 - free(buf);
941 - }
942 -
943 - free(ip);
944 -
945 - if (start_date == 0 && verbose)
946 - puts("No emerge processes located");
947 -}
948 -#else
949 -void show_current_emerge(void)
950 -{
951 - errf("not supported on your OS");
952 -}
953 -#endif
954 +struct qlop_mode {
955 + char do_time:1;
956 + char do_merge:1;
957 + char do_unmerge:1;
958 + char do_autoclean:1;
959 + char do_sync:1;
960 + char do_running:1;
961 + char do_average:1;
962 + char do_summary:1;
963 + char do_human:1;
964 + char do_endtime:1;
965 +};
966
967 static bool
968 parse_date(const char *sdate, time_t *t)
969 @@ -813,33 +168,688 @@ parse_date(const char *sdate, time_t *t)
970 return (*t == -1) ? false : true;
971 }
972
973 +static char _date_buf[48];
974 +static char *fmt_date(struct qlop_mode *flags, time_t ts, time_t te)
975 +{
976 + time_t t;
977 +
978 + t = flags->do_endtime ? te : ts;
979 + strftime(_date_buf, sizeof(_date_buf), "%Y-%m-%dT%H:%M:%S", localtime(&t));
980 + return _date_buf;
981 +}
982 +
983 +static char _elapsed_buf[256];
984 +static char *fmt_elapsedtime(struct qlop_mode *flags, time_t e)
985 +{
986 + if (flags->do_human) {
987 + time_t dd;
988 + time_t hh;
989 + time_t mm;
990 + time_t ss;
991 + size_t bufpos = 0;
992 +
993 + ss = e % 60;
994 + e /= 60;
995 + mm = e % 60;
996 + e /= 60;
997 + hh = e % 24;
998 + e /= 24;
999 + dd = e;
1000 +
1001 + if (dd > 0)
1002 + bufpos += snprintf(_elapsed_buf + bufpos,
1003 + sizeof(_elapsed_buf) - bufpos,
1004 + "%s%zd%s day%s",
1005 + GREEN, (size_t)dd, NORM, dd == 1 ? "" : "s");
1006 + if (hh > 0)
1007 + bufpos += snprintf(_elapsed_buf + bufpos,
1008 + sizeof(_elapsed_buf) - bufpos,
1009 + "%s%s%zd%s hour%s",
1010 + bufpos == 0 ? "" : ", ",
1011 + GREEN, (size_t)hh, NORM, hh == 1 ? "" : "s");
1012 + if (mm > 0)
1013 + bufpos += snprintf(_elapsed_buf + bufpos,
1014 + sizeof(_elapsed_buf) - bufpos,
1015 + "%s%s%zd%s minute%s",
1016 + bufpos == 0 ? "" : ", ",
1017 + GREEN, (size_t)mm, NORM, mm == 1 ? "" : "s");
1018 + if (ss > 0 || (mm + hh + dd) == 0)
1019 + bufpos += snprintf(_elapsed_buf + bufpos,
1020 + sizeof(_elapsed_buf) - bufpos,
1021 + "%s%s%zd%s second%s",
1022 + bufpos == 0 ? "" : ", ",
1023 + GREEN, (size_t)ss, NORM, ss == 1 ? "" : "s");
1024 + } else {
1025 + snprintf(_elapsed_buf, sizeof(_elapsed_buf), "%s%zd%s seconds",
1026 + GREEN, (size_t)e, NORM);
1027 + }
1028 +
1029 + return _elapsed_buf;
1030 +}
1031 +
1032 +static char _atom_buf[BUFSIZ];
1033 +static char *fmt_atom(struct qlop_mode *flags, depend_atom *atom)
1034 +{
1035 + (void)flags;
1036 +
1037 + if (verbose) {
1038 + size_t len = snprintf(_atom_buf, sizeof(_atom_buf), "%s/%s-%s",
1039 + atom->CATEGORY, atom->PN, atom->PV);
1040 + if (atom->PR_int > 0)
1041 + snprintf(_atom_buf + len, sizeof(_atom_buf) - len, "-r%d",
1042 + atom->PR_int);
1043 + } else {
1044 + snprintf(_atom_buf, sizeof(_atom_buf), "%s/%s",
1045 + atom->CATEGORY, atom->PN);
1046 + }
1047 +
1048 + return _atom_buf;
1049 +}
1050 +
1051 +/* The format of the sync log has changed over time.
1052 +
1053 +Old format:
1054 +1106804103: Started emerge on: Jan 27, 2005 05:35:03
1055 +1106804103: *** emerge sync
1056 +1106804103: === sync
1057 +1106804103: >>> starting rsync with rsync://192.168.0.5/gentoo-portage
1058 +1106804537: === Sync completed with rsync://192.168.0.5/gentoo-portage
1059 +1106804538: *** terminating.
1060 +
1061 +New format:
1062 +1431764402: Started emerge on: May 16, 2015 04:20:01
1063 +1431764402: *** emerge --quiet --keep-going --verbose --nospinner --oneshot --quiet-build=n --sync
1064 +1431764402: === sync
1065 +1431764402: >>> Syncing repository 'gentoo' into '/usr/portage'...
1066 +1431764402: >>> Starting rsync with rsync://[2a01:90:200:10::1a]/gentoo-portage
1067 +1431764460: === Sync completed for gentoo
1068 +1431764493: *** terminating.
1069 +
1070 +*** packages
1071 +
1072 +1547475773: >>> emerge (53 of 74) app-shells/bash-5.0 to /gentoo/prefix64/
1073 +1547475774: === (53 of 74) Cleaning (app-shells/bash-5.0::/path/to/app-shells/bash/bash-5.0.ebuild)
1074 +1547475774: === (53 of 74) Compiling/Merging (app-shells/bash-5.0::/path/to/app-shells/bash/bash-5.0.ebuild)
1075 +1547475913: === (53 of 74) Merging (app-shells/bash-5.0::/path/to/app-shells/bash/bash-5.0.ebuild)
1076 +1547475916: >>> AUTOCLEAN: app-shells/bash:0
1077 +1547475916: === Unmerging... (app-shells/bash-4.4_p23)
1078 +1547475918: >>> unmerge success: app-shells/bash-4.4_p23
1079 +1547475921: === (53 of 74) Post-Build Cleaning (app-shells/bash-5.0::/path/to/app-shells/bash/bash-5.0.ebuild)
1080 +1547475921: ::: completed emerge (53 of 74) app-shells/bash-5.0 to /gentoo/prefix64/
1081 +
1082 +1550953093: Started emerge on: Feb 23, 2019 21:18:12
1083 +1550953093: *** emerge --ask --verbose --depclean pwgen
1084 +1550953093: >>> depclean
1085 +1550953118: === Unmerging... (app-admin/pwgen-2.08)
1086 +1550953125: >>> unmerge success: app-admin/pwgen-2.08
1087 +1550953125: *** exiting successfully.
1088 +1550953125: *** terminating.
1089 +*/
1090 +static int do_emerge_log(
1091 + const char *log,
1092 + struct qlop_mode *flags,
1093 + array_t *atoms,
1094 + time_t tbegin,
1095 + time_t tend)
1096 +{
1097 + FILE *fp;
1098 + char buf[BUFSIZ];
1099 + char *p;
1100 + char *q;
1101 + time_t tstart;
1102 + time_t sync_start = 0;
1103 + time_t sync_time = 0;
1104 + size_t sync_cnt = 0;
1105 + time_t elapsed;
1106 + depend_atom *atom;
1107 + depend_atom *atomw;
1108 + DECLARE_ARRAY(merge_matches);
1109 + DECLARE_ARRAY(merge_averages);
1110 + DECLARE_ARRAY(unmerge_matches);
1111 + DECLARE_ARRAY(unmerge_averages);
1112 + size_t i;
1113 + size_t parallel_emerge = 0;
1114 +
1115 + struct pkg_match {
1116 + char id[BUFSIZ];
1117 + depend_atom *atom;
1118 + time_t tbegin;
1119 + time_t time;
1120 + size_t cnt;
1121 + };
1122 + struct pkg_match *pkg;
1123 + struct pkg_match *pkgw;
1124 +
1125 + if ((fp = fopen(log, "r")) == NULL) {
1126 + warnp("Could not open logfile '%s'", log);
1127 + return 1;
1128 + }
1129 +
1130 + if (array_cnt(atoms) == 0) {
1131 + /* assemble list of atoms */
1132 + while (fgets(buf, sizeof(buf), fp) != NULL) {
1133 + if ((p = strchr(buf, ':')) == NULL)
1134 + continue;
1135 + *p++ = '\0';
1136 +
1137 + tstart = atol(buf);
1138 + if (tstart < tbegin || tstart > tend)
1139 + continue;
1140 +
1141 + atom = NULL;
1142 + if (strncmp(p, " >>> emerge ", 13) == 0 &&
1143 + (p = strchr(p + 13, ')')) != NULL)
1144 + {
1145 + p += 2;
1146 + q = strchr(p, ' ');
1147 + if (q != NULL) {
1148 + *q = '\0';
1149 + atom = atom_explode(p);
1150 + }
1151 + } else if (strncmp(p, " === Unmerging... (", 20) == 0 ||
1152 + strncmp(p, " === Unmerging... (", 19) == 0)
1153 + {
1154 + if (p[1] == ' ')
1155 + p++;
1156 + p += 19;
1157 + q = strchr(p, ')');
1158 + if (q != NULL) {
1159 + *q = '\0';
1160 + atom = atom_explode(p);
1161 + }
1162 + }
1163 + if (atom != NULL) {
1164 + /* strip off version info, if we generate a list
1165 + * ourselves, we will always print everything, so as
1166 + * well can keep memory footprint a bit lower by only
1167 + * having package matches */
1168 + atom->PV = NULL;
1169 + atom->PVR = NULL;
1170 + atom->PR_int = 0;
1171 +
1172 + atomw = NULL;
1173 + array_for_each(atoms, i, atomw) {
1174 + if (atom_compare(atom, atomw) == EQUAL)
1175 + break;
1176 + atomw = NULL;
1177 + }
1178 + if (atomw == NULL) {
1179 + xarraypush_ptr(atoms, atom);
1180 + } else {
1181 + atom_implode(atom);
1182 + }
1183 + }
1184 + }
1185 +
1186 + rewind(fp);
1187 + }
1188 +
1189 + /* loop over lines searching for atoms */
1190 + while (fgets(buf, sizeof(buf), fp) != NULL) {
1191 + if ((p = strchr(buf, ':')) == NULL)
1192 + continue;
1193 + *p++ = '\0';
1194 +
1195 + /* keeping track of parallel merges needs to be done before
1196 + * applying dates, for a subset of the log might show emerge
1197 + * finished without knowledge of another instance */
1198 + if (flags->do_running &&
1199 + (strncmp(p, " *** emerge ", 13) == 0 ||
1200 + strncmp(p, " *** terminating.", 18) == 0 ||
1201 + strncmp(p, " *** exiting ", 14) == 0))
1202 + {
1203 + if (p[7] == 'm') {
1204 + parallel_emerge++;
1205 + } else if (parallel_emerge > 0) {
1206 + parallel_emerge--;
1207 + if (parallel_emerge == 0) {
1208 + /* we just finished the only emerge we found to be
1209 + * running, so if there were "running" (unfinished)
1210 + * merges, they must have been terminated */
1211 + sync_start = 0;
1212 + while ((i = array_cnt(merge_matches)) > 0) {
1213 + i--;
1214 + pkgw = xarrayget(merge_matches, i);
1215 + atom_implode(pkgw->atom);
1216 + xarraydelete(merge_matches, i);
1217 + }
1218 + while ((i = array_cnt(unmerge_matches)) > 0) {
1219 + i--;
1220 + pkgw = xarrayget(unmerge_matches, i);
1221 + atom_implode(pkgw->atom);
1222 + xarraydelete(unmerge_matches, i);
1223 + }
1224 + }
1225 + }
1226 + }
1227 +
1228 + tstart = atol(buf);
1229 + if (tstart < tbegin || tstart > tend)
1230 + continue;
1231 +
1232 + /* are we interested in this line? */
1233 + if (flags->do_sync && (
1234 + strncmp(p, " === Sync completed ", 20) == 0 ||
1235 + strcmp(p, " === sync\n") == 0))
1236 + {
1237 + /* sync start or stop, we have nothing to detect parallel
1238 + * syncs with, so don't bother and assume this doesn't
1239 + * happen */
1240 + if (p[6] == 's') {
1241 + sync_start = tstart;
1242 + } else {
1243 + if (sync_start == 0)
1244 + continue; /* sync without start, exclude */
1245 + elapsed = tstart - sync_start;
1246 +
1247 + p += 20;
1248 + if (strncmp(p, "for ", 4) == 0) {
1249 + p += 4;
1250 + } else { /* "with " */
1251 + p += 5;
1252 + }
1253 + if ((q = strchr(p, '\n')) != NULL)
1254 + *q = '\0';
1255 +
1256 + if (flags->do_average || flags->do_running)
1257 + {
1258 + sync_cnt++;
1259 + sync_time += elapsed;
1260 + sync_start = 0; /* reset */
1261 + continue;
1262 + }
1263 + if (flags->do_time) {
1264 + printf("%s *** %s%s%s: %s\n",
1265 + fmt_date(flags, sync_start, tstart),
1266 + GREEN, p, NORM, fmt_elapsedtime(flags, elapsed));
1267 + } else {
1268 + printf("%s *** %s%s%s\n",
1269 + fmt_date(flags, sync_start, tstart),
1270 + GREEN, p, NORM);
1271 + }
1272 + sync_start = 0; /* reset */
1273 + }
1274 + } else if (flags->do_merge && (
1275 + strncmp(p, " >>> emerge (", 14) == 0 ||
1276 + strncmp(p, " ::: completed emerge (", 24) == 0))
1277 + {
1278 + /* merge start/stop (including potential unmerge of old pkg) */
1279 + if (p[3] == '>') { /* >>> emerge */
1280 + char *id;
1281 +
1282 + q = strchr(p + 14, ')');
1283 + if (q == NULL)
1284 + continue;
1285 +
1286 + /* keep a copy of the relevant string in case we need to
1287 + * match this */
1288 + id = p + 6;
1289 +
1290 + q += 2; /* ") " */
1291 + p = strchr(q, ' ');
1292 + if (p == NULL)
1293 + continue;
1294 +
1295 + *p = '\0';
1296 + atom = atom_explode(q);
1297 + *p = ' ';
1298 + if (atom == NULL)
1299 + continue;
1300 +
1301 + /* see if we need this atom */
1302 + atomw = NULL;
1303 + array_for_each(atoms, i, atomw) {
1304 + if (atom_compare(atom, atomw) == EQUAL)
1305 + break;
1306 + atomw = NULL;
1307 + }
1308 + if (atomw == NULL) {
1309 + atom_implode(atom);
1310 + continue;
1311 + }
1312 +
1313 + pkg = xmalloc(sizeof(struct pkg_match));
1314 + snprintf(pkg->id, sizeof(pkg->id), "%s", id);
1315 + pkg->atom = atom;
1316 + pkg->tbegin = tstart;
1317 + pkg->time = (time_t)0;
1318 + pkg->cnt = 0;
1319 + xarraypush_ptr(merge_matches, pkg);
1320 + } else { /* ::: completed */
1321 + array_for_each_rev(merge_matches, i, pkgw) {
1322 + if (strcmp(p + 16, pkgw->id) != 0)
1323 + continue;
1324 +
1325 + /* found, do report */
1326 + elapsed = tstart - pkgw->tbegin;
1327 +
1328 + if (flags->do_average || flags->do_running)
1329 + {
1330 + /* find in list of averages */
1331 + size_t n;
1332 +
1333 + pkg = NULL;
1334 + array_for_each(merge_averages, n, pkg) {
1335 + if (atom_compare(pkg->atom, pkgw->atom) == EQUAL) {
1336 + pkg->cnt++;
1337 + pkg->time += elapsed;
1338 + /* store max time for do_running */
1339 + if (elapsed > pkg->tbegin)
1340 + pkg->tbegin = elapsed;
1341 + atom_implode(pkgw->atom);
1342 + xarraydelete(merge_matches, i);
1343 + break;
1344 + }
1345 + pkg = NULL;
1346 + }
1347 + if (pkg == NULL) { /* push new entry */
1348 + if (!verbose || flags->do_running) {
1349 + /* strip off version info */
1350 + pkgw->atom->PV = NULL;
1351 + pkgw->atom->PVR = NULL;
1352 + pkgw->atom->PR_int = 0;
1353 + }
1354 + pkgw->id[0] = '\0';
1355 + pkgw->cnt = 1;
1356 + pkgw->time = elapsed;
1357 + pkgw->tbegin = elapsed;
1358 + xarraypush_ptr(merge_averages, pkgw);
1359 + xarraydelete_ptr(merge_matches, i);
1360 + }
1361 + break;
1362 + }
1363 + if (flags->do_time) {
1364 + printf("%s >>> %s%s%s: %s\n",
1365 + fmt_date(flags, pkgw->tbegin, tstart),
1366 + BLUE, fmt_atom(flags, pkgw->atom), NORM,
1367 + fmt_elapsedtime(flags, elapsed));
1368 + } else if (!flags->do_average) {
1369 + printf("%s >>> %s%s%s\n",
1370 + fmt_date(flags, pkgw->tbegin, tstart),
1371 + BLUE, fmt_atom(flags, pkgw->atom), NORM);
1372 + }
1373 + atom_implode(pkgw->atom);
1374 + xarraydelete(merge_matches, i);
1375 + break;
1376 + }
1377 + }
1378 + } else if (
1379 + (flags->do_unmerge &&
1380 + strncmp(p, " === Unmerging... (", 19) == 0) ||
1381 + (flags->do_autoclean &&
1382 + strncmp(p, " === Unmerging... (", 20) == 0) ||
1383 + ((flags->do_unmerge || flags->do_autoclean) &&
1384 + strncmp(p, " >>> unmerge success: ", 23) == 0))
1385 + {
1386 + /* unmerge action */
1387 + if (p[2] == '=') {
1388 + if (p[1] == ' ')
1389 + p++;
1390 + p += 19;
1391 +
1392 + if ((q = strchr(p, ')')) == NULL)
1393 + continue;
1394 +
1395 + *q = '\0';
1396 + atom = atom_explode(p);
1397 + if (atom == NULL)
1398 + continue;
1399 +
1400 + /* see if we need this atom */
1401 + atomw = NULL;
1402 + array_for_each(atoms, i, atomw) {
1403 + if (atom_compare(atom, atomw) == EQUAL)
1404 + break;
1405 + atomw = NULL;
1406 + }
1407 + if (atomw == NULL) {
1408 + atom_implode(atom);
1409 + continue;
1410 + }
1411 +
1412 + pkg = xmalloc(sizeof(struct pkg_match));
1413 + snprintf(pkg->id, sizeof(pkg->id), "%s\n", p); /* \n !!! */
1414 + pkg->atom = atom;
1415 + pkg->tbegin = tstart;
1416 + pkg->time = (time_t)0;
1417 + pkg->cnt = 0;
1418 + xarraypush_ptr(unmerge_matches, pkg);
1419 + } else {
1420 + array_for_each_rev(unmerge_matches, i, pkgw) {
1421 + if (strcmp(p + 23, pkgw->id) != 0)
1422 + continue;
1423 +
1424 + /* found, do report */
1425 + elapsed = tstart - pkgw->tbegin;
1426 +
1427 + if (flags->do_average || flags->do_running)
1428 + {
1429 + /* find in list of averages */
1430 + size_t n;
1431 +
1432 + pkg = NULL;
1433 + array_for_each(unmerge_averages, n, pkg) {
1434 + if (atom_compare(pkg->atom, pkgw->atom) == EQUAL) {
1435 + pkg->cnt++;
1436 + pkg->time += elapsed;
1437 + /* store max time for do_running */
1438 + if (elapsed > pkg->tbegin)
1439 + pkg->tbegin = elapsed;
1440 + atom_implode(pkgw->atom);
1441 + xarraydelete(unmerge_matches, i);
1442 + break;
1443 + }
1444 + pkg = NULL;
1445 + }
1446 + if (pkg == NULL) { /* push new entry */
1447 + if (!verbose || flags->do_running) {
1448 + /* strip off version info */
1449 + pkgw->atom->PV = NULL;
1450 + pkgw->atom->PVR = NULL;
1451 + pkgw->atom->PR_int = 0;
1452 + }
1453 + pkgw->id[0] = '\0';
1454 + pkgw->cnt = 1;
1455 + pkgw->time = elapsed;
1456 + pkgw->tbegin = elapsed;
1457 + xarraypush_ptr(unmerge_averages, pkgw);
1458 + xarraydelete_ptr(unmerge_matches, i);
1459 + }
1460 + break;
1461 + }
1462 + if (flags->do_time) {
1463 + printf("%s <<< %s%s%s: %s\n",
1464 + fmt_date(flags, pkgw->tbegin, tstart),
1465 + BLUE, fmt_atom(flags, pkgw->atom), NORM,
1466 + fmt_elapsedtime(flags, elapsed));
1467 + } else if (!flags->do_average) {
1468 + printf("%s <<< %s%s%s\n",
1469 + fmt_date(flags, pkgw->tbegin, tstart),
1470 + BLUE, fmt_atom(flags, pkgw->atom), NORM);
1471 + }
1472 + atom_implode(pkgw->atom);
1473 + xarraydelete(unmerge_matches, i);
1474 + break;
1475 + }
1476 + }
1477 + }
1478 + }
1479 + fclose(fp);
1480 + if (flags->do_running) {
1481 + /* can't report endtime for non-finished operations */
1482 + flags->do_endtime = 0;
1483 + tstart = time(NULL);
1484 + sync_time /= sync_cnt;
1485 + if (sync_start > 0) {
1486 + if (elapsed >= sync_time)
1487 + sync_time = 0;
1488 + if (flags->do_time) {
1489 + elapsed = tstart - sync_start;
1490 + printf("%s *** %s%s%s: %s... ETA: %s\n",
1491 + fmt_date(flags, sync_start, 0),
1492 + YELLOW, "sync", NORM, fmt_elapsedtime(flags, elapsed),
1493 + sync_time == 0 ? "unknown" :
1494 + fmt_elapsedtime(flags, sync_time - elapsed));
1495 + } else {
1496 + printf("%s *** %s%s%s... ETA: %s\n",
1497 + fmt_date(flags, sync_start, 0),
1498 + YELLOW, "sync", NORM,
1499 + sync_time == 0 ? "unknown" :
1500 + fmt_elapsedtime(flags, sync_time - elapsed));
1501 + }
1502 + }
1503 + array_for_each(merge_matches, i, pkgw) {
1504 + size_t j;
1505 + time_t maxtime = 0;
1506 +
1507 + elapsed = tstart - pkgw->tbegin;
1508 + pkg = NULL;
1509 + array_for_each(merge_averages, j, pkg) {
1510 + if (atom_compare(pkg->atom, pkgw->atom) == EQUAL) {
1511 + maxtime = pkg->time / pkg->cnt;
1512 + if (elapsed >= maxtime)
1513 + maxtime = elapsed >= pkg->tbegin ? 0 : pkg->tbegin;
1514 + break;
1515 + }
1516 + pkg = NULL;
1517 + }
1518 +
1519 + if (flags->do_time) {
1520 + printf("%s >>> %s%s%s: %s... ETA: %s\n",
1521 + fmt_date(flags, pkgw->tbegin, 0),
1522 + YELLOW, fmt_atom(flags, pkgw->atom), NORM,
1523 + fmt_elapsedtime(flags, elapsed),
1524 + maxtime == 0 ? "unknown" :
1525 + fmt_elapsedtime(flags, maxtime - elapsed));
1526 + } else {
1527 + printf("%s >>> %s%s%s... ETA: %s\n",
1528 + fmt_date(flags, pkgw->tbegin, 0),
1529 + YELLOW, fmt_atom(flags, pkgw->atom), NORM,
1530 + maxtime == 0 ? "unknown" :
1531 + fmt_elapsedtime(flags, maxtime - elapsed));
1532 + }
1533 + }
1534 + array_for_each(unmerge_matches, i, pkgw) {
1535 + size_t j;
1536 + time_t maxtime = 0;
1537 +
1538 + elapsed = tstart - pkgw->tbegin;
1539 + pkg = NULL;
1540 + array_for_each(unmerge_averages, j, pkg) {
1541 + if (atom_compare(pkg->atom, pkgw->atom) == EQUAL) {
1542 + maxtime = pkg->time / pkg->cnt;
1543 + if (elapsed >= maxtime)
1544 + maxtime = elapsed >= pkg->tbegin ? 0 : pkg->tbegin;
1545 + break;
1546 + }
1547 + pkg = NULL;
1548 + }
1549 +
1550 + if (flags->do_time) {
1551 + printf("%s <<< %s%s%s: %s... ETA: %s\n",
1552 + fmt_date(flags, pkgw->tbegin, 0),
1553 + YELLOW, fmt_atom(flags, pkgw->atom), NORM,
1554 + fmt_elapsedtime(flags, elapsed),
1555 + maxtime == 0 ? "unknown" :
1556 + fmt_elapsedtime(flags, maxtime - elapsed));
1557 + } else {
1558 + printf("%s <<< %s%s%s... ETA: %s\n",
1559 + fmt_date(flags, pkgw->tbegin, 0),
1560 + YELLOW, fmt_atom(flags, pkgw->atom), NORM,
1561 + maxtime == 0 ? "unknown" :
1562 + fmt_elapsedtime(flags, maxtime - elapsed));
1563 + }
1564 + }
1565 + } else if (flags->do_average) {
1566 + size_t total_merges = 0;
1567 + size_t total_unmerges = 0;
1568 + time_t total_time = (time_t)0;
1569 +
1570 + array_for_each(merge_averages, i, pkg) {
1571 + printf("%s%s%s: %s average for %s%zd%s merge%s\n",
1572 + BLUE, fmt_atom(flags, pkg->atom), NORM,
1573 + fmt_elapsedtime(flags, pkg->time / pkg->cnt),
1574 + GREEN, pkg->cnt, NORM, pkg->cnt == 1 ? "" : "s");
1575 + total_merges += pkg->cnt;
1576 + total_time += pkg->time;
1577 + }
1578 + array_for_each(unmerge_averages, i, pkg) {
1579 + printf("%s%s%s: %s average for %s%zd%s unmerge%s\n",
1580 + BLUE, fmt_atom(flags, pkg->atom), NORM,
1581 + fmt_elapsedtime(flags, pkg->time / pkg->cnt),
1582 + GREEN, pkg->cnt, NORM, pkg->cnt == 1 ? "" : "s");
1583 + total_unmerges += pkg->cnt;
1584 + total_time += pkg->time;
1585 + }
1586 + if (sync_cnt > 0) {
1587 + printf("%ssync%s: %s average for %s%zd%s sync%s\n",
1588 + BLUE, NORM, fmt_elapsedtime(flags, sync_time / sync_cnt),
1589 + GREEN, sync_cnt, NORM, sync_cnt == 1 ? "" : "s");
1590 + total_time += sync_time;
1591 + }
1592 + if (flags->do_summary) {
1593 + /* 123 seconds for 5 merges, 3 unmerges, 1 sync */
1594 + printf("%stotal%s: %s for ",
1595 + BLUE, NORM, fmt_elapsedtime(flags, total_time));
1596 + if (total_merges > 0)
1597 + printf("%s%zd%s merge%s",
1598 + GREEN, total_merges, NORM, total_merges == 1 ? "" : "s");
1599 + if (total_unmerges > 0)
1600 + printf("%s%s%zd%s unmerge%s",
1601 + total_merges == 0 ? "" : ", ",
1602 + GREEN, total_unmerges, NORM,
1603 + total_unmerges == 1 ? "" : "s");
1604 + if (sync_cnt > 0)
1605 + printf("%s%s%zd%s sync%s",
1606 + total_merges + total_unmerges == 0 ? "" : ", ",
1607 + GREEN, sync_cnt, NORM, sync_cnt == 1 ? "" : "s");
1608 + printf("\n");
1609 + }
1610 + }
1611 + return 0;
1612 +}
1613 +
1614 int qlop_main(int argc, char **argv)
1615 {
1616 size_t i;
1617 int ret;
1618 - int average = 1;
1619 - time_t start_time, end_time;
1620 - char do_time, do_list, do_unlist, do_sync, do_current, do_human_readable = 0;
1621 + time_t start_time;
1622 + time_t end_time;
1623 + struct qlop_mode m;
1624 char *logfile = NULL;
1625 - int flags;
1626 + char *atomfile = NULL;
1627 + char *p;
1628 + char *q;
1629 depend_atom *atom;
1630 DECLARE_ARRAY(atoms);
1631
1632 start_time = 0;
1633 end_time = LONG_MAX;
1634 - do_time = do_list = do_unlist = do_sync = do_current = 0;
1635 + m.do_time = 0;
1636 + m.do_merge = 0;
1637 + m.do_unmerge = 0;
1638 + m.do_autoclean = 0;
1639 + m.do_sync = 0;
1640 + m.do_running = 0;
1641 + m.do_average = 0;
1642 + m.do_summary = 0;
1643 + m.do_human = 0;
1644 + m.do_endtime = 0;
1645
1646 while ((ret = GETOPT_LONG(QLOP, qlop, "")) != -1) {
1647 switch (ret) {
1648 COMMON_GETOPTS_CASES(qlop)
1649
1650 - case 't': do_time = 1; break;
1651 - case 'l': do_list = 1; break;
1652 - case 'u': do_unlist = 1; break;
1653 - case 's': do_sync = 1; break;
1654 - case 'c': do_current = 1; break;
1655 - case 'g': do_time = 1; average = 0; break;
1656 - case 'H': do_human_readable = 1; break;
1657 + case 't': m.do_time = 1; break;
1658 + case 'm': m.do_merge = 1; break;
1659 + case 'u': m.do_unmerge = 1; break;
1660 + case 'U': m.do_autoclean = 1; break;
1661 + case 's': m.do_sync = 1; break;
1662 + case 'r': m.do_running = 1; break;
1663 + case 'a': m.do_average = 1; break;
1664 + case 'c': m.do_summary = 1; break;
1665 + case 'H': m.do_human = 1; break;
1666 + case 'e': m.do_endtime = 1; break;
1667 case 'd':
1668 if (start_time == 0) {
1669 if (!parse_date(optarg, &start_time))
1670 @@ -851,13 +861,19 @@ int qlop_main(int argc, char **argv)
1671 err("too many -d options");
1672 break;
1673 case 'f':
1674 - if (logfile) err("Only use -f once");
1675 + if (logfile != NULL)
1676 + err("Only use -f once");
1677 logfile = xstrdup(optarg);
1678 break;
1679 + case 'w':
1680 + if (atomfile != NULL)
1681 + err("Only use -w once");
1682 + if (!eat_file(optarg, &atomfile, &i))
1683 + err("failed to open file %s", optarg);
1684 + break;
1685 }
1686 }
1687 - if (!do_list && !do_unlist && !do_time && !do_sync && !do_current)
1688 - qlop_usage(EXIT_FAILURE);
1689 +
1690 if (logfile == NULL)
1691 xasprintf(&logfile, "%s/%s", portlogdir, QLOP_DEFAULT_LOGFILE);
1692
1693 @@ -870,26 +886,75 @@ int qlop_main(int argc, char **argv)
1694 else
1695 xarraypush_ptr(atoms, atom);
1696 }
1697 + for (p = atomfile; p != NULL && *p != '\0'; p = q) {
1698 + while (isspace((int)(*p)))
1699 + p++;
1700 + q = strchr(p, '\n');
1701 + if (q != NULL) {
1702 + *q = '\0';
1703 + q++;
1704 + }
1705 + atom = atom_explode(p);
1706 + if (!atom)
1707 + warn("invalid atom: %s", p);
1708 + else
1709 + xarraypush_ptr(atoms, atom);
1710 + }
1711 + if (atomfile)
1712 + free(atomfile);
1713 +
1714 + /* default operation: -must */
1715 + if (
1716 + m.do_time == 0 &&
1717 + m.do_merge == 0 &&
1718 + m.do_unmerge == 0 &&
1719 + m.do_autoclean == 0 &&
1720 + m.do_sync == 0 &&
1721 + m.do_running == 0 &&
1722 + m.do_average == 0 &&
1723 + m.do_summary == 0 &&
1724 + m.do_human == 0
1725 + )
1726 + {
1727 + m.do_merge = 1;
1728 + m.do_unmerge = 1;
1729 + m.do_sync = 1;
1730 + m.do_time = 1;
1731 + }
1732 +
1733 + /* handle deps */
1734 + if (m.do_summary)
1735 + m.do_average = 1;
1736 +
1737 + /* handle -a / -t conflict */
1738 + if (m.do_average && m.do_time) {
1739 + warn("-a (or -c) and -t cannot be used together, dropping -t");
1740 + m.do_time = 0;
1741 + }
1742
1743 - flags = 0;
1744 - if (do_list)
1745 - flags |= QLOP_LIST;
1746 - if (do_unlist)
1747 - flags |= QLOP_UNLIST;
1748 - if (flags)
1749 - show_emerge_history(flags, atoms, logfile, start_time, end_time);
1750 -
1751 - if (do_current)
1752 - show_current_emerge();
1753 - if (do_sync)
1754 - show_sync_history(logfile, start_time, end_time);
1755 -
1756 - if (do_time) {
1757 - for (i = 0; i < (size_t)argc; ++i)
1758 - show_merge_times(argv[i], logfile, average, do_human_readable,
1759 - start_time, end_time);
1760 + /* handle -a / -r conflict */
1761 + if (m.do_average && m.do_running) {
1762 + warn("-a (or -c) and -r cannot be used together, dropping -a");
1763 + m.do_average = 0;
1764 }
1765
1766 + if (m.do_sync && array_cnt(atoms) > 0) {
1767 + warn("-s cannot be used when specifying atoms, dropping -s");
1768 + m.do_sync = 0;
1769 + }
1770 +
1771 + /* set default for -t, -a or -r */
1772 + if ((m.do_average || m.do_time || m.do_running) &&
1773 + !(m.do_merge || m.do_unmerge || m.do_sync))
1774 + {
1775 + m.do_merge = 1;
1776 + m.do_unmerge = 1;
1777 + if (array_cnt(atoms) == 0)
1778 + m.do_sync = 1;
1779 + }
1780 +
1781 + do_emerge_log(logfile, &m, atoms, start_time, end_time);
1782 +
1783 array_for_each(atoms, i, atom)
1784 atom_implode(atom);
1785 xarrayfree_int(atoms);
1786
1787 diff --git a/tests/qlop/dotest b/tests/qlop/dotest
1788 index ac30924..51cdb8a 100755
1789 --- a/tests/qlop/dotest
1790 +++ b/tests/qlop/dotest
1791 @@ -25,26 +25,26 @@ export LC_TIME="C"
1792 # simple sync check
1793 test 01 0 "qlop -s -f ${as}/sync.log"
1794
1795 -# check all installed pkgs
1796 -test 02 0 "qlop -l -f ${as}/sync.log"
1797 +# check all merged pkgs
1798 +test 02 0 "qlop -mv -f ${as}/sync.log"
1799
1800 -# check all uninstalled pkgs
1801 -test 03 0 "qlop -u -f ${as}/sync.log"
1802 +# check all unmerged pkgs
1803 +test 03 0 "qlop -uv -f ${as}/sync.log"
1804
1805 # verify atom parsing works (and not partial strings)
1806 -test 04 0 "qlop -l gcc -f ${as}/sync.log"
1807 +test 04 0 "qlop -mv gcc -f ${as}/sync.log"
1808
1809 # verify atom version parsing works
1810 -test 05 0 "qlop -l '<gcc-5' -f ${as}/sync.log"
1811 +test 05 0 "qlop -mv '<gcc-5' -f ${as}/sync.log"
1812
1813 # check date time parser, note on date parsing,
1814 # https://bugs.gentoo.org/638032#c6 so the format %d%Y%m isn't compliant
1815 -test 06 0 "qlop -l -f ${as}/sync.log -d 2005-01-01"
1816 -test 07 0 "qlop -l -f ${as}/sync.log -d '%d %Y %m|01 2005 01'"
1817 -test 08 0 "qlop -l -f ${as}/sync.log -d 1104898893"
1818 +test 06 0 "qlop -mv -f ${as}/sync.log -d 2005-01-01"
1819 +test 07 0 "qlop -mv -f ${as}/sync.log -d '%d %Y %m|01 2005 01'"
1820 +test 08 0 "qlop -mv -f ${as}/sync.log -d 1104898893"
1821
1822 # deal with aborted merges
1823 -test 09 0 "qlop -Htgv automake -f ${as}/aborts.log"
1824 +test 09 0 "qlop -Hacv automake -f ${as}/aborts.log"
1825
1826 cleantmpdir
1827
1828
1829 diff --git a/tests/qlop/list01.good b/tests/qlop/list01.good
1830 index fc8683c..2689952 100644
1831 --- a/tests/qlop/list01.good
1832 +++ b/tests/qlop/list01.good
1833 @@ -1,2 +1,2 @@
1834 -Thu Jan 27 05:42:17 2005 >>> rsync://192.168.0.5/gentoo-portage
1835 -Sat May 16 08:21:00 2015 >>> gentoo
1836 +2005-01-27T05:35:03 *** rsync://192.168.0.5/gentoo-portage
1837 +2015-05-16T08:20:02 *** gentoo
1838
1839 diff --git a/tests/qlop/list02.good b/tests/qlop/list02.good
1840 index a00a3f6..706bdac 100644
1841 --- a/tests/qlop/list02.good
1842 +++ b/tests/qlop/list02.good
1843 @@ -1,3 +1,3 @@
1844 -Thu Oct 28 06:49:14 2004 >>> dev-util/ccache-2.3
1845 -Thu Jan 27 05:56:39 2005 >>> sys-devel/gcc-config-1.3.9
1846 -Thu Jan 27 06:17:10 2005 >>> sys-devel/gcc-3.4.3-r1
1847 +2004-10-28T06:49:13 >>> dev-util/ccache-2.3
1848 +2005-01-27T05:56:28 >>> sys-devel/gcc-config-1.3.9
1849 +2005-01-27T05:56:39 >>> sys-devel/gcc-3.4.3-r1
1850
1851 diff --git a/tests/qlop/list03.good b/tests/qlop/list03.good
1852 index add774a..cccc8bb 100644
1853 --- a/tests/qlop/list03.good
1854 +++ b/tests/qlop/list03.good
1855 @@ -1,4 +1,4 @@
1856 -Thu Jan 27 05:56:39 2005 <<< sys-devel/gcc-config-1.3.6-r3
1857 -Thu Jan 27 05:58:04 2005 <<< sys-apps/pam-login-3.14
1858 -Thu Jan 27 05:58:06 2005 <<< sys-libs/pam-0.77-r1
1859 -Thu Jan 27 05:58:16 2005 <<< sys-fs/devfsd-1.3.25-r8
1860 +2005-01-27T05:56:38 <<< sys-devel/gcc-config-1.3.6-r3
1861 +2005-01-27T05:58:02 <<< sys-apps/pam-login-3.14
1862 +2005-01-27T05:58:04 <<< sys-libs/pam-0.77-r1
1863 +2005-01-27T05:58:15 <<< sys-fs/devfsd-1.3.25-r8
1864
1865 diff --git a/tests/qlop/list04.good b/tests/qlop/list04.good
1866 index c3de519..aa39ed2 100644
1867 --- a/tests/qlop/list04.good
1868 +++ b/tests/qlop/list04.good
1869 @@ -1 +1 @@
1870 -Thu Jan 27 06:17:10 2005 >>> sys-devel/gcc-3.4.3-r1
1871 +2005-01-27T05:56:39 >>> sys-devel/gcc-3.4.3-r1
1872
1873 diff --git a/tests/qlop/list05.good b/tests/qlop/list05.good
1874 index c3de519..aa39ed2 100644
1875 --- a/tests/qlop/list05.good
1876 +++ b/tests/qlop/list05.good
1877 @@ -1 +1 @@
1878 -Thu Jan 27 06:17:10 2005 >>> sys-devel/gcc-3.4.3-r1
1879 +2005-01-27T05:56:39 >>> sys-devel/gcc-3.4.3-r1
1880
1881 diff --git a/tests/qlop/list06.good b/tests/qlop/list06.good
1882 index e9fccc3..769aa7b 100644
1883 --- a/tests/qlop/list06.good
1884 +++ b/tests/qlop/list06.good
1885 @@ -1,2 +1,2 @@
1886 -Thu Jan 27 05:56:39 2005 >>> sys-devel/gcc-config-1.3.9
1887 -Thu Jan 27 06:17:10 2005 >>> sys-devel/gcc-3.4.3-r1
1888 +2005-01-27T05:56:28 >>> sys-devel/gcc-config-1.3.9
1889 +2005-01-27T05:56:39 >>> sys-devel/gcc-3.4.3-r1
1890
1891 diff --git a/tests/qlop/list07.good b/tests/qlop/list07.good
1892 index e9fccc3..769aa7b 100644
1893 --- a/tests/qlop/list07.good
1894 +++ b/tests/qlop/list07.good
1895 @@ -1,2 +1,2 @@
1896 -Thu Jan 27 05:56:39 2005 >>> sys-devel/gcc-config-1.3.9
1897 -Thu Jan 27 06:17:10 2005 >>> sys-devel/gcc-3.4.3-r1
1898 +2005-01-27T05:56:28 >>> sys-devel/gcc-config-1.3.9
1899 +2005-01-27T05:56:39 >>> sys-devel/gcc-3.4.3-r1
1900
1901 diff --git a/tests/qlop/list08.good b/tests/qlop/list08.good
1902 index e9fccc3..769aa7b 100644
1903 --- a/tests/qlop/list08.good
1904 +++ b/tests/qlop/list08.good
1905 @@ -1,2 +1,2 @@
1906 -Thu Jan 27 05:56:39 2005 >>> sys-devel/gcc-config-1.3.9
1907 -Thu Jan 27 06:17:10 2005 >>> sys-devel/gcc-3.4.3-r1
1908 +2005-01-27T05:56:28 >>> sys-devel/gcc-config-1.3.9
1909 +2005-01-27T05:56:39 >>> sys-devel/gcc-3.4.3-r1
1910
1911 diff --git a/tests/qlop/list09.good b/tests/qlop/list09.good
1912 index 333d7ad..269ec03 100644
1913 --- a/tests/qlop/list09.good
1914 +++ b/tests/qlop/list09.good
1915 @@ -1,3 +1,3 @@
1916 -automake-1.11.6: Mon Apr 1 12:34:09 2013: 53 minutes, 52 seconds
1917 -automake-1.9.6-r3: Fri May 17 12:58:39 2013: 24 minutes, 7 seconds
1918 -automake: 2 times
1919 +sys-devel/automake-1.11.6: 53 minutes, 52 seconds average for 1 merge
1920 +sys-devel/automake-1.9.6-r3: 24 minutes, 7 seconds average for 1 merge
1921 +total: 1 hour, 17 minutes, 59 seconds for 2 merges