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