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