1 |
commit: 79ae531435cf37e50676c25e794f335a6587c7d3 |
2 |
Author: Mike Frysinger <vapier <AT> gentoo <DOT> org> |
3 |
AuthorDate: Mon Mar 28 03:52:02 2016 +0000 |
4 |
Commit: Mike Frysinger <vapier <AT> gentoo <DOT> org> |
5 |
CommitDate: Mon Mar 28 03:52:02 2016 +0000 |
6 |
URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=79ae5314 |
7 |
|
8 |
qlop: add --date option to filter output |
9 |
|
10 |
Allow people to filter results by start & end dates. |
11 |
|
12 |
URL: https://bugs.gentoo.org/192918 |
13 |
Reported-by: Laurento Frittella <laurento.frittella <AT> gmail.com> |
14 |
|
15 |
man/qlop.1 | 5 +- |
16 |
qlop.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++--- |
17 |
tests/qlop/dotest | 5 ++ |
18 |
tests/qlop/list06.good | 2 + |
19 |
tests/qlop/list07.good | 2 + |
20 |
tests/qlop/list08.good | 2 + |
21 |
6 files changed, 139 insertions(+), 8 deletions(-) |
22 |
|
23 |
diff --git a/man/qlop.1 b/man/qlop.1 |
24 |
index 6e645a8..77cf5ef 100644 |
25 |
--- a/man/qlop.1 |
26 |
+++ b/man/qlop.1 |
27 |
@@ -1,4 +1,4 @@ |
28 |
-.TH qlop "1" "Feb 2016" "Gentoo Foundation" "qlop" |
29 |
+.TH qlop "1" "Mar 2016" "Gentoo Foundation" "qlop" |
30 |
.SH NAME |
31 |
qlop \- emerge log analyzer |
32 |
.SH SYNOPSIS |
33 |
@@ -29,6 +29,9 @@ Show sync history |
34 |
\fB\-c\fR, \fB\-\-current\fR |
35 |
Show current emerging packages |
36 |
.TP |
37 |
+\fB\-d\fR \fI<arg>\fR, \fB\-\-date\fR \fI<arg>\fR |
38 |
+Limit selection to this time (1st -d is start, 2nd -d is end) |
39 |
+.TP |
40 |
\fB\-f\fR \fI<arg>\fR, \fB\-\-logfile\fR \fI<arg>\fR |
41 |
Read emerge logfile instead of $EMERGE_LOG_DIR/emerge.log |
42 |
.TP |
43 |
|
44 |
diff --git a/qlop.c b/qlop.c |
45 |
index 319d767..0da636a 100644 |
46 |
--- a/qlop.c |
47 |
+++ b/qlop.c |
48 |
@@ -10,7 +10,7 @@ |
49 |
|
50 |
#define QLOP_DEFAULT_LOGFILE "emerge.log" |
51 |
|
52 |
-#define QLOP_FLAGS "gtHluscf:" COMMON_FLAGS |
53 |
+#define QLOP_FLAGS "gtHluscd:f:" COMMON_FLAGS |
54 |
static struct option const qlop_long_opts[] = { |
55 |
{"gauge", no_argument, NULL, 'g'}, |
56 |
{"time", no_argument, NULL, 't'}, |
57 |
@@ -19,6 +19,7 @@ static struct option const qlop_long_opts[] = { |
58 |
{"unlist", no_argument, NULL, 'u'}, |
59 |
{"sync", no_argument, NULL, 's'}, |
60 |
{"current", no_argument, NULL, 'c'}, |
61 |
+ {"date", a_argument, NULL, 'd'}, |
62 |
{"logfile", a_argument, NULL, 'f'}, |
63 |
COMMON_LONG_OPTS |
64 |
}; |
65 |
@@ -30,6 +31,7 @@ static const char * const qlop_opts_help[] = { |
66 |
"Show unmerge history", |
67 |
"Show sync history", |
68 |
"Show current emerging packages", |
69 |
+ "Limit selection to this time (1st -d is start, 2nd -d is end)", |
70 |
"Read emerge logfile instead of $EMERGE_LOG_DIR/" QLOP_DEFAULT_LOGFILE, |
71 |
COMMON_OPTS_HELP |
72 |
}; |
73 |
@@ -64,7 +66,8 @@ chop_ctime(time_t t) |
74 |
} |
75 |
|
76 |
_q_static unsigned long |
77 |
-show_merge_times(char *package, const char *logfile, int average, char human_readable) |
78 |
+show_merge_times(char *package, const char *logfile, int average, char human_readable, |
79 |
+ time_t start_time, time_t end_time) |
80 |
{ |
81 |
FILE *fp; |
82 |
char cat[126], buf[2][BUFSIZ]; |
83 |
@@ -103,6 +106,8 @@ show_merge_times(char *package, const char *logfile, int average, char human_rea |
84 |
continue; |
85 |
*p = 0; |
86 |
t[0] = atol(buf[0]); |
87 |
+ if (t[0] < start_time || t[0] > end_time) |
88 |
+ continue; |
89 |
strcpy(buf[1], p + 1); |
90 |
rmspace(buf[1]); |
91 |
if (strncmp(buf[1], ">>> emerge (", 12) == 0) { |
92 |
@@ -216,7 +221,8 @@ show_merge_times(char *package, const char *logfile, int average, char human_rea |
93 |
} |
94 |
|
95 |
_q_static void |
96 |
-show_emerge_history(int listflag, array_t *atoms, const char *logfile) |
97 |
+show_emerge_history(int listflag, array_t *atoms, const char *logfile, |
98 |
+ time_t start_time, time_t end_time) |
99 |
{ |
100 |
FILE *fp; |
101 |
size_t buflen, linelen; |
102 |
@@ -247,6 +253,8 @@ show_emerge_history(int listflag, array_t *atoms, const char *logfile) |
103 |
continue; |
104 |
|
105 |
t = (time_t) atol(buf); |
106 |
+ if (t < start_time || t > end_time) |
107 |
+ continue; |
108 |
|
109 |
if ((listflag & QLOP_LIST) && !strncmp(q, "::: completed emerge (", 22)) { |
110 |
merged = 1; |
111 |
@@ -313,7 +321,7 @@ New format: |
112 |
1431764493: *** terminating. |
113 |
*/ |
114 |
_q_static void |
115 |
-show_sync_history(const char *logfile) |
116 |
+show_sync_history(const char *logfile, time_t start_time, time_t end_time) |
117 |
{ |
118 |
FILE *fp; |
119 |
size_t buflen, linelen; |
120 |
@@ -344,6 +352,8 @@ show_sync_history(const char *logfile) |
121 |
rmspace_len(buf, linelen); |
122 |
|
123 |
t = (time_t)atol(buf); |
124 |
+ if (t < start_time || t > end_time) |
125 |
+ continue; |
126 |
|
127 |
if (!strncmp(p, "with ", 5)) |
128 |
p += 5; |
129 |
@@ -635,16 +645,112 @@ void show_current_emerge(void) |
130 |
} |
131 |
#endif |
132 |
|
133 |
+_q_static |
134 |
+bool parse_date(const char *sdate, time_t *t) |
135 |
+{ |
136 |
+ struct tm tm; |
137 |
+ const char *s; |
138 |
+ |
139 |
+ memset(&tm, 0, sizeof(tm)); |
140 |
+ |
141 |
+ s = strchr(sdate, '|'); |
142 |
+ if (s) { |
143 |
+ /* Handle custom format like "%Y|2012". */ |
144 |
+ size_t fmtlen = s - sdate; |
145 |
+ char fmt[fmtlen + 1]; |
146 |
+ memcpy(fmt, sdate, fmtlen); |
147 |
+ fmt[fmtlen] = '\0'; |
148 |
+ sdate = s + 1; |
149 |
+ s = strptime(sdate, fmt, &tm); |
150 |
+ if (s == NULL || s[0] != '\0') |
151 |
+ return false; |
152 |
+ } else { |
153 |
+ /* Handle automatic formats: |
154 |
+ * - "12315128" -> %s |
155 |
+ * - "2015-12-24" -> %F (same as %Y-%m-%d |
156 |
+ * - human readable format (see below) |
157 |
+ */ |
158 |
+ size_t len = strspn(sdate, "0123456789-"); |
159 |
+ if (sdate[len] == '\0') { |
160 |
+ const char *fmt; |
161 |
+ if (strchr(sdate, '-') == NULL) |
162 |
+ fmt = "%s"; |
163 |
+ else |
164 |
+ fmt = "%F"; |
165 |
+ |
166 |
+ s = strptime(sdate, fmt, &tm); |
167 |
+ if (s == NULL || s[0] != '\0') |
168 |
+ return false; |
169 |
+ } else { |
170 |
+ /* Handle the formats: |
171 |
+ * <#> <day|week|month|year>[s] [ago] |
172 |
+ */ |
173 |
+ len = strlen(sdate); |
174 |
+ |
175 |
+ unsigned long num; |
176 |
+ char dur[len]; |
177 |
+ char ago[len]; |
178 |
+ int ret = sscanf(sdate, "%lu %s %s", &num, dur, ago); |
179 |
+ |
180 |
+ if (ret < 2) |
181 |
+ return false; |
182 |
+ if (ret == 3 && strcmp(ago, "ago") != 0) |
183 |
+ return false; |
184 |
+ |
185 |
+ if (time(t) == -1) |
186 |
+ return false; |
187 |
+ if (localtime_r(t, &tm) == NULL) |
188 |
+ return false; |
189 |
+ |
190 |
+ /* Chop and trailing "s" sizes. */ |
191 |
+ len = strlen(dur); |
192 |
+ if (dur[len - 1] == 's') |
193 |
+ dur[len - 1] = '\0'; |
194 |
+ |
195 |
+ /* Step down the current time. */ |
196 |
+ if (!strcmp(dur, "year")) { |
197 |
+ tm.tm_year -= num; |
198 |
+ } else if (!strcmp(dur, "month")) { |
199 |
+ if (num >= 12) { |
200 |
+ tm.tm_year -= (num / 12); |
201 |
+ num %= 12; |
202 |
+ } |
203 |
+ tm.tm_mon -= num; |
204 |
+ if (tm.tm_mon < 0) { |
205 |
+ tm.tm_mon += 12; |
206 |
+ tm.tm_year -= 1; |
207 |
+ } |
208 |
+ } else if (!strcmp(dur, "week")) { |
209 |
+ num *= 7; |
210 |
+ goto days; |
211 |
+ } else if (!strcmp(dur, "day")) { |
212 |
+ days: |
213 |
+ /* This is in seconds, so scale w/that. */ |
214 |
+ *t -= (num * 24 * 60 * 60); |
215 |
+ if (localtime_r(t, &tm) == NULL) |
216 |
+ return false; |
217 |
+ } else |
218 |
+ return false; |
219 |
+ } |
220 |
+ } |
221 |
+ |
222 |
+ *t = mktime(&tm); |
223 |
+ return (*t == -1) ? false : true; |
224 |
+} |
225 |
+ |
226 |
int qlop_main(int argc, char **argv) |
227 |
{ |
228 |
size_t i; |
229 |
int average = 1; |
230 |
+ time_t start_time, end_time; |
231 |
char do_time, do_list, do_unlist, do_sync, do_current, do_human_readable = 0; |
232 |
char *logfile = NULL; |
233 |
int flags; |
234 |
depend_atom *atom; |
235 |
DECLARE_ARRAY(atoms); |
236 |
|
237 |
+ start_time = 0; |
238 |
+ end_time = LONG_MAX; |
239 |
do_time = do_list = do_unlist = do_sync = do_current = 0; |
240 |
|
241 |
while ((i = GETOPT_LONG(QLOP, qlop, "")) != -1) { |
242 |
@@ -658,6 +764,16 @@ int qlop_main(int argc, char **argv) |
243 |
case 'c': do_current = 1; break; |
244 |
case 'g': do_time = 1; average = 0; break; |
245 |
case 'H': do_human_readable = 1; break; |
246 |
+ case 'd': |
247 |
+ if (start_time == 0) { |
248 |
+ if (!parse_date(optarg, &start_time)) |
249 |
+ err("invalid date: %s", optarg); |
250 |
+ } else if (end_time == LONG_MAX) { |
251 |
+ if (!parse_date(optarg, &end_time)) |
252 |
+ err("invalid date: %s", optarg); |
253 |
+ } else |
254 |
+ err("too many -d options"); |
255 |
+ break; |
256 |
case 'f': |
257 |
if (logfile) err("Only use -f once"); |
258 |
logfile = xstrdup(optarg); |
259 |
@@ -685,16 +801,17 @@ int qlop_main(int argc, char **argv) |
260 |
if (do_unlist) |
261 |
flags |= QLOP_UNLIST; |
262 |
if (flags) |
263 |
- show_emerge_history(flags, atoms, logfile); |
264 |
+ show_emerge_history(flags, atoms, logfile, start_time, end_time); |
265 |
|
266 |
if (do_current) |
267 |
show_current_emerge(); |
268 |
if (do_sync) |
269 |
- show_sync_history(logfile); |
270 |
+ show_sync_history(logfile, start_time, end_time); |
271 |
|
272 |
if (do_time) { |
273 |
for (i = 0; i < argc; ++i) |
274 |
- show_merge_times(argv[i], logfile, average, do_human_readable); |
275 |
+ show_merge_times(argv[i], logfile, average, do_human_readable, |
276 |
+ start_time, end_time); |
277 |
} |
278 |
|
279 |
array_for_each(atoms, i, atom) |
280 |
|
281 |
diff --git a/tests/qlop/dotest b/tests/qlop/dotest |
282 |
index fad6011..0275d45 100755 |
283 |
--- a/tests/qlop/dotest |
284 |
+++ b/tests/qlop/dotest |
285 |
@@ -37,6 +37,11 @@ test 04 0 "qlop -l gcc -f ${as}/sync.log" |
286 |
# verify atom version parsing works |
287 |
test 05 0 "qlop -l '<gcc-5' -f ${as}/sync.log" |
288 |
|
289 |
+# check date time parser |
290 |
+test 06 0 "qlop -l -f ${as}/sync.log -d 2005-01-01" |
291 |
+test 07 0 "qlop -l -f ${as}/sync.log -d '%d%Y%m|01200501'" |
292 |
+test 08 0 "qlop -l -f ${as}/sync.log -d 1104898893" |
293 |
+ |
294 |
cleantmpdir |
295 |
|
296 |
end |
297 |
|
298 |
diff --git a/tests/qlop/list06.good b/tests/qlop/list06.good |
299 |
new file mode 100644 |
300 |
index 0000000..e9fccc3 |
301 |
--- /dev/null |
302 |
+++ b/tests/qlop/list06.good |
303 |
@@ -0,0 +1,2 @@ |
304 |
+Thu Jan 27 05:56:39 2005 >>> sys-devel/gcc-config-1.3.9 |
305 |
+Thu Jan 27 06:17:10 2005 >>> sys-devel/gcc-3.4.3-r1 |
306 |
|
307 |
diff --git a/tests/qlop/list07.good b/tests/qlop/list07.good |
308 |
new file mode 100644 |
309 |
index 0000000..e9fccc3 |
310 |
--- /dev/null |
311 |
+++ b/tests/qlop/list07.good |
312 |
@@ -0,0 +1,2 @@ |
313 |
+Thu Jan 27 05:56:39 2005 >>> sys-devel/gcc-config-1.3.9 |
314 |
+Thu Jan 27 06:17:10 2005 >>> sys-devel/gcc-3.4.3-r1 |
315 |
|
316 |
diff --git a/tests/qlop/list08.good b/tests/qlop/list08.good |
317 |
new file mode 100644 |
318 |
index 0000000..e9fccc3 |
319 |
--- /dev/null |
320 |
+++ b/tests/qlop/list08.good |
321 |
@@ -0,0 +1,2 @@ |
322 |
+Thu Jan 27 05:56:39 2005 >>> sys-devel/gcc-config-1.3.9 |
323 |
+Thu Jan 27 06:17:10 2005 >>> sys-devel/gcc-3.4.3-r1 |