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 print("\t" + give_date(p[1]) + " >>> " + GREEN(p[0]))
334 all_packages.pop(all_packages.index(p))
336 print("\n" + GREEN(str(emerge_number)) + " packages in total.")
340 def get_package(name):
341 """Take the user-input package name and search for it
344 dirlist = os.listdir(PORTDIR)
345 possible_package = []
348 # If the given name is in the format xxx/zzz
349 # assume that xxx is the package group
351 group = name.partition('/')[0]
352 pkg = name.partition('/')[2]
353 directory = PORTDIR + group
356 dirs = os.listdir(directory)
358 possible_package.append(name)
361 # Go through the directory listing searching for anything
362 # that matches the given name
364 directory = PORTDIR + i
365 if os.path.isdir(directory):
366 dirs = os.listdir(directory)
368 possible_package.append(i + '/' + name)
371 if len(possible_package) > 1:
372 print("Multiple packages found for '" + name + "'.")
373 print("Possible packages: ")
374 for value in possible_package:
378 elif len(possible_package) == 1:
379 package = possible_package[0]
384 print("No package '" + name + "' found")
391 def list_pretended():
392 """List all the pretended packages given by emerge -p
393 output. Create a class out of each of those packages and add them
398 for line in sys.stdin:
399 if "[ebuild" in line:
400 full_name = line.partition("] ")[2].partition(' ')[0]
402 version = full_name.partition('/')[2].partition('-')[2]
403 while not version[0].isdigit():
404 version = version.partition('-')[2]
405 package_name = full_name[:-len(version)-1]
407 PACKAGES.append(package(package_name, version))
411 def list_emerge_processes():
412 """Look for the ebuild process with ps. If the process is found parse
413 the command for the package. With this package search the LOGFILE for
414 the emerge startup time."""
418 now = datetime.datetime.today()
420 for i in os.popen("ps ax"):
421 if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
422 pack = i.partition('[')[2].partition(']')[0]
424 version = pack.partition('/')[2].partition('-')[2]
426 while not version[0].isdigit():
427 version = version.partition('-')[2]
429 package_name = pack[:-len(version)-1]
431 PACKAGES.append(package(package_name, version))
434 if len(PACKAGES) == 0:
435 print "No current emerge process found."
441 if ((">>>" in line) and ("emerge" in line)):
445 if (p.name + '-' + p.version in line):
447 time = float(line.partition(' ')[0].strip(":"))
449 timestamp = datetime.datetime.fromtimestamp(time)
450 difference = (now - timestamp).total_seconds()
452 if ((difference < p.emerge_time) or
453 (p.emerge_time == "infinity")):
455 p.emerge_time = difference
463 print "These emerge syncs found"
464 print "\tDate Server"
465 print "\t------------------------------"
468 if "=== Sync completed with" in line:
469 time = float(line.partition(' ')[0].strip(":"))
470 server = line.rpartition(' ')[2]
472 print("\t" + GREEN(give_date(time)) +
477 def main(status, user_package=None):
479 _main(status, user_package)
484 def _main(status, user_package=None):
485 """Main function. Hanlde all the different modes of operation."""
487 if status == "package":
488 for p in user_package:
489 pack = get_package(p)
493 search_log_for_package(pack)
495 if len(pack.versions) != 0:
496 pack.print_versions()
497 pack.print_min_max_ave()
500 print("Package " + GREEN(pack.name)
501 + " has never been emerged.")
504 elif status == "sync":
509 elif status == "list":
510 search_log_for_all_packages()
514 elif status == "current":
515 if list_emerge_processes():
518 print "Currently emerging:"
521 search_log_for_package(p)
522 p.print_current_emerge()
525 elif status == "pretended":
528 print "This is how long these packages would take to emerge"
530 total_pretended_time = 0
533 search_log_for_package(p)
535 total_pretended_time += p.print_pretended_times()
539 print("Total emerge time of " + GREEN(str(len(PACKAGES)))
540 + " package(s): "+ give_time(total_pretended_time))
544 usage = """Usage: emerge-timer.py [package] [options]
546 Calculate emerge times from emerge log.
549 \t-c, --current \t Show time until currently compiling package finishes
550 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
551 \t-l, --list \t List all emerged packages
552 \t-s, --sync \t Show emerge sync history
553 \t-h, --help \t Show this helpscreen
554 \t-q, --quiet \t Be less verbose
555 \t--no-color \t Use colorless output
556 \t--simulate \t Do a simulation run"""
563 if __name__ == "__main__":
565 # Set the default mode as "package"
567 input_packages = None
570 for arg in sys.argv[1:]:
572 if arg == "-p" or arg == "--pretended":
575 if arg == "-c" or arg == "--current":
578 if arg == "-h" or arg == "--help":
581 if arg == "-l" or arg == "--list":
584 if arg == "-s" or arg == "--sync":
587 if arg == "-q" or arg == "--quiet":
590 sys.argv.pop(sys.argv.index(arg))
592 if arg == "--no-color":
596 sys.argv.pop(sys.argv.index(arg))
598 if arg == "--simulate":
602 if len(sys.argv) > 1:
603 input_packages = sys.argv[1:]
607 if simulation == True:
609 print(RED("\n" + '*'*25 + "\n" + "THIS IS A SIMULATION RUN\n"
612 print(RED("Beginning 'package' mode check"))
614 print(RED("Checking for one emerge\n"))
616 LOGFILE = "simulate/fake_emerge.log"
617 PORTDIR = "simulate/"
619 main("package", "first_fake_package")
621 print(RED("\nChecking for three emerges\n"))
623 main("package", "second_fake_package")
625 print(RED("\n'package' mode check complete\n"))
629 print(RED("\nBeginning 'current' mode check"))
630 print(RED("Current emerge with no emerge process\n"))
632 main("current", None)
634 print(RED("\nCurrent emerge with emerge processes\n"))
636 PACKAGES.append(package("test-group/second_fake_package", "2.9-r2"))
637 PACKAGES[0].emerge_time = 60
638 PACKAGES.append(package("test-group/first_fake_package", "1.10.2-r1"))
639 PACKAGES[1].emerge_time = 120
641 main("current", None)
643 print(RED("\nCurrent emerge with incomplete emerge log " +
644 "(causes error in some cases)\n"))
647 PACKAGES.append(package("test-group/third_fake_package", "2.9-r2"))
649 main("current", None)
651 print(RED("\n" + '*'*20 + "\n" + "SIMULATION FINISHED\n" +
656 main(mode, input_packages)