]> git.itanic.dy.fi Git - emerge-timer/blob - emerge-timer.py
list_pretended: Change how the package name is parsed from stdin
[emerge-timer] / emerge-timer.py
1 #!/usr/bin/python
2
3
4 import sys, subprocess, datetime, os
5
6
7 PORTDIR = "/usr/portage/"
8 LOGFILE = "/var/log/emerge.log"
9
10
11
12 green_start = "\033[32m"
13 color_stop = "\033[m"
14
15
16
17
18
19 def organize_times(time):
20     """Takes the emerge time in seconds, organizes it into
21     days, hours, minutes or seconds and finally prints that out."""
22
23     days = time/(3600*24)
24     hours = (days - int(days))*24
25     minutes = (hours - int(hours))*60
26     seconds = (minutes - int(minutes))*60
27
28     days = int(days)
29     hours = int(hours)
30     minutes = int(minutes)
31     seconds = int(round(seconds))
32
33     if days > 0:
34         print_days = (green_start + str(days) + color_stop + " day")
35         if days != 1:
36             print_days += "s"
37         print print_days,
38
39     if hours > 0:
40         print_hours = (green_start + str(hours) + color_stop + " hour")
41         if hours != 1:
42             print_hours += "s"
43         print print_hours,
44
45     if minutes > 0:
46         print_minutes = (green_start + str(minutes) + color_stop + " minute")
47         if minutes != 1:
48             print_minutes += "s"
49         print print_minutes,
50
51     printable_sec = (green_start + str(seconds) + color_stop + " second")
52     if seconds != 1:
53         printable_sec += "s"
54     print printable_sec,
55
56
57
58 def get_date(emerge_start):
59     """Take the emerge startup time in seconds and turn it into a
60     correct date."""
61
62     date = datetime.datetime.fromtimestamp(emerge_start)
63
64     year = str(date.year)
65     month = str(date.month)
66     day = str(date.day)
67     weekday = date.weekday()
68
69     if weekday == 0: weekday = 'Mon '
70     if weekday == 1: weekday = 'Tue '
71     if weekday == 2: weekday = 'Wed '
72     if weekday == 3: weekday = 'Thu '
73     if weekday == 4: weekday = 'Fri '
74     if weekday == 5: weekday = 'Sat '
75     if weekday == 6: weekday = 'Sun '
76
77     hour = str(date.hour)
78     minute = str(date.minute)
79     second = str(date.second)
80
81     # This is in the format 'Mon 23.05.2011 00:20:14'
82
83     date = weekday + "{:%d.%m.%Y %H:%M:%S}".format(date)
84
85     return date
86
87
88
89 def list_all_packages():
90     """Go through PORTDIR and create a list of all the packages in portage"""
91
92     root = os.listdir(PORTDIR)
93     all_packages = []
94
95     for package_group in root:
96         group_dir = PORTDIR + package_group
97         if (os.path.isdir(group_dir)
98             and (package_group != "licenses")
99             and (package_group != "metadata")):
100
101             name_dir = os.listdir(group_dir)
102
103             for package_name in name_dir:
104                 if ".xml" not in package_name:
105
106                     all_packages.append((package_group +
107                                          '/' + package_name))
108
109     return all_packages
110
111
112
113
114 def get_package(name):
115     """Take the user-input package name and search for it
116     in PORTDIR. """
117
118     dirlist = os.listdir(PORTDIR)
119     possible_package = []
120
121
122     # If the given name is in the format xxx/zzz
123     # assume that xxx is the package group
124     if '/' in name:
125         group = name.partition('/')[0]
126         pkg = name.partition('/')[2]
127         directory = PORTDIR + group
128
129         if group in dirlist:
130             dirs = os.listdir(directory)
131             if pkg in dirs:
132                 possible_package.append(name)
133
134
135     # Go through the directory listing searching for anything
136     # that matches the given name
137     for i in dirlist:
138         directory = PORTDIR + i
139         if os.path.isdir(directory):
140             dirs = os.listdir(directory)
141             if name in dirs:
142                 possible_package.append(i + '/' + name)
143
144
145     if len(possible_package) > 1:
146         print("Multiple packages found for '" + name + "'.")
147         print("Possible packages: ")
148         for value in possible_package:
149             print("\t" + value)
150
151
152     elif len(possible_package) == 1:
153         package = possible_package[0]
154         return package
155
156
157     else:
158         print("No package '" + name + "' found")
159
160
161     sys.exit(1)
162
163
164
165 def print_times(package, times, silent):
166     """Print the maximum/minimum/average times of the given emerge package.
167     If we're in the 'current emerge stage' (the 'silent' flag is True)
168     print the appropriate comment for that package."""
169
170
171     times.sort()
172     times.reverse()
173
174
175     # This should be True if we're in current emerge stage
176     if silent == True:
177         if len(times) == 0:
178             print("\t  no previous emerges found for this package"),
179             return 0
180
181         elif len(times) == 1:
182             print("\t  previous emerge time:\t"),
183             organize_times(times[0][0])
184             print("(only one emerge previously)"),
185             return times[0][0]
186
187         else:
188             print("\t  average emerge time:\t"),
189             all_times = 0
190             for i in times:
191                 all_times += i[0]
192
193             organize_times(all_times/len(times))
194
195         return all_times/len(times)
196
197
198     if len(times) == 1:
199         print(green_start + package + color_stop + " emerged once")
200
201     elif len(times) > 1:
202         print(green_start + package + color_stop + " emerged " + green_start +
203               str(len(times)) + color_stop + " times\n")
204
205         print "Max time:\t",
206         organize_times(times[0][0])
207         print "at", times[0][1]
208
209         print "Min time:\t",
210         organize_times(times[len(times)-1][0])
211         print "at", times[len(times)-1][1]
212
213         all_times = 0
214         for i in times:
215             all_times += i[0]
216
217         print "Average time\t",
218         organize_times(all_times/len(times))
219         print
220
221         print "In total spent\t",
222         organize_times(all_times)
223         print("emerging " + green_start +
224               package + color_stop)
225
226
227
228 def open_log():
229     """Attempt to open the LOGFILE."""
230
231     try:
232         f = open(LOGFILE, 'r')
233     except IOError as detail:
234         print detail
235         sys.exit(1)
236     finally:
237         return f
238
239
240
241 def list_emerge_processes(f):
242     """Look for the ebuild process with ps. If the process is found parse
243     the command for the package. With this package search the LOGFILE for
244     the emerge startup time."""
245
246     now = datetime.datetime.today()
247     packages = []
248
249     for i in os.popen("ps ax"):
250         if (("ebuild" in i) and ("/bin/bash" not in i)):
251              pack = i.partition('[')[2].partition(']')[0]
252
253              packages.append([pack, 12*3600])
254
255
256     for line in f:
257         if ((">>>" in line) and ("emerge" in line)):
258             for p in packages:
259                 if (p[0] in line):
260
261                     time = float(line.partition(' ')[0].strip(":"))
262
263                     timestamp = datetime.datetime.fromtimestamp(time)
264                     difference = (now - timestamp).total_seconds()
265
266                     if difference < p[1]:
267                         p[1] = difference
268
269
270     if len(packages) == 0:
271         print "No current emerge process found."
272         return
273
274     print_current_emerges(f, packages)
275
276
277
278
279 def print_current_emerges(f, packages):
280     """Print the current packages that are being merged with the
281     current emerge time."""
282
283     all_packages = list_all_packages()
284
285     print("Currently emerging: ")
286
287     for p in packages:
288         print("\t" + green_start + p[0] + color_stop),
289         print("\n\t  current emerge time:\t"),
290
291         organize_times(p[1])
292         print
293
294
295         for i in all_packages:
296             if i in p[0]:
297                 average_time = main_loop(f, i, True)
298
299         if average_time != 0:
300             print("\n\t  " + '-'*45 + "\n\t  time to finish: \t"),
301             if (average_time - p[1]) < 0:
302                 print(green_start + "Any time now" + color_stop),
303             else:
304                 organize_times(average_time - p[1])
305             print "\n"
306
307
308
309 def list_pretended(f):
310     """Print the average times of pretended packages"""
311
312     all_packages = list_all_packages()
313
314     packages = []
315     for line in sys.stdin:
316         if "[ebuild" in line:
317             full_name = line.partition('] ')[2].partition(' ')[0]
318
319             version = full_name.partition('/')[2].partition('-')[2]
320             while not version[0].isdigit():
321                 version = version.partition('-')[2]
322
323             package_name = full_name[:-len(version)-1]
324
325             packages.append((package_name, '-' + version))
326
327
328     if len(packages) == 0:
329         return
330
331     print "This is how long these packages would take to emerge"
332
333     all_time = 0
334     for pack in packages:
335
336         print('\t' + green_start + pack[0] + pack[1] + color_stop)
337
338         all_time += main_loop(f, pack[0], True)
339
340         print "\n"
341
342
343     if all_time != 0:
344         print("Total emerge time of " + green_start + str(len(packages)) +
345               color_stop + " packages:"),
346         organize_times(all_time)
347
348
349
350
351 def main_loop(f, package, silent):
352     """The main loop which parses the LOGFILE and if needed prints out emerge times."""
353
354     f.seek(0) # Seek to the beginning of the file
355     times = []
356
357     # MAIN LOOP
358     for line in f:
359         if ((">>>" in line) and ("emerge" in line)):
360             if package in line:
361                 version = line.partition(package)[2].partition(' ')[0]
362
363                 if version.strip('-')[0].isdigit():
364                     full_package = package + version
365
366                     time_string = line.partition(">>>")
367                     start_time = float(time_string[0].strip().strip(':'))
368
369
370         elif ((":::" in line) and ("completed emerge" in line)):
371             if package in line:
372                 if version.strip('-')[0].isdigit():
373
374                     time_string = line.partition(":::")
375                     end_time = float(time_string[0].strip().strip(':'))
376
377
378                     emerge_time = end_time - start_time
379
380                     date = get_date(start_time)
381
382
383                     if silent == False:
384                         print(str(len(times)+1) + ". " +
385                               green_start + full_package + color_stop +
386                               "  >>>  " + date + "  >>>  "),
387
388                         organize_times(emerge_time)
389
390                         print("\n" + '-'*90)
391
392
393                     times.append((emerge_time, date))
394
395
396     average_time = print_times(package, times, silent)
397     return average_time
398
399
400
401 def main(status):
402     """Change between current emerge stage and normal operating stage."""
403
404     f = open_log()
405
406     if status == 'current':
407         list_emerge_processes(f)
408         return
409     elif status == 'pretended':
410         list_pretended(f)
411         return
412     else:
413         pass
414
415     package = get_package(package_name)
416
417     print('-'*90)
418
419     main_loop(f, package, False)
420
421     f.close()
422
423
424
425 if __name__ == "__main__":
426
427     if len(sys.argv) == 1:
428         main('current')
429         sys.exit(1)
430
431     elif sys.argv[1] == "-p":
432         main('pretended')
433         sys.exit(1)
434
435     elif ((sys.argv[1] == "-h") or (sys.argv[1] == "--help")):
436         print("Usage: emerge-timer.py [options] [package]\n\nOptions:\n"
437               + green_start + "\t-p" + color_stop +
438               "\tcalculate compile time from piped 'emerge -p' output\n" +
439               green_start + "\t[none]" + color_stop +
440               "\tShow average emerge times for currently compiling packages.")
441         sys.exit(1)
442
443     if len(sys.argv) > 1:
444         package_name = sys.argv[1]
445         main(0)
446
447