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