]> git.itanic.dy.fi Git - emerge-timer/blob - emerge-timer.py
Beautify output (cont.)
[emerge-timer] / emerge-timer.py
1 #!/usr/bin/python
2
3
4 import sys, datetime, os
5
6
7 PORTDIR = "/usr/portage/"
8 LOGFILE = "/var/log/emerge.log"
9
10
11 green_start = "\033[32m"
12 color_stop = "\033[m"
13
14 QUIET = False
15
16 PACKAGES = []
17
18
19
20 class package:
21     def __init__(self, name, version=0):
22         self.name = name
23         self.version = version
24         self.versions = []
25         self.emerge_time = 12*3600
26
27
28     def add_version(self, version, emerge_time, emerge_date):
29         """Add version to the class version list"""
30         self.versions.append((version, emerge_time, emerge_date))
31
32
33     def average_time(self):
34         """Return average time from class version list"""
35         total_time = 0
36         for i in self.versions:
37             total_time += i[1]
38
39         average_time = total_time/len(self.versions)
40
41         return average_time
42
43
44     def total_time(self):
45         """Return total time from class version list"""
46         total_time = 0
47         for i in self.versions:
48             total_time += i[1]
49
50         return total_time
51
52
53     def max_time(self):
54         """Return maximum time from class version list"""
55         self.versions.sort()
56
57         return self.versions[len(self.versions)-1][1]
58
59
60     def min_time(self):
61         """Return minimum time from class version list"""
62         self.versions.sort()
63
64         return self.versions[0][1]
65
66
67     def print_current_emerge(self):
68         """Function used to print all the current emerge stuff"""
69
70         print("\t" + green_start + self.name + '-' + self.version +
71               color_stop + "\n\t current time: " + give_time(self.emerge_time) +
72               "\n\t average time: "),
73
74         if len(self.versions) > 1:
75             print(give_time(self.average_time())),
76         else:
77             print("unknown"),
78
79         print("\n\t " + '-'*45),
80
81         finish_time = self.average_time() - self.emerge_time
82
83         print("\n\t time to finish: "),
84
85         if finish_time > 0:
86             print(give_time(finish_time))
87         else:
88             print("any time now")
89         print
90
91
92     def print_versions(self):
93         """This prints the emerge times for different versions in the
94         normal operating mode of the script"""
95
96         if QUIET == False:
97
98             version_length = 0
99             time_length = 0
100
101             for p in self.versions:
102                 if len(p[0]) > version_length:
103                     version_length = len(p[0])
104
105                 if len(give_time(p[1])) > time_length:
106                     time_length = len(give_time(p[1]))
107
108             for p in self.versions:
109
110                 print('-'*90 + "\n" +
111                       green_start + self.name + (p[0]).ljust(version_length) +
112                       color_stop + "  >>>  " + (give_time(p[1])).ljust(time_length)
113                       + "  >>>  " + give_date(p[2]))
114
115         print('-'*90 + "\n" + "Package " + green_start +
116               self.name + color_stop + " emerged " +
117               str(len(self.versions)) + " times.")
118
119         print
120
121
122     def print_pretended_times(self):
123         """This is used the print all the pretended times"""
124
125         if QUIET == False:
126             print("\t" + green_start + self.name + '-' + self.version + color_stop),
127
128         if len(self.versions) > 1:
129             aver_time = self.average_time()
130
131             if QUIET == False:
132                 print("\n\taverage time: " + give_time(aver_time))
133
134             return aver_time
135
136         else:
137             if QUIET == False:
138                 print("\n\t no previous emerges")
139
140             return 0
141
142
143     def print_min_max_ave(self):
144         maxi = self.max_time()
145         mini = self.min_time()
146         average = self.average_time()
147         total = self.total_time()
148
149         print("Max time: \t" + give_time(maxi) +
150               "\nMin time: \t" + give_time(mini) +
151               "\nAverage time: \t" + give_time(average) +
152               "\nIn total spent " + give_time(total) +
153               " emerging " + green_start + self.name + color_stop)
154
155
156
157 def give_time(time):
158     """Converts time in seconds to human readable form"""
159     days = time/(3600*24)
160     hours = (days - int(days))*24
161     minutes = (hours - int(hours))*60
162     seconds = (minutes - int(minutes))*60
163
164     days = int(days)
165     hours = int(hours)
166     minutes = int(minutes)
167     seconds = int(round(seconds))
168
169     pdays = str()
170     phours = str()
171     pminutes = str()
172     pseconds = str()
173
174     if days > 0:
175         pdays = (green_start + str(days) +
176                  color_stop + " day ")
177         if days != 1:
178             pdays = (green_start + str(days) +
179                          color_stop + " days ")
180
181     if hours > 0:
182         phours = (green_start + str(hours) +
183                   color_stop + " hour ")
184         if hours != 1:
185             phours = (green_start + str(hours) +
186                           color_stop + " hours ")
187
188     if minutes > 0:
189         pminutes = (green_start + str(minutes) +
190                     color_stop + " minute ")
191         if minutes != 1:
192             pminutes = (green_start + str(minutes) +
193                         color_stop + " minutes ")
194
195     pseconds = (green_start + str(seconds) +
196                 color_stop + " second ")
197     if seconds != 1:
198         pseconds = (green_start + str(seconds) +
199                     color_stop + " seconds ")
200
201     return (pdays + phours + pminutes + pseconds)
202
203
204
205 def give_date(emerge_date):
206     """Returns a date string from a standard POSIX time"""
207     date = datetime.datetime.fromtimestamp(emerge_date)
208
209     date = "{:%d.%m.%Y %H:%M:%S}".format(date)
210
211     return date
212
213
214
215 def open_log():
216     """Attempt to open the LOGFILE."""
217
218     try:
219         f = open(LOGFILE, 'r')
220     except IOError as detail:
221         print detail
222         sys.exit(1)
223
224     return f
225
226
227
228 def search_log_for_package(package_class):
229     """Searchs emerge log for given package and adds all found
230     versions with their emerge times to the class"""
231
232     log = open_log()
233
234     for line in log:
235         if ((">>>" in line) and ("emerge" in line)):
236             if package_class.name in line:
237
238                 version = line.partition(package_class.name)[2].partition(' ')[0]
239                 digit = version.strip('-')[0].isdigit()
240
241                 if digit:
242                     time_string = line.partition(">>>")
243                     start_time = float(time_string[0].strip().strip(':'))
244
245         elif ((":::" in line) and ("completed emerge" in line)):
246
247             if package_class.name in line:
248                 if digit:
249                     time_string = line.partition(":::")
250                     stop_time = float(time_string[0].strip().strip(':'))
251
252                     emerge_time = stop_time - start_time
253
254                     package_class.add_version(version, emerge_time, start_time)
255
256
257
258 def get_package(name):
259     """Take the user-input package name and search for it
260     in PORTDIR. """
261
262     dirlist = os.listdir(PORTDIR)
263     possible_package = []
264
265
266     # If the given name is in the format xxx/zzz
267     # assume that xxx is the package group
268     if '/' in name:
269         group = name.partition('/')[0]
270         pkg = name.partition('/')[2]
271         directory = PORTDIR + group
272
273         if group in dirlist:
274             dirs = os.listdir(directory)
275             if pkg in dirs:
276                 possible_package.append(name)
277
278
279     # Go through the directory listing searching for anything
280     # that matches the given name
281     for i in dirlist:
282         directory = PORTDIR + i
283         if os.path.isdir(directory):
284             dirs = os.listdir(directory)
285             if name in dirs:
286                 possible_package.append(i + '/' + name)
287
288
289     if len(possible_package) > 1:
290         print("Multiple packages found for '" + name + "'.")
291         print("Possible packages: ")
292         for value in possible_package:
293             print("\t" + value)
294
295
296     elif len(possible_package) == 1:
297         package = possible_package[0]
298         return package
299
300
301     else:
302         print("No package '" + name + "' found")
303
304
305     sys.exit(1)
306
307
308
309 def list_pretended():
310     """List all the pretended packages given by emerge -p
311     output. Create a class out of each of those packages and add them
312     to the list."""
313
314     log = open_log()
315
316     for line in sys.stdin:
317         if "[ebuild" in line:
318             full_name = line.partition("] ")[2].partition(' ')[0]
319
320             version = full_name.partition('/')[2].partition('-')[2]
321             while not version[0].isdigit():
322                 version = version.partition('-')[2]
323             package_name = full_name[:-len(version)-1]
324
325             PACKAGES.append(package(package_name, version))
326
327
328
329 def list_emerge_processes():
330     """Look for the ebuild process with ps. If the process is found parse
331     the command for the package. With this package search the LOGFILE for
332     the emerge startup time."""
333
334     f = open_log()
335
336     now = datetime.datetime.today()
337
338     for i in os.popen("ps ax"):
339         if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
340             pack = i.partition('[')[2].partition(']')[0]
341
342             version = pack.partition('/')[2].partition('-')[2]
343
344             while not version[0].isdigit():
345                 version = version.partition('-')[2]
346
347             package_name = pack[:-len(version)-1]
348
349             PACKAGES.append(package(package_name, version))
350
351
352     if len(PACKAGES) == 0:
353         print "No current emerge process found."
354         sys.exit(0)
355
356
357     for line in f:
358         if ((">>>" in line) and ("emerge" in line)):
359             for p in PACKAGES:
360                 if (p.name + '-' + p.version in line):
361
362                     time = float(line.partition(' ')[0].strip(":"))
363
364                     timestamp = datetime.datetime.fromtimestamp(time)
365                     difference = (now - timestamp).total_seconds()
366
367                     if difference < p.emerge_time:
368                         p.emerge_time = difference
369
370
371
372 def main(status, user_package=None):
373     """Main function. Hanlde all the different modes of operation."""
374
375     if status == "package":
376         user_package = get_package(user_package)
377
378         pack = package(user_package)
379
380         search_log_for_package(pack)
381         pack.print_versions()
382         pack.print_min_max_ave()
383
384
385     elif status == "current":
386         list_emerge_processes()
387
388         print "Currently emerging:"
389
390         for p in PACKAGES:
391             search_log_for_package(p)
392             p.print_current_emerge()
393
394
395     elif status == "pretended":
396         list_pretended()
397
398         print "This is how long these packages would take to emerge"
399
400         total_pretended_time = 0
401
402         for p in PACKAGES:
403             search_log_for_package(p)
404
405             total_pretended_time += p.print_pretended_times()
406
407             print
408
409         print("Total emerge time of " + green_start + str(len(PACKAGES)) +
410               color_stop + " package(s): "+ give_time(total_pretended_time))
411
412
413 def usage():
414     usage = """Usage: emerge-timer.py [package] [options]
415
416 Calculate emerge times from emerge log.
417
418 Options:
419 \t-c, --current \t Show time until currently compiling package finishes
420 \t-p, --pretended  Calculate compile time from piped 'emerge -p' output
421 \t-h, --help \t Show this helpscreen
422 \t-q, --quiet \t Be less verbose
423 \t--no-color \t Use colorless output"""
424
425     print usage
426
427     sys.exit(0)
428
429
430 if __name__ == "__main__":
431
432     # Set the default mode as "package"
433     mode = "package"
434     input_package = None
435
436
437     for arg in sys.argv[1:]:
438
439         if arg == "-p" or arg == "--pretended":
440             mode = "pretended"
441
442         if arg == "-c" or arg == "--current":
443             mode = "current"
444
445         if arg == "-h" or arg == "--help":
446             usage()
447
448         if arg == "-q" or arg == "--quiet":
449             QUIET = True
450
451         if arg == "--no-color":
452             green_start = ""
453             color_stop = ""
454
455
456     if len(sys.argv) > 1:
457         input_package = sys.argv[1]
458     else:
459         usage()
460
461     main(mode, input_package)