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