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