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