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
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 difference = "infinity"
379 if (p.name + '-' + p.version in line):
381 time = float(line.partition(' ')[0].strip(":"))
383 timestamp = datetime.datetime.fromtimestamp(time)
384 new_difference = (now - timestamp).total_seconds()
386 if ((new_difference < difference) or
387 (difference == "infinity")):
388 difference = new_difference
390 p.emerge_time = difference
396 def main(status, user_package=None):
397 """Main function. Hanlde all the different modes of operation."""
399 if status == "package":
400 user_package = get_package(user_package)
402 pack = package(user_package)
404 search_log_for_package(pack)
406 if len(pack.versions) != 0:
407 pack.print_versions()
408 pack.print_min_max_ave()
411 print("Package " + green_start + pack.name +
412 color_stop + " has never been emerged.")
415 elif status == "current":
416 if list_emerge_processes():
419 print "Currently emerging:"
422 search_log_for_package(p)
423 p.print_current_emerge()
426 elif status == "pretended":
429 print "This is how long these packages would take to emerge"
431 total_pretended_time = 0
434 search_log_for_package(p)
436 total_pretended_time += p.print_pretended_times()
440 print("Total emerge time of " + green_start + str(len(PACKAGES)) +
441 color_stop + " package(s): "+ give_time(total_pretended_time))
445 usage = """Usage: emerge-timer.py [package] [options]
447 Calculate emerge times from emerge log.
450 \t-c, --current \t Show time until currently compiling package finishes
451 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
452 \t-h, --help \t Show this helpscreen
453 \t-q, --quiet \t Be less verbose
454 \t--no-color \t Use colorless output"""
461 if __name__ == "__main__":
463 # Set the default mode as "package"
468 for arg in sys.argv[1:]:
470 if arg == "-p" or arg == "--pretended":
473 if arg == "-c" or arg == "--current":
476 if arg == "-h" or arg == "--help":
479 if arg == "-q" or arg == "--quiet":
482 if arg == "--no-color":
487 if len(sys.argv) > 1:
488 input_package = sys.argv[1]
492 main(mode, input_package)