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
467 print "These emerge syncs found"
468 print "\tDate Server"
469 print "\t------------------------------"
472 if "=== Sync completed with" in line:
473 time = float(line.partition(' ')[0].strip(":"))
474 server = line.rpartition(' ')[2]
476 print("\t" + GREEN(give_date(time)) +
481 def main(status, user_package=None):
483 _main(status, user_package)
488 def _main(status, user_package=None):
489 """Main function. Hanlde all the different modes of operation."""
491 if status == "package":
492 for p in user_package:
493 pack = get_package(p)
497 search_log_for_package(pack)
499 if len(pack.versions) != 0:
500 pack.print_versions()
501 pack.print_min_max_ave()
504 print("Package " + GREEN(pack.name)
505 + " has never been emerged.")
508 elif status == "sync":
513 elif status == "list":
514 search_log_for_all_packages()
518 elif status == "current":
519 if list_emerge_processes():
522 print "Currently emerging:"
525 search_log_for_package(p)
526 p.print_current_emerge()
529 elif status == "pretended":
532 print "This is how long these packages would take to emerge"
534 total_pretended_time = 0
537 search_log_for_package(p)
539 total_pretended_time += p.print_pretended_times()
543 print("Total emerge time of " + GREEN(str(len(PACKAGES)))
544 + " package(s): "+ give_time(total_pretended_time))
548 usage = """Usage: emerge-timer.py [package] [options]
550 Calculate emerge times from emerge log.
553 \t-c, --current \t Show time until currently compiling package finishes
554 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
555 \t-l, --list \t List all emerged packages
556 \t-s, --sync \t Show emerge sync history
557 \t-h, --help \t Show this helpscreen
558 \t-q, --quiet \t Be less verbose
559 \t--no-color \t Use colorless output
560 \t--simulate \t Do a simulation run"""
567 if __name__ == "__main__":
569 # Set the default mode as "package"
571 input_packages = None
574 for arg in sys.argv[1:]:
576 if arg == "-p" or arg == "--pretended":
579 if arg == "-c" or arg == "--current":
582 if arg == "-h" or arg == "--help":
585 if arg == "-l" or arg == "--list":
588 if arg == "-s" or arg == "--sync":
591 if arg == "-q" or arg == "--quiet":
594 sys.argv.pop(sys.argv.index(arg))
596 if arg == "--no-color":
600 sys.argv.pop(sys.argv.index(arg))
602 if arg == "--simulate":
606 if len(sys.argv) > 1:
607 input_packages = sys.argv[1:]
611 if simulation == True:
613 print(RED("\n" + '*'*25 + "\n" + "THIS IS A SIMULATION RUN\n"
616 print(RED("Beginning 'package' mode check"))
618 print(RED("Checking for one emerge\n"))
620 LOGFILE = "simulate/fake_emerge.log"
621 PORTDIR = "simulate/"
623 main("package", "first_fake_package")
625 print(RED("\nChecking for three emerges\n"))
627 main("package", "second_fake_package")
629 print(RED("\n'package' mode check complete\n"))
633 print(RED("\nBeginning 'current' mode check"))
634 print(RED("Current emerge with no emerge process\n"))
636 main("current", None)
638 print(RED("\nCurrent emerge with emerge processes\n"))
640 PACKAGES.append(package("test-group/second_fake_package", "2.9-r2"))
641 PACKAGES[0].emerge_time = 60
642 PACKAGES.append(package("test-group/first_fake_package", "1.10.2-r1"))
643 PACKAGES[1].emerge_time = 120
645 main("current", None)
647 print(RED("\nCurrent emerge with incomplete emerge log " +
648 "(causes error in some cases)\n"))
651 PACKAGES.append(package("test-group/third_fake_package", "2.9-r2"))
653 main("current", None)
655 print(RED("\n" + '*'*20 + "\n" + "SIMULATION FINISHED\n" +
660 main(mode, input_packages)