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