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"
36 def add_version(self, version, emerge_time, emerge_date):
37 """Add version to the class version list"""
38 self.versions.append((version, emerge_time, emerge_date))
41 def average_time(self):
42 """Return average time from class version list"""
44 for i in self.versions:
47 average_time = total_time/len(self.versions)
53 """Return total time from class version list"""
55 for i in self.versions:
62 """Return maximum time from class version list"""
65 for i in self.versions:
66 emerge_times.append(i[1])
70 return emerge_times[-1]
74 """Return minimum time from class version list"""
77 for i in self.versions:
78 emerge_times.append(i[1])
82 return emerge_times[0]
86 def print_current_emerge(self):
87 """Function used to print all the current emerge stuff"""
89 print("\t" + GREEN(self.name + '-' + self.version) +
90 "\n\t current time: " + give_time(self.emerge_time))
93 if len(self.versions) == 1:
94 print("\t last time: "),
95 print(give_time(self.average_time())),
97 elif len(self.versions) > 1:
98 print("\t average time:"),
99 print(give_time(self.average_time())),
102 print("\t average time: " + GREEN("unknown\n")),
105 print("\n\t " + '-'*45),
107 print("\n\t time to finish:"),
109 if type(self.emerge_time) != str:
111 finish_time = self.average_time() - self.emerge_time
114 print(give_time(finish_time))
116 print(GREEN("any time now"))
118 print(GREEN("unknown"))
122 def print_versions(self):
123 """This prints the emerge times for different versions in the
124 'package' operating mode of the script"""
131 for p in self.versions:
132 if len(p[0]) > version_length:
133 version_length = len(p[0])
135 if len(give_time(p[1], True)) > time_length:
136 time_length = len(give_time(p[1], True))
138 # Create the data for plotting in the format (emerge time, emerge date)
139 self.plotData.append((p[1], p[2]))
141 dots = (version_length + time_length + len(self.name)
142 + len(give_date(self.versions[0][2])) + 14)
144 for p in self.versions:
146 pad = time_length - len(give_time(p[1], True))
149 p_time = give_time(p[1])
150 p_date = give_date(p[2])
152 print('-' * dots + "\n" +
153 GREEN(name + (p[0]).ljust(version_length))
154 + " >>> " + p_time + " "*pad + " >>> " + p_date)
156 print("\n" + "Package " + GREEN(self.name) + " emerged"),
158 if len(self.versions) > 1:
159 print(str(len(self.versions)) + " times.\n")
160 elif len(self.versions) == 1:
165 def print_pretended_times(self):
166 """This is used the print all the pretended times"""
169 print("\t" + GREEN(self.name + '-' + self.version)),
171 if len(self.versions) > 1:
172 aver_time = self.average_time()
175 print("\n\taverage time: " + give_time(aver_time))
181 print("\n\t no previous emerges")
186 def print_min_max_ave(self):
188 if len(self.versions) == 1:
191 maxi = self.max_time()
192 mini = self.min_time()
193 average = self.average_time()
194 total = self.total_time()
196 print("Max time:\t" + give_time(maxi) +
197 "\nMin time:\t" + give_time(mini) +
198 "\nAverage time:\t" + give_time(average) +
199 "\nIn total spent:\t" + give_time(total) +
200 "emerging " + GREEN(self.name))
202 def plotToScreen(self):
206 for i in self.plotData:
207 dates.append(datetime.date.fromtimestamp(i[1]))
212 plt.plot_date(dates, times, xdate=True, ydate=False)
214 plt.ylabel("Emerge time [s]")
215 plt.suptitle(self.name)
221 def give_time(time, nocolor=False):
222 """Converts time in seconds to human readable form"""
223 global green_start, color_stop
225 if green_start == "":
232 if type(time) == str:
233 return(GREEN("unknown"))
236 days = time/(3600.0*24.0)
237 hours = (days - int(days))*24.0
238 minutes = (hours - int(hours))*60.0
239 seconds = (minutes - int(minutes))*60.0
243 minutes = int(minutes)
244 seconds = int(round(seconds))
252 pdays = (GREEN(str(days)) + " day ")
254 pdays = (GREEN(str(days)) + " days ")
257 phours = (GREEN(str(hours)) + " hour ")
259 phours = (GREEN(str(hours)) + " hours ")
262 pminutes = (GREEN(str(minutes)) + " minute ")
264 pminutes = (GREEN(str(minutes)) + " minutes ")
267 pseconds = (GREEN(str(seconds)) + " second ")
269 pseconds = (GREEN(str(seconds)) + " seconds ")
272 green_start = "\033[32m"
273 color_stop = "\033[m"
275 return (pdays + phours + pminutes + pseconds)
279 def give_date(emerge_date):
280 """Returns a date string from a standard POSIX time"""
281 date = datetime.datetime.fromtimestamp(emerge_date)
283 date = "{:%d.%m.%Y %H:%M:%S}".format(date)
290 """Attempt to open the LOGFILE."""
293 f = open(LOGFILE, 'r')
294 except IOError as detail:
302 def search_log_for_package(package_class):
303 """Searchs emerge log for given package and adds all found
304 versions with their emerge times to the class"""
309 if ((">>>" in line) and ("emerge" in line)):
310 if package_class.name in line:
312 version = line.partition(package_class.name)[2].partition(' ')[0]
313 digit = version.strip('-')[0].isdigit()
316 time_string = line.partition(">>>")
317 start_time = float(time_string[0].strip().strip(':'))
319 elif ((":::" in line) and ("completed emerge" in line)):
321 if package_class.name in line:
323 time_string = line.partition(":::")
324 stop_time = float(time_string[0].strip().strip(':'))
326 emerge_time = stop_time - start_time
328 package_class.add_version(version, emerge_time, start_time)
332 def search_log_for_all_packages():
333 """Goes through the emerge.log and lists all packages in there"""
339 total_emerge_time = 0
343 if ((">>>" in line) and ("emerge" in line)):
344 pack = line.partition(')')[2].strip().partition(' ')[0]
345 start_time = float(line.partition(':')[0])
347 all_packages.append((pack, start_time))
349 elif ((":::" in line) and ("completed emerge" in line)):
350 for p in all_packages:
352 stop_time = float(line.partition(':')[0])
354 print("\t" + give_date(p[1]) + " >>> " + GREEN(p[0]))
356 total_emerge_time += stop_time - p[1]
359 all_packages.pop(all_packages.index(p))
361 print("\n" + GREEN(str(emerge_number)) + " emerges in total found.")
365 def get_package(name):
366 """Take the user-input package name and search for it
369 dirlist = os.listdir(PORTDIR)
370 possible_package = []
373 # If the given name is in the format xxx/zzz
374 # assume that xxx is the package group
376 group = name.partition('/')[0]
377 pkg = name.partition('/')[2]
378 directory = PORTDIR + group
381 dirs = os.listdir(directory)
383 possible_package.append(name)
386 # Go through the directory listing searching for anything
387 # that matches the given name
389 directory = PORTDIR + i
390 if os.path.isdir(directory):
391 dirs = os.listdir(directory)
393 possible_package.append(i + '/' + name)
396 if len(possible_package) > 1:
397 print("Multiple packages found for '" + name + "'.")
398 print("Possible packages: ")
399 for value in possible_package:
403 elif len(possible_package) == 1:
404 package = possible_package[0]
409 print("No package '" + name + "' found")
416 def list_pretended():
417 """List all the pretended packages given by emerge -p
418 output. Create a class out of each of those packages and add them
423 for line in sys.stdin:
424 if "[ebuild" in line:
425 full_name = line.partition("] ")[2].partition(' ')[0]
427 version = full_name.partition('/')[2].partition('-')[2]
428 while not version[0].isdigit():
429 version = version.partition('-')[2]
430 package_name = full_name[:-len(version)-1]
432 PACKAGES.append(package(package_name, version))
436 def list_emerge_processes():
437 """Look for the ebuild process with ps. If the process is found parse
438 the command for the package. With this package search the LOGFILE for
439 the emerge startup time."""
443 now = datetime.datetime.today()
445 for i in os.popen("ps ax"):
446 if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
447 pack = i.partition('[')[2].partition(']')[0]
449 version = pack.partition('/')[2].partition('-')[2]
451 while not version[0].isdigit():
452 version = version.partition('-')[2]
454 package_name = pack[:-len(version)-1]
456 PACKAGES.append(package(package_name, version))
459 if len(PACKAGES) == 0:
460 print "No current emerge process found."
466 if ((">>>" in line) and ("emerge" in line)):
470 if (p.name + '-' + p.version in line):
472 time = float(line.partition(' ')[0].strip(":"))
474 timestamp = datetime.datetime.fromtimestamp(time)
475 difference = (now - timestamp).total_seconds()
477 if ((difference < p.emerge_time) or
478 (p.emerge_time == "infinity")):
480 p.emerge_time = difference
488 print "These emerge syncs found"
489 print "\tDate Server"
490 print "\t------------------------------"
493 if "=== Sync completed with" in line:
494 time = float(line.partition(' ')[0].strip(":"))
495 server = line.rpartition(' ')[2]
497 print("\t" + GREEN(give_date(time)) +
502 def main(status, user_package=None):
504 _main(status, user_package)
509 def _main(status, user_package=None):
510 """Main function. Hanlde all the different modes of operation."""
512 if status == "package":
513 for p in user_package:
514 pack = get_package(p)
518 search_log_for_package(pack)
520 if len(pack.versions) != 0:
521 pack.print_versions()
522 pack.print_min_max_ave()
528 print("Package " + GREEN(pack.name)
529 + " has never been emerged.")
532 elif status == "sync":
537 elif status == "list":
538 search_log_for_all_packages()
542 elif status == "current":
543 if list_emerge_processes():
546 print "Currently emerging:"
549 search_log_for_package(p)
550 p.print_current_emerge()
553 elif status == "pretended":
556 print "This is how long these packages would take to emerge"
558 total_pretended_time = 0
561 search_log_for_package(p)
563 total_pretended_time += p.print_pretended_times()
567 print("Total emerge time of " + GREEN(str(len(PACKAGES)))
568 + " package(s): "+ give_time(total_pretended_time))
572 usage = """Usage: emerge-timer.py [package] [options]
574 Calculate emerge times from emerge log.
577 \t-c, --current \t Show time until currently compiling package finishes
578 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
579 \t-l, --list \t List all emerged packages
580 \t-s, --sync \t Show emerge sync history
581 \t-h, --help \t Show this helpscreen
582 \t-q, --quiet \t Be less verbose
583 \t--no-color \t Use colorless output
584 \t--plot \t\t Plot emerge times into a 2D scatter plot
585 \t\t\t (needs matlibplot installed for this to work)
586 \t--simulate \t Do a simulation run"""
593 if __name__ == "__main__":
595 # Set the default mode as "package"
597 input_packages = None
599 matplotWorking = False
601 for arg in sys.argv[1:]:
603 if arg == "-p" or arg == "--pretended":
606 if arg == "-c" or arg == "--current":
609 if arg == "-h" or arg == "--help":
612 if arg == "-l" or arg == "--list":
615 if arg == "-s" or arg == "--sync":
618 if arg == "-q" or arg == "--quiet":
621 sys.argv.pop(sys.argv.index(arg))
625 import matplotlib.pyplot as plt
626 matplotWorking = True
628 print(RED("Cannot initialize matplotlib!"))
629 print(RED("Check that you have properly installed matplotlib.\n"))
630 matplotWorking = False
632 sys.argv.pop(sys.argv.index(arg))
634 if arg == "--no-color":
638 sys.argv.pop(sys.argv.index(arg))
640 if arg == "--simulate":
644 if len(sys.argv) > 1:
645 input_packages = sys.argv[1:]
649 if simulation == True:
651 print(RED("\n" + '*'*25 + "\n" + "THIS IS A SIMULATION RUN\n"
654 print(RED("Beginning 'package' mode check"))
656 print(RED("Checking for one emerge\n"))
658 LOGFILE = "simulate/fake_emerge.log"
659 PORTDIR = "simulate/"
661 main("package", "first_fake_package")
663 print(RED("\nChecking for three emerges\n"))
665 main("package", "second_fake_package")
667 print(RED("\n'package' mode check complete\n"))
671 print(RED("\nBeginning 'current' mode check"))
672 print(RED("Current emerge with no emerge process\n"))
674 main("current", None)
676 print(RED("\nCurrent emerge with emerge processes\n"))
678 PACKAGES.append(package("test-group/second_fake_package", "2.9-r2"))
679 PACKAGES[0].emerge_time = 60
680 PACKAGES.append(package("test-group/first_fake_package", "1.10.2-r1"))
681 PACKAGES[1].emerge_time = 120
683 main("current", None)
685 print(RED("\nCurrent emerge with incomplete emerge log " +
686 "(causes error in some cases)\n"))
689 PACKAGES.append(package("test-group/third_fake_package", "2.9-r2"))
691 main("current", None)
693 print(RED("\n" + '*'*20 + "\n" + "SIMULATION FINISHED\n" +
698 main(mode, input_packages)