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"
20 return green_start + string + color_stop
23 return red_start + string + color_stop
27 def __init__(self, name, version=0):
29 self.version = version
31 self.emerge_time = "infinity"
34 def add_version(self, version, emerge_time, emerge_date):
35 """Add version to the class version list"""
36 self.versions.append((version, emerge_time, emerge_date))
39 def average_time(self):
40 """Return average time from class version list"""
42 for i in self.versions:
45 average_time = total_time/len(self.versions)
51 """Return total time from class version list"""
53 for i in self.versions:
60 """Return maximum time from class version list"""
63 for i in self.versions:
64 emerge_times.append(i[1])
68 return emerge_times[-1]
72 """Return minimum time from class version list"""
75 for i in self.versions:
76 emerge_times.append(i[1])
80 return emerge_times[0]
84 def print_current_emerge(self):
85 """Function used to print all the current emerge stuff"""
87 print("\t" + GREEN(self.name + '-' + self.version) +
88 "\n\t current time: " + give_time(self.emerge_time))
91 if len(self.versions) == 1:
92 print("\t last time: "),
93 print(give_time(self.average_time())),
95 elif len(self.versions) > 1:
96 print("\t average time:"),
97 print(give_time(self.average_time())),
100 print("\t average time: " + GREEN("unknown\n")),
103 print("\n\t " + '-'*45),
105 print("\n\t time to finish:"),
107 if type(self.emerge_time) != str:
109 finish_time = self.average_time() - self.emerge_time
112 print(give_time(finish_time))
114 print(GREEN("any time now"))
116 print(GREEN("unknown"))
120 def print_versions(self):
121 """This prints the emerge times for different versions in the
122 'package' operating mode of the script"""
129 for p in self.versions:
130 if len(p[0]) > version_length:
131 version_length = len(p[0])
133 if len(give_time(p[1], True)) > time_length:
134 time_length = len(give_time(p[1], True))
136 dots = (version_length + time_length + len(self.name)
137 + len(give_date(self.versions[0][2])) + 14)
139 for p in self.versions:
141 pad = time_length - len(give_time(p[1], True))
144 p_time = give_time(p[1])
145 p_date = give_date(p[2])
147 print('-' * dots + "\n" +
148 GREEN(name + (p[0]).ljust(version_length))
149 + " >>> " + p_time + " "*pad + " >>> " + p_date)
151 print("\n" + "Package " + GREEN(self.name) + " emerged"),
153 if len(self.versions) > 1:
154 print(str(len(self.versions)) + " times.\n")
155 elif len(self.versions) == 1:
160 def print_pretended_times(self):
161 """This is used the print all the pretended times"""
164 print("\t" + GREEN(self.name + '-' + self.version)),
166 if len(self.versions) > 1:
167 aver_time = self.average_time()
170 print("\n\taverage time: " + give_time(aver_time))
176 print("\n\t no previous emerges")
181 def print_min_max_ave(self):
183 if len(self.versions) == 1:
186 maxi = self.max_time()
187 mini = self.min_time()
188 average = self.average_time()
189 total = self.total_time()
191 print("Max time:\t" + give_time(maxi) +
192 "\nMin time:\t" + give_time(mini) +
193 "\nAverage time:\t" + give_time(average) +
194 "\nIn total spent:\t" + give_time(total) +
195 "emerging " + GREEN(self.name))
199 def give_time(time, nocolor=False):
200 """Converts time in seconds to human readable form"""
201 global green_start, color_stop
203 if green_start == "":
210 if type(time) == str:
211 return(GREEN("unknown"))
214 days = time/(3600.0*24.0)
215 hours = (days - int(days))*24.0
216 minutes = (hours - int(hours))*60.0
217 seconds = (minutes - int(minutes))*60.0
221 minutes = int(minutes)
222 seconds = int(round(seconds))
230 pdays = (GREEN(str(days)) + " day ")
232 pdays = (GREEN(str(days)) + " days ")
235 phours = (GREEN(str(hours)) + " hour ")
237 phours = (GREEN(str(hours)) + " hours ")
240 pminutes = (GREEN(str(minutes)) + " minute ")
242 pminutes = (GREEN(str(minutes)) + " minutes ")
245 pseconds = (GREEN(str(seconds)) + " second ")
247 pseconds = (GREEN(str(seconds)) + " seconds ")
250 green_start = "\033[32m"
251 color_stop = "\033[m"
253 return (pdays + phours + pminutes + pseconds)
257 def give_date(emerge_date):
258 """Returns a date string from a standard POSIX time"""
259 date = datetime.datetime.fromtimestamp(emerge_date)
261 date = "{:%d.%m.%Y %H:%M:%S}".format(date)
268 """Attempt to open the LOGFILE."""
271 f = open(LOGFILE, 'r')
272 except IOError as detail:
280 def search_log_for_package(package_class):
281 """Searchs emerge log for given package and adds all found
282 versions with their emerge times to the class"""
287 if ((">>>" in line) and ("emerge" in line)):
288 if package_class.name in line:
290 version = line.partition(package_class.name)[2].partition(' ')[0]
291 digit = version.strip('-')[0].isdigit()
294 time_string = line.partition(">>>")
295 start_time = float(time_string[0].strip().strip(':'))
297 elif ((":::" in line) and ("completed emerge" in line)):
299 if package_class.name in line:
301 time_string = line.partition(":::")
302 stop_time = float(time_string[0].strip().strip(':'))
304 emerge_time = stop_time - start_time
306 package_class.add_version(version, emerge_time, start_time)
310 def search_log_for_all_packages():
311 """Goes through the emerge.log and lists all packages in there"""
317 total_emerge_time = 0
321 if ((">>>" in line) and ("emerge" in line)):
322 pack = line.partition(')')[2].strip().partition(' ')[0]
323 start_time = float(line.partition(':')[0])
325 all_packages.append((pack, start_time))
327 elif ((":::" in line) and ("completed emerge" in line)):
328 for p in all_packages:
330 stop_time = float(line.partition(':')[0])
332 print("\t" + give_date(p[1]) + " >>> " + GREEN(p[0]))
334 total_emerge_time += stop_time - p[1]
337 all_packages.pop(all_packages.index(p))
339 print("\nTotal emerge time of " + GREEN(str(emerge_number)) +
340 " merges: " + give_time(total_emerge_time))
344 def get_package(name):
345 """Take the user-input package name and search for it
348 dirlist = os.listdir(PORTDIR)
349 possible_package = []
352 # If the given name is in the format xxx/zzz
353 # assume that xxx is the package group
355 group = name.partition('/')[0]
356 pkg = name.partition('/')[2]
357 directory = PORTDIR + group
360 dirs = os.listdir(directory)
362 possible_package.append(name)
365 # Go through the directory listing searching for anything
366 # that matches the given name
368 directory = PORTDIR + i
369 if os.path.isdir(directory):
370 dirs = os.listdir(directory)
372 possible_package.append(i + '/' + name)
375 if len(possible_package) > 1:
376 print("Multiple packages found for '" + name + "'.")
377 print("Possible packages: ")
378 for value in possible_package:
382 elif len(possible_package) == 1:
383 package = possible_package[0]
388 print("No package '" + name + "' found")
395 def list_pretended():
396 """List all the pretended packages given by emerge -p
397 output. Create a class out of each of those packages and add them
402 for line in sys.stdin:
403 if "[ebuild" in line:
404 full_name = line.partition("] ")[2].partition(' ')[0]
406 version = full_name.partition('/')[2].partition('-')[2]
407 while not version[0].isdigit():
408 version = version.partition('-')[2]
409 package_name = full_name[:-len(version)-1]
411 PACKAGES.append(package(package_name, version))
415 def list_emerge_processes():
416 """Look for the ebuild process with ps. If the process is found parse
417 the command for the package. With this package search the LOGFILE for
418 the emerge startup time."""
422 now = datetime.datetime.today()
424 for i in os.popen("ps ax"):
425 if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
426 pack = i.partition('[')[2].partition(']')[0]
428 version = pack.partition('/')[2].partition('-')[2]
430 while not version[0].isdigit():
431 version = version.partition('-')[2]
433 package_name = pack[:-len(version)-1]
435 PACKAGES.append(package(package_name, version))
438 if len(PACKAGES) == 0:
439 print "No current emerge process found."
445 if ((">>>" in line) and ("emerge" in line)):
449 if (p.name + '-' + p.version in line):
451 time = float(line.partition(' ')[0].strip(":"))
453 timestamp = datetime.datetime.fromtimestamp(time)
454 difference = (now - timestamp).total_seconds()
456 if ((difference < p.emerge_time) or
457 (p.emerge_time == "infinity")):
459 p.emerge_time = difference
464 def main(status, user_package=None):
466 _main(status, user_package)
471 def _main(status, user_package=None):
472 """Main function. Hanlde all the different modes of operation."""
474 if status == "package":
475 for p in user_package:
476 pack = get_package(p)
480 search_log_for_package(pack)
482 if len(pack.versions) != 0:
483 pack.print_versions()
484 pack.print_min_max_ave()
487 print("Package " + GREEN(pack.name)
488 + " has never been emerged.")
491 elif status == "list":
492 search_log_for_all_packages()
496 elif status == "current":
497 if list_emerge_processes():
500 print "Currently emerging:"
503 search_log_for_package(p)
504 p.print_current_emerge()
507 elif status == "pretended":
510 print "This is how long these packages would take to emerge"
512 total_pretended_time = 0
515 search_log_for_package(p)
517 total_pretended_time += p.print_pretended_times()
521 print("Total emerge time of " + GREEN(str(len(PACKAGES)))
522 + " package(s): "+ give_time(total_pretended_time))
526 usage = """Usage: emerge-timer.py [package] [options]
528 Calculate emerge times from emerge log.
531 \t-c, --current \t Show time until currently compiling package finishes
532 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
533 \t-l, --list \t List all emerged packages
534 \t-h, --help \t Show this helpscreen
535 \t-q, --quiet \t Be less verbose
536 \t--no-color \t Use colorless output
537 \t--simulate \t Do a simulation run"""
544 if __name__ == "__main__":
546 # Set the default mode as "package"
548 input_packages = None
551 for arg in sys.argv[1:]:
553 if arg == "-p" or arg == "--pretended":
556 if arg == "-c" or arg == "--current":
559 if arg == "-h" or arg == "--help":
562 if arg == "-l" or arg == "--list":
565 if arg == "-q" or arg == "--quiet":
568 sys.argv.pop(sys.argv.index(arg))
570 if arg == "--no-color":
574 sys.argv.pop(sys.argv.index(arg))
576 if arg == "--simulate":
580 if len(sys.argv) > 1:
581 input_packages = sys.argv[1:]
585 if simulation == True:
587 print(RED("\n" + '*'*25 + "\n" + "THIS IS A SIMULATION RUN\n"
590 print(RED("Beginning 'package' mode check"))
592 print(RED("Checking for one emerge\n"))
594 LOGFILE = "simulate/fake_emerge.log"
595 PORTDIR = "simulate/"
597 main("package", "first_fake_package")
599 print(RED("\nChecking for three emerges\n"))
601 main("package", "second_fake_package")
603 print(RED("\n'package' mode check complete\n"))
607 print(RED("\nBeginning 'current' mode check"))
608 print(RED("Current emerge with no emerge process\n"))
610 main("current", None)
612 print(RED("\nCurrent emerge with emerge processes\n"))
614 PACKAGES.append(package("test-group/second_fake_package", "2.9-r2"))
615 PACKAGES[0].emerge_time = 60
616 PACKAGES.append(package("test-group/first_fake_package", "1.10.2-r1"))
617 PACKAGES[1].emerge_time = 120
619 main("current", None)
621 print(RED("\nCurrent emerge with incomplete emerge log " +
622 "(causes error in some cases)\n"))
625 PACKAGES.append(package("test-group/third_fake_package", "2.9-r2"))
627 main("current", None)
629 print(RED("\n" + '*'*20 + "\n" + "SIMULATION FINISHED\n" +
634 main(mode, input_packages)