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))
88 print(green_start + "any time now" + color_stop)
92 def print_versions(self):
93 """This prints the emerge times for different versions in the
94 'package' 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
163 if green_start == "":
170 days = time/(3600*24)
171 hours = (days - int(days))*24
172 minutes = (hours - int(hours))*60
173 seconds = (minutes - int(minutes))*60
177 minutes = int(minutes)
178 seconds = int(round(seconds))
186 pdays = (green_start + str(days) +
187 color_stop + " day ")
189 pdays = (green_start + str(days) +
190 color_stop + " days ")
193 phours = (green_start + str(hours) +
194 color_stop + " hour ")
196 phours = (green_start + str(hours) +
197 color_stop + " hours ")
200 pminutes = (green_start + str(minutes) +
201 color_stop + " minute ")
203 pminutes = (green_start + str(minutes) +
204 color_stop + " minutes ")
206 pseconds = (green_start + str(seconds) +
207 color_stop + " second ")
209 pseconds = (green_start + str(seconds) +
210 color_stop + " seconds ")
213 green_start = "\033[32m"
214 color_stop = "\033[m"
216 return (pdays + phours + pminutes + pseconds)
220 def give_date(emerge_date):
221 """Returns a date string from a standard POSIX time"""
222 date = datetime.datetime.fromtimestamp(emerge_date)
224 date = "{:%d.%m.%Y %H:%M:%S}".format(date)
231 """Attempt to open the LOGFILE."""
234 f = open(LOGFILE, 'r')
235 except IOError as detail:
243 def search_log_for_package(package_class):
244 """Searchs emerge log for given package and adds all found
245 versions with their emerge times to the class"""
250 if ((">>>" in line) and ("emerge" in line)):
251 if package_class.name in line:
253 version = line.partition(package_class.name)[2].partition(' ')[0]
254 digit = version.strip('-')[0].isdigit()
257 time_string = line.partition(">>>")
258 start_time = float(time_string[0].strip().strip(':'))
260 elif ((":::" in line) and ("completed emerge" in line)):
262 if package_class.name in line:
264 time_string = line.partition(":::")
265 stop_time = float(time_string[0].strip().strip(':'))
267 emerge_time = stop_time - start_time
269 package_class.add_version(version, emerge_time, start_time)
273 def get_package(name):
274 """Take the user-input package name and search for it
277 dirlist = os.listdir(PORTDIR)
278 possible_package = []
281 # If the given name is in the format xxx/zzz
282 # assume that xxx is the package group
284 group = name.partition('/')[0]
285 pkg = name.partition('/')[2]
286 directory = PORTDIR + group
289 dirs = os.listdir(directory)
291 possible_package.append(name)
294 # Go through the directory listing searching for anything
295 # that matches the given name
297 directory = PORTDIR + i
298 if os.path.isdir(directory):
299 dirs = os.listdir(directory)
301 possible_package.append(i + '/' + name)
304 if len(possible_package) > 1:
305 print("Multiple packages found for '" + name + "'.")
306 print("Possible packages: ")
307 for value in possible_package:
311 elif len(possible_package) == 1:
312 package = possible_package[0]
317 print("No package '" + name + "' found")
324 def list_pretended():
325 """List all the pretended packages given by emerge -p
326 output. Create a class out of each of those packages and add them
331 for line in sys.stdin:
332 if "[ebuild" in line:
333 full_name = line.partition("] ")[2].partition(' ')[0]
335 version = full_name.partition('/')[2].partition('-')[2]
336 while not version[0].isdigit():
337 version = version.partition('-')[2]
338 package_name = full_name[:-len(version)-1]
340 PACKAGES.append(package(package_name, version))
344 def list_emerge_processes():
345 """Look for the ebuild process with ps. If the process is found parse
346 the command for the package. With this package search the LOGFILE for
347 the emerge startup time."""
351 now = datetime.datetime.today()
353 for i in os.popen("ps ax"):
354 if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
355 pack = i.partition('[')[2].partition(']')[0]
357 version = pack.partition('/')[2].partition('-')[2]
359 while not version[0].isdigit():
360 version = version.partition('-')[2]
362 package_name = pack[:-len(version)-1]
364 PACKAGES.append(package(package_name, version))
367 if len(PACKAGES) == 0:
368 print "No current emerge process found."
374 if ((">>>" in line) and ("emerge" in line)):
376 if (p.name + '-' + p.version in line):
378 time = float(line.partition(' ')[0].strip(":"))
380 timestamp = datetime.datetime.fromtimestamp(time)
381 difference = (now - timestamp).total_seconds()
383 if difference < p.emerge_time:
384 p.emerge_time = difference
390 def main(status, user_package=None):
391 """Main function. Hanlde all the different modes of operation."""
393 if status == "package":
394 user_package = get_package(user_package)
396 pack = package(user_package)
398 search_log_for_package(pack)
400 if len(pack.versions) != 0:
401 pack.print_versions()
402 pack.print_min_max_ave()
405 print("Package " + green_start + pack.name +
406 color_stop + " has never been emerged.")
409 elif status == "current":
410 if list_emerge_processes():
413 print "Currently emerging:"
416 search_log_for_package(p)
417 p.print_current_emerge()
420 elif status == "pretended":
423 print "This is how long these packages would take to emerge"
425 total_pretended_time = 0
428 search_log_for_package(p)
430 total_pretended_time += p.print_pretended_times()
434 print("Total emerge time of " + green_start + str(len(PACKAGES)) +
435 color_stop + " package(s): "+ give_time(total_pretended_time))
439 usage = """Usage: emerge-timer.py [package] [options]
441 Calculate emerge times from emerge log.
444 \t-c, --current \t Show time until currently compiling package finishes
445 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
446 \t-h, --help \t Show this helpscreen
447 \t-q, --quiet \t Be less verbose
448 \t--no-color \t Use colorless output"""
455 if __name__ == "__main__":
457 # Set the default mode as "package"
462 for arg in sys.argv[1:]:
464 if arg == "-p" or arg == "--pretended":
467 if arg == "-c" or arg == "--current":
470 if arg == "-h" or arg == "--help":
473 if arg == "-q" or arg == "--quiet":
476 if arg == "--no-color":
481 if len(sys.argv) > 1:
482 input_package = sys.argv[1]
486 main(mode, input_package)