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