4 import sys, datetime, os
7 PORTDIR = "/usr/portage/"
8 LOGFILE = "/var/log/emerge.log"
11 green_start = "\033[32m"
21 def __init__(self, name, version=0):
23 self.version = version
25 self.emerge_time = 12*3600
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))
33 def average_time(self):
34 """Return average time from class version list"""
36 for i in self.versions:
39 average_time = total_time/len(self.versions)
45 """Return total time from class version list"""
47 for i in self.versions:
54 """Return maximum time from class version list"""
57 return self.versions[len(self.versions)-1][1]
61 """Return minimum time from class version list"""
64 return self.versions[0][1]
67 def print_current_emerge(self):
68 """Function used to print all the current emerge stuff"""
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: "),
74 if len(self.versions) > 1:
75 print(give_time(self.average_time())),
79 print("\n\t " + '-'*45),
81 finish_time = self.average_time() - self.emerge_time
83 print("\n\t time to finish: "),
86 print(give_time(finish_time))
92 def print_versions(self):
93 """This prints the emerge times for different versions in the
94 normal operating mode of the script"""
101 for p in self.versions:
102 if len(p[0]) > version_length:
103 version_length = len(p[0])
105 if len(give_time(p[1], True)) > time_length:
106 time_length = len(give_time(p[1], True))
108 for p in self.versions:
110 pad = time_length - len(give_time(p[1], True))
112 print('-'*90 + "\n" +
113 green_start + self.name + (p[0]).ljust(version_length) +
114 color_stop + " >>> " + (give_time(p[1])) + " "*pad +
115 " >>> " + give_date(p[2]))
117 print('-'*90 + "\n" + "Package " + green_start +
118 self.name + color_stop + " emerged " +
119 str(len(self.versions)) + " times.")
124 def print_pretended_times(self):
125 """This is used the print all the pretended times"""
128 print("\t" + green_start + self.name + '-' + self.version + color_stop),
130 if len(self.versions) > 1:
131 aver_time = self.average_time()
134 print("\n\taverage time: " + give_time(aver_time))
140 print("\n\t no previous emerges")
145 def print_min_max_ave(self):
146 maxi = self.max_time()
147 mini = self.min_time()
148 average = self.average_time()
149 total = self.total_time()
151 print("Max time: \t" + give_time(maxi) +
152 "\nMin time: \t" + give_time(mini) +
153 "\nAverage time: \t" + give_time(average) +
154 "\nIn total spent " + give_time(total) +
155 " emerging " + green_start + self.name + color_stop)
159 def give_time(time, nocolor=False):
160 """Converts time in seconds to human readable form"""
161 global green_start, color_stop
167 days = time/(3600*24)
168 hours = (days - int(days))*24
169 minutes = (hours - int(hours))*60
170 seconds = (minutes - int(minutes))*60
174 minutes = int(minutes)
175 seconds = int(round(seconds))
183 pdays = (green_start + str(days) +
184 color_stop + " day ")
186 pdays = (green_start + str(days) +
187 color_stop + " days ")
190 phours = (green_start + str(hours) +
191 color_stop + " hour ")
193 phours = (green_start + str(hours) +
194 color_stop + " hours ")
197 pminutes = (green_start + str(minutes) +
198 color_stop + " minute ")
200 pminutes = (green_start + str(minutes) +
201 color_stop + " minutes ")
203 pseconds = (green_start + str(seconds) +
204 color_stop + " second ")
206 pseconds = (green_start + str(seconds) +
207 color_stop + " seconds ")
209 green_start = "\033[32m"
210 color_stop = "\033[m"
212 return (pdays + phours + pminutes + pseconds)
216 def give_date(emerge_date):
217 """Returns a date string from a standard POSIX time"""
218 date = datetime.datetime.fromtimestamp(emerge_date)
220 date = "{:%d.%m.%Y %H:%M:%S}".format(date)
227 """Attempt to open the LOGFILE."""
230 f = open(LOGFILE, 'r')
231 except IOError as detail:
239 def search_log_for_package(package_class):
240 """Searchs emerge log for given package and adds all found
241 versions with their emerge times to the class"""
246 if ((">>>" in line) and ("emerge" in line)):
247 if package_class.name in line:
249 version = line.partition(package_class.name)[2].partition(' ')[0]
250 digit = version.strip('-')[0].isdigit()
253 time_string = line.partition(">>>")
254 start_time = float(time_string[0].strip().strip(':'))
256 elif ((":::" in line) and ("completed emerge" in line)):
258 if package_class.name in line:
260 time_string = line.partition(":::")
261 stop_time = float(time_string[0].strip().strip(':'))
263 emerge_time = stop_time - start_time
265 package_class.add_version(version, emerge_time, start_time)
269 def get_package(name):
270 """Take the user-input package name and search for it
273 dirlist = os.listdir(PORTDIR)
274 possible_package = []
277 # If the given name is in the format xxx/zzz
278 # assume that xxx is the package group
280 group = name.partition('/')[0]
281 pkg = name.partition('/')[2]
282 directory = PORTDIR + group
285 dirs = os.listdir(directory)
287 possible_package.append(name)
290 # Go through the directory listing searching for anything
291 # that matches the given name
293 directory = PORTDIR + i
294 if os.path.isdir(directory):
295 dirs = os.listdir(directory)
297 possible_package.append(i + '/' + name)
300 if len(possible_package) > 1:
301 print("Multiple packages found for '" + name + "'.")
302 print("Possible packages: ")
303 for value in possible_package:
307 elif len(possible_package) == 1:
308 package = possible_package[0]
313 print("No package '" + name + "' found")
320 def list_pretended():
321 """List all the pretended packages given by emerge -p
322 output. Create a class out of each of those packages and add them
327 for line in sys.stdin:
328 if "[ebuild" in line:
329 full_name = line.partition("] ")[2].partition(' ')[0]
331 version = full_name.partition('/')[2].partition('-')[2]
332 while not version[0].isdigit():
333 version = version.partition('-')[2]
334 package_name = full_name[:-len(version)-1]
336 PACKAGES.append(package(package_name, version))
340 def list_emerge_processes():
341 """Look for the ebuild process with ps. If the process is found parse
342 the command for the package. With this package search the LOGFILE for
343 the emerge startup time."""
347 now = datetime.datetime.today()
349 for i in os.popen("ps ax"):
350 if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
351 pack = i.partition('[')[2].partition(']')[0]
353 version = pack.partition('/')[2].partition('-')[2]
355 while not version[0].isdigit():
356 version = version.partition('-')[2]
358 package_name = pack[:-len(version)-1]
360 PACKAGES.append(package(package_name, version))
363 if len(PACKAGES) == 0:
364 print "No current emerge process found."
369 if ((">>>" in line) and ("emerge" in line)):
371 if (p.name + '-' + p.version in line):
373 time = float(line.partition(' ')[0].strip(":"))
375 timestamp = datetime.datetime.fromtimestamp(time)
376 difference = (now - timestamp).total_seconds()
378 if difference < p.emerge_time:
379 p.emerge_time = difference
383 def main(status, user_package=None):
384 """Main function. Hanlde all the different modes of operation."""
386 if status == "package":
387 user_package = get_package(user_package)
389 pack = package(user_package)
391 search_log_for_package(pack)
392 pack.print_versions()
393 pack.print_min_max_ave()
396 elif status == "current":
397 list_emerge_processes()
399 print "Currently emerging:"
402 search_log_for_package(p)
403 p.print_current_emerge()
406 elif status == "pretended":
409 print "This is how long these packages would take to emerge"
411 total_pretended_time = 0
414 search_log_for_package(p)
416 total_pretended_time += p.print_pretended_times()
420 print("Total emerge time of " + green_start + str(len(PACKAGES)) +
421 color_stop + " package(s): "+ give_time(total_pretended_time))
425 usage = """Usage: emerge-timer.py [package] [options]
427 Calculate emerge times from emerge log.
430 \t-c, --current \t Show time until currently compiling package finishes
431 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
432 \t-h, --help \t Show this helpscreen
433 \t-q, --quiet \t Be less verbose
434 \t--no-color \t Use colorless output"""
441 if __name__ == "__main__":
443 # Set the default mode as "package"
448 for arg in sys.argv[1:]:
450 if arg == "-p" or arg == "--pretended":
453 if arg == "-c" or arg == "--current":
456 if arg == "-h" or arg == "--help":
459 if arg == "-q" or arg == "--quiet":
462 if arg == "--no-color":
467 if len(sys.argv) > 1:
468 input_package = sys.argv[1]
472 main(mode, input_package)