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