4 import sys, datetime, os
7 PORTDIR = "/usr/portage/"
8 LOGFILE = "/var/log/emerge.log"
11 green_start = "\033[32m"
12 red_start = "\033[1;31m"
22 def __init__(self, name, version=0):
24 self.version = version
26 self.emerge_time = "infinity"
29 def add_version(self, version, emerge_time, emerge_date):
30 """Add version to the class version list"""
31 self.versions.append((version, emerge_time, emerge_date))
34 def average_time(self):
35 """Return average time from class version list"""
37 for i in self.versions:
40 average_time = total_time/len(self.versions)
46 """Return total time from class version list"""
48 for i in self.versions:
55 """Return maximum time from class version list"""
58 return self.versions[len(self.versions)-1][1]
62 """Return minimum time from class version list"""
65 return self.versions[0][1]
68 def print_current_emerge(self):
69 """Function used to print all the current emerge stuff"""
71 print("\t" + green_start + self.name + '-' + self.version +
72 color_stop + "\n\t current time: " + give_time(self.emerge_time))
75 if len(self.versions) == 1:
76 print("\t last time: "),
77 print(give_time(self.average_time())),
79 elif len(self.versions) > 1:
80 print("\t average time:"),
81 print(give_time(self.average_time())),
84 print("\t average time: " + green_start + "unknown\n" + color_stop),
87 print("\n\t " + '-'*45),
89 print("\n\t time to finish:"),
91 if type(self.emerge_time) != str:
93 finish_time = self.average_time() - self.emerge_time
96 print(give_time(finish_time))
98 print(green_start + "any time now" + color_stop)
100 print(green_start + "unknown" + color_stop)
104 def print_versions(self):
105 """This prints the emerge times for different versions in the
106 'package' operating mode of the script"""
113 for p in self.versions:
114 if len(p[0]) > version_length:
115 version_length = len(p[0])
117 if len(give_time(p[1], True)) > time_length:
118 time_length = len(give_time(p[1], True))
120 for p in self.versions:
122 pad = time_length - len(give_time(p[1], True))
124 print('-'*90 + "\n" +
125 green_start + self.name + (p[0]).ljust(version_length) +
126 color_stop + " >>> " + (give_time(p[1])) + " "*pad +
127 " >>> " + give_date(p[2]))
129 print('-'*90 + "\n" + "Package " + green_start +
130 self.name + color_stop + " emerged " +
131 str(len(self.versions)) + " times.")
136 def print_pretended_times(self):
137 """This is used the print all the pretended times"""
140 print("\t" + green_start + self.name + '-' + self.version + color_stop),
142 if len(self.versions) > 1:
143 aver_time = self.average_time()
146 print("\n\taverage time: " + give_time(aver_time))
152 print("\n\t no previous emerges")
157 def print_min_max_ave(self):
158 maxi = self.max_time()
159 mini = self.min_time()
160 average = self.average_time()
161 total = self.total_time()
163 print("Max time:\t" + give_time(maxi) +
164 "\nMin time:\t" + give_time(mini) +
165 "\nAverage time:\t" + give_time(average) +
166 "\nIn total spent:\t" + give_time(total) +
167 "emerging " + green_start + self.name + color_stop)
171 def give_time(time, nocolor=False):
172 """Converts time in seconds to human readable form"""
173 global green_start, color_stop
175 if green_start == "":
182 if type(time) == str:
183 return(green_start + "unknown" + color_stop)
186 days = time/(3600.0*24.0)
187 hours = (days - int(days))*24.0
188 minutes = (hours - int(hours))*60.0
189 seconds = (minutes - int(minutes))*60.0
193 minutes = int(minutes)
194 seconds = int(round(seconds))
202 pdays = (green_start + str(days) +
203 color_stop + " day ")
205 pdays = (green_start + str(days) +
206 color_stop + " days ")
209 phours = (green_start + str(hours) +
210 color_stop + " hour ")
212 phours = (green_start + str(hours) +
213 color_stop + " hours ")
216 pminutes = (green_start + str(minutes) +
217 color_stop + " minute ")
219 pminutes = (green_start + str(minutes) +
220 color_stop + " minutes ")
222 pseconds = (green_start + str(seconds) +
223 color_stop + " second ")
225 pseconds = (green_start + str(seconds) +
226 color_stop + " seconds ")
229 green_start = "\033[32m"
230 color_stop = "\033[m"
232 return (pdays + phours + pminutes + pseconds)
236 def give_date(emerge_date):
237 """Returns a date string from a standard POSIX time"""
238 date = datetime.datetime.fromtimestamp(emerge_date)
240 date = "{:%d.%m.%Y %H:%M:%S}".format(date)
247 """Attempt to open the LOGFILE."""
250 f = open(LOGFILE, 'r')
251 except IOError as detail:
259 def search_log_for_package(package_class):
260 """Searchs emerge log for given package and adds all found
261 versions with their emerge times to the class"""
266 if ((">>>" in line) and ("emerge" in line)):
267 if package_class.name in line:
269 version = line.partition(package_class.name)[2].partition(' ')[0]
270 digit = version.strip('-')[0].isdigit()
273 time_string = line.partition(">>>")
274 start_time = float(time_string[0].strip().strip(':'))
276 elif ((":::" in line) and ("completed emerge" in line)):
278 if package_class.name in line:
280 time_string = line.partition(":::")
281 stop_time = float(time_string[0].strip().strip(':'))
283 emerge_time = stop_time - start_time
285 package_class.add_version(version, emerge_time, start_time)
289 def get_package(name):
290 """Take the user-input package name and search for it
293 dirlist = os.listdir(PORTDIR)
294 possible_package = []
297 # If the given name is in the format xxx/zzz
298 # assume that xxx is the package group
300 group = name.partition('/')[0]
301 pkg = name.partition('/')[2]
302 directory = PORTDIR + group
305 dirs = os.listdir(directory)
307 possible_package.append(name)
310 # Go through the directory listing searching for anything
311 # that matches the given name
313 directory = PORTDIR + i
314 if os.path.isdir(directory):
315 dirs = os.listdir(directory)
317 possible_package.append(i + '/' + name)
320 if len(possible_package) > 1:
321 print("Multiple packages found for '" + name + "'.")
322 print("Possible packages: ")
323 for value in possible_package:
327 elif len(possible_package) == 1:
328 package = possible_package[0]
333 print("No package '" + name + "' found")
340 def list_pretended():
341 """List all the pretended packages given by emerge -p
342 output. Create a class out of each of those packages and add them
347 for line in sys.stdin:
348 if "[ebuild" in line:
349 full_name = line.partition("] ")[2].partition(' ')[0]
351 version = full_name.partition('/')[2].partition('-')[2]
352 while not version[0].isdigit():
353 version = version.partition('-')[2]
354 package_name = full_name[:-len(version)-1]
356 PACKAGES.append(package(package_name, version))
360 def list_emerge_processes():
361 """Look for the ebuild process with ps. If the process is found parse
362 the command for the package. With this package search the LOGFILE for
363 the emerge startup time."""
367 now = datetime.datetime.today()
369 for i in os.popen("ps ax"):
370 if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
371 pack = i.partition('[')[2].partition(']')[0]
373 version = pack.partition('/')[2].partition('-')[2]
375 while not version[0].isdigit():
376 version = version.partition('-')[2]
378 package_name = pack[:-len(version)-1]
380 PACKAGES.append(package(package_name, version))
383 if len(PACKAGES) == 0:
384 print "No current emerge process found."
390 if ((">>>" in line) and ("emerge" in line)):
394 if (p.name + '-' + p.version in line):
396 time = float(line.partition(' ')[0].strip(":"))
398 timestamp = datetime.datetime.fromtimestamp(time)
399 difference = (now - timestamp).total_seconds()
401 if ((difference < p.emerge_time) or
402 (p.emerge_time == "infinity")):
404 p.emerge_time = difference
410 def main(status, user_package=None):
411 """Main function. Hanlde all the different modes of operation."""
413 if status == "package":
414 user_package = get_package(user_package)
416 pack = package(user_package)
418 search_log_for_package(pack)
420 if len(pack.versions) != 0:
421 pack.print_versions()
422 pack.print_min_max_ave()
425 print("Package " + green_start + pack.name +
426 color_stop + " has never been emerged.")
429 elif status == "current":
430 if list_emerge_processes():
433 print "Currently emerging:"
436 search_log_for_package(p)
437 p.print_current_emerge()
440 elif status == "pretended":
443 print "This is how long these packages would take to emerge"
445 total_pretended_time = 0
448 search_log_for_package(p)
450 total_pretended_time += p.print_pretended_times()
454 print("Total emerge time of " + green_start + str(len(PACKAGES)) +
455 color_stop + " package(s): "+ give_time(total_pretended_time))
459 usage = """Usage: emerge-timer.py [package] [options]
461 Calculate emerge times from emerge log.
464 \t-c, --current \t Show time until currently compiling package finishes
465 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
466 \t-h, --help \t Show this helpscreen
467 \t-q, --quiet \t Be less verbose
468 \t--no-color \t Use colorless output
469 \t--simulate \t Do a simulation run"""
476 if __name__ == "__main__":
478 # Set the default mode as "package"
483 for arg in sys.argv[1:]:
485 if arg == "-p" or arg == "--pretended":
488 if arg == "-c" or arg == "--current":
491 if arg == "-h" or arg == "--help":
494 if arg == "-q" or arg == "--quiet":
497 if arg == "--no-color":
501 if arg == "--simulate":
505 if len(sys.argv) > 1:
506 input_package = sys.argv[1]
510 if simulation == True:
512 print(red_start + "\n" + '*'*25 + "\n" + "THIS IS A SIMULATION RUN\n"
515 print("Beginning 'package' mode check")
517 print("Checking for one emerge\n" + color_stop)
519 LOGFILE = "simulate/fake_emerge.log"
520 PORTDIR = "simulate/"
522 main("package", "first_fake_package")
524 print(red_start + "\nChecking for three emerges\n" + color_stop)
526 main("package", "second_fake_package")
528 print(red_start + "\n'package' mode check complete\n")
532 print("\nBeginning 'current' mode check")
533 print("Current emerge with no emerge process\n" + color_stop)
535 main("current", None)
537 print(red_start + "\nCurrent emerge with emerge processes\n" + color_stop)
539 PACKAGES.append(package("test-group/second_fake_package", "2.9-r2"))
540 PACKAGES[0].emerge_time = 60
541 PACKAGES.append(package("test-group/first_fake_package", "1.10.2-r1"))
542 PACKAGES[1].emerge_time = 120
544 main("current", None)
546 print(red_start + "\nCurrent emerge with incomplete emerge log" +
547 "(causes error in some cases)\n" + color_stop)
550 PACKAGES.append(package("test-group/third_fake_package", "2.9-r2"))
552 main("current", None)
554 print(red_start + "\n" + '*'*20 + "\n" + "SIMULATION FINISHED\n" +
559 main(mode, input_package)