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("\nTotal emerge time of " + GREEN(str(emerge_number)) +
362 " merges: " + give_time(total_emerge_time))
366 def get_package(name):
367 """Take the user-input package name and search for it
370 dirlist = os.listdir(PORTDIR)
371 possible_package = []
374 # If the given name is in the format xxx/zzz
375 # assume that xxx is the package group
377 group = name.partition('/')[0]
378 pkg = name.partition('/')[2]
379 directory = PORTDIR + group
382 dirs = os.listdir(directory)
384 possible_package.append(name)
387 # Go through the directory listing searching for anything
388 # that matches the given name
390 directory = PORTDIR + i
391 if os.path.isdir(directory):
392 dirs = os.listdir(directory)
394 possible_package.append(i + '/' + name)
397 if len(possible_package) > 1:
398 print("Multiple packages found for '" + name + "'.")
399 print("Possible packages: ")
400 for value in possible_package:
404 elif len(possible_package) == 1:
405 package = possible_package[0]
410 print("No package '" + name + "' found")
417 def list_pretended():
418 """List all the pretended packages given by emerge -p
419 output. Create a class out of each of those packages and add them
424 for line in sys.stdin:
425 if "[ebuild" in line:
426 full_name = line.partition("] ")[2].partition(' ')[0]
428 version = full_name.partition('/')[2].partition('-')[2]
429 while not version[0].isdigit():
430 version = version.partition('-')[2]
431 package_name = full_name[:-len(version)-1]
433 PACKAGES.append(package(package_name, version))
437 def list_emerge_processes():
438 """Look for the ebuild process with ps. If the process is found parse
439 the command for the package. With this package search the LOGFILE for
440 the emerge startup time."""
444 now = datetime.datetime.today()
446 for i in os.popen("ps ax"):
447 if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
448 pack = i.partition('[')[2].partition(']')[0]
450 version = pack.partition('/')[2].partition('-')[2]
452 while not version[0].isdigit():
453 version = version.partition('-')[2]
455 package_name = pack[:-len(version)-1]
457 PACKAGES.append(package(package_name, version))
460 if len(PACKAGES) == 0:
461 print "No current emerge process found."
467 if ((">>>" in line) and ("emerge" in line)):
471 if (p.name + '-' + p.version in line):
473 time = float(line.partition(' ')[0].strip(":"))
475 timestamp = datetime.datetime.fromtimestamp(time)
476 difference = (now - timestamp).total_seconds()
478 if ((difference < p.emerge_time) or
479 (p.emerge_time == "infinity")):
481 p.emerge_time = difference
489 print "These emerge syncs found"
490 print "\tDate Server"
491 print "\t------------------------------"
494 if "=== Sync completed with" in line:
495 time = float(line.partition(' ')[0].strip(":"))
496 server = line.rpartition(' ')[2]
498 print("\t" + GREEN(give_date(time)) +
503 def main(status, user_package=None):
505 _main(status, user_package)
510 def _main(status, user_package=None):
511 """Main function. Hanlde all the different modes of operation."""
513 if status == "package":
514 for p in user_package:
515 pack = get_package(p)
519 search_log_for_package(pack)
521 if len(pack.versions) != 0:
522 pack.print_versions()
523 pack.print_min_max_ave()
529 print("Package " + GREEN(pack.name)
530 + " has never been emerged.")
533 elif status == "sync":
538 elif status == "list":
539 search_log_for_all_packages()
543 elif status == "current":
544 if list_emerge_processes():
547 print "Currently emerging:"
550 search_log_for_package(p)
551 p.print_current_emerge()
554 elif status == "pretended":
557 print "This is how long these packages would take to emerge"
559 total_pretended_time = 0
562 search_log_for_package(p)
564 total_pretended_time += p.print_pretended_times()
568 print("Total emerge time of " + GREEN(str(len(PACKAGES)))
569 + " package(s): "+ give_time(total_pretended_time))
573 usage = """Usage: emerge-timer.py [package] [options]
575 Calculate emerge times from emerge log.
578 \t-c, --current \t Show time until currently compiling package finishes
579 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
580 \t-l, --list \t List all emerged packages
581 \t-s, --sync \t Show emerge sync history
582 \t-h, --help \t Show this helpscreen
583 \t-q, --quiet \t Be less verbose
584 \t--no-color \t Use colorless output
585 \t--plot \t\t Plot emerge times into a 2D scatter plot
586 \t\t\t (needs matlibplot installed for this to work)
587 \t--simulate \t Do a simulation run"""
594 if __name__ == "__main__":
596 # Set the default mode as "package"
598 input_packages = None
600 matplotWorking = False
602 for arg in sys.argv[1:]:
604 if arg == "-p" or arg == "--pretended":
607 if arg == "-c" or arg == "--current":
610 if arg == "-h" or arg == "--help":
613 if arg == "-l" or arg == "--list":
616 if arg == "-s" or arg == "--sync":
619 if arg == "-q" or arg == "--quiet":
622 sys.argv.pop(sys.argv.index(arg))
626 import matplotlib.pyplot as plt
627 matplotWorking = True
629 print(RED("Cannot initialize matplotlib!"))
630 print(RED("Check that you have properly installed matplotlib.\n"))
631 matplotWorking = False
633 sys.argv.pop(sys.argv.index(arg))
635 if arg == "--no-color":
639 sys.argv.pop(sys.argv.index(arg))
641 if arg == "--simulate":
645 if len(sys.argv) > 1:
646 input_packages = sys.argv[1:]
650 if simulation == True:
652 print(RED("\n" + '*'*25 + "\n" + "THIS IS A SIMULATION RUN\n"
655 print(RED("Beginning 'package' mode check"))
657 print(RED("Checking for one emerge\n"))
659 LOGFILE = "simulate/fake_emerge.log"
660 PORTDIR = "simulate/"
662 main("package", "first_fake_package")
664 print(RED("\nChecking for three emerges\n"))
666 main("package", "second_fake_package")
668 print(RED("\n'package' mode check complete\n"))
672 print(RED("\nBeginning 'current' mode check"))
673 print(RED("Current emerge with no emerge process\n"))
675 main("current", None)
677 print(RED("\nCurrent emerge with emerge processes\n"))
679 PACKAGES.append(package("test-group/second_fake_package", "2.9-r2"))
680 PACKAGES[0].emerge_time = 60
681 PACKAGES.append(package("test-group/first_fake_package", "1.10.2-r1"))
682 PACKAGES[1].emerge_time = 120
684 main("current", None)
686 print(RED("\nCurrent emerge with incomplete emerge log " +
687 "(causes error in some cases)\n"))
690 PACKAGES.append(package("test-group/third_fake_package", "2.9-r2"))
692 main("current", None)
694 print(RED("\n" + '*'*20 + "\n" + "SIMULATION FINISHED\n" +
699 main(mode, input_packages)