]> git.itanic.dy.fi Git - emerge-timer/blob - emerge-timer.py
give_time(): Add nocolor option
[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, nocolor=False):
158     """Converts time in seconds to human readable form"""
159     global green_start, color_stop
160
161     if nocolor == True:
162         green_start = ""
163         color_stop = ""
164
165     days = time/(3600*24)
166     hours = (days - int(days))*24
167     minutes = (hours - int(hours))*60
168     seconds = (minutes - int(minutes))*60
169
170     days = int(days)
171     hours = int(hours)
172     minutes = int(minutes)
173     seconds = int(round(seconds))
174
175     pdays = str()
176     phours = str()
177     pminutes = str()
178     pseconds = str()
179
180     if days > 0:
181         pdays = (green_start + str(days) +
182                  color_stop + " day ")
183         if days != 1:
184             pdays = (green_start + str(days) +
185                          color_stop + " days ")
186
187     if hours > 0:
188         phours = (green_start + str(hours) +
189                   color_stop + " hour ")
190         if hours != 1:
191             phours = (green_start + str(hours) +
192                           color_stop + " hours ")
193
194     if minutes > 0:
195         pminutes = (green_start + str(minutes) +
196                     color_stop + " minute ")
197         if minutes != 1:
198             pminutes = (green_start + str(minutes) +
199                         color_stop + " minutes ")
200
201     pseconds = (green_start + str(seconds) +
202                 color_stop + " second ")
203     if seconds != 1:
204         pseconds = (green_start + str(seconds) +
205                     color_stop + " seconds ")
206
207     green_start = "\033[32m"
208     color_stop = "\033[m"
209
210     return (pdays + phours + pminutes + pseconds)
211
212
213
214 def give_date(emerge_date):
215     """Returns a date string from a standard POSIX time"""
216     date = datetime.datetime.fromtimestamp(emerge_date)
217
218     date = "{:%d.%m.%Y %H:%M:%S}".format(date)
219
220     return date
221
222
223
224 def open_log():
225     """Attempt to open the LOGFILE."""
226
227     try:
228         f = open(LOGFILE, 'r')
229     except IOError as detail:
230         print detail
231         sys.exit(1)
232
233     return f
234
235
236
237 def search_log_for_package(package_class):
238     """Searchs emerge log for given package and adds all found
239     versions with their emerge times to the class"""
240
241     log = open_log()
242
243     for line in log:
244         if ((">>>" in line) and ("emerge" in line)):
245             if package_class.name in line:
246
247                 version = line.partition(package_class.name)[2].partition(' ')[0]
248                 digit = version.strip('-')[0].isdigit()
249
250                 if digit:
251                     time_string = line.partition(">>>")
252                     start_time = float(time_string[0].strip().strip(':'))
253
254         elif ((":::" in line) and ("completed emerge" in line)):
255
256             if package_class.name in line:
257                 if digit:
258                     time_string = line.partition(":::")
259                     stop_time = float(time_string[0].strip().strip(':'))
260
261                     emerge_time = stop_time - start_time
262
263                     package_class.add_version(version, emerge_time, start_time)
264
265
266
267 def get_package(name):
268     """Take the user-input package name and search for it
269     in PORTDIR. """
270
271     dirlist = os.listdir(PORTDIR)
272     possible_package = []
273
274
275     # If the given name is in the format xxx/zzz
276     # assume that xxx is the package group
277     if '/' in name:
278         group = name.partition('/')[0]
279         pkg = name.partition('/')[2]
280         directory = PORTDIR + group
281
282         if group in dirlist:
283             dirs = os.listdir(directory)
284             if pkg in dirs:
285                 possible_package.append(name)
286
287
288     # Go through the directory listing searching for anything
289     # that matches the given name
290     for i in dirlist:
291         directory = PORTDIR + i
292         if os.path.isdir(directory):
293             dirs = os.listdir(directory)
294             if name in dirs:
295                 possible_package.append(i + '/' + name)
296
297
298     if len(possible_package) > 1:
299         print("Multiple packages found for '" + name + "'.")
300         print("Possible packages: ")
301         for value in possible_package:
302             print("\t" + value)
303
304
305     elif len(possible_package) == 1:
306         package = possible_package[0]
307         return package
308
309
310     else:
311         print("No package '" + name + "' found")
312
313
314     sys.exit(1)
315
316
317
318 def list_pretended():
319     """List all the pretended packages given by emerge -p
320     output. Create a class out of each of those packages and add them
321     to the list."""
322
323     log = open_log()
324
325     for line in sys.stdin:
326         if "[ebuild" in line:
327             full_name = line.partition("] ")[2].partition(' ')[0]
328
329             version = full_name.partition('/')[2].partition('-')[2]
330             while not version[0].isdigit():
331                 version = version.partition('-')[2]
332             package_name = full_name[:-len(version)-1]
333
334             PACKAGES.append(package(package_name, version))
335
336
337
338 def list_emerge_processes():
339     """Look for the ebuild process with ps. If the process is found parse
340     the command for the package. With this package search the LOGFILE for
341     the emerge startup time."""
342
343     f = open_log()
344
345     now = datetime.datetime.today()
346
347     for i in os.popen("ps ax"):
348         if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
349             pack = i.partition('[')[2].partition(']')[0]
350
351             version = pack.partition('/')[2].partition('-')[2]
352
353             while not version[0].isdigit():
354                 version = version.partition('-')[2]
355
356             package_name = pack[:-len(version)-1]
357
358             PACKAGES.append(package(package_name, version))
359
360
361     if len(PACKAGES) == 0:
362         print "No current emerge process found."
363         sys.exit(0)
364
365
366     for line in f:
367         if ((">>>" in line) and ("emerge" in line)):
368             for p in PACKAGES:
369                 if (p.name + '-' + p.version in line):
370
371                     time = float(line.partition(' ')[0].strip(":"))
372
373                     timestamp = datetime.datetime.fromtimestamp(time)
374                     difference = (now - timestamp).total_seconds()
375
376                     if difference < p.emerge_time:
377                         p.emerge_time = difference
378
379
380
381 def main(status, user_package=None):
382     """Main function. Hanlde all the different modes of operation."""
383
384     if status == "package":
385         user_package = get_package(user_package)
386
387         pack = package(user_package)
388
389         search_log_for_package(pack)
390         pack.print_versions()
391         pack.print_min_max_ave()
392
393
394     elif status == "current":
395         list_emerge_processes()
396
397         print "Currently emerging:"
398
399         for p in PACKAGES:
400             search_log_for_package(p)
401             p.print_current_emerge()
402
403
404     elif status == "pretended":
405         list_pretended()
406
407         print "This is how long these packages would take to emerge"
408
409         total_pretended_time = 0
410
411         for p in PACKAGES:
412             search_log_for_package(p)
413
414             total_pretended_time += p.print_pretended_times()
415
416             print
417
418         print("Total emerge time of " + green_start + str(len(PACKAGES)) +
419               color_stop + " package(s): "+ give_time(total_pretended_time))
420
421
422 def usage():
423     usage = """Usage: emerge-timer.py [package] [options]
424
425 Calculate emerge times from emerge log.
426
427 Options:
428 \t-c, --current \t Show time until currently compiling package finishes
429 \t-p, --pretended  Calculate compile time from piped 'emerge -p' output
430 \t-h, --help \t Show this helpscreen
431 \t-q, --quiet \t Be less verbose
432 \t--no-color \t Use colorless output"""
433
434     print usage
435
436     sys.exit(0)
437
438
439 if __name__ == "__main__":
440
441     # Set the default mode as "package"
442     mode = "package"
443     input_package = None
444
445
446     for arg in sys.argv[1:]:
447
448         if arg == "-p" or arg == "--pretended":
449             mode = "pretended"
450
451         if arg == "-c" or arg == "--current":
452             mode = "current"
453
454         if arg == "-h" or arg == "--help":
455             usage()
456
457         if arg == "-q" or arg == "--quiet":
458             QUIET = True
459
460         if arg == "--no-color":
461             green_start = ""
462             color_stop = ""
463
464
465     if len(sys.argv) > 1:
466         input_package = sys.argv[1]
467     else:
468         usage()
469
470     main(mode, input_package)