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 seek_versions(self, whatToSeek, Input):
43 if whatToSeek == "date":
44 for i in self.versions:
48 if whatToSeek == "version":
49 for i in self.versions:
54 def average_time(self):
55 """Return average time from class version list"""
57 for i in self.versions:
60 average_time = total_time/len(self.versions)
66 """Return total time from class version list"""
68 for i in self.versions:
74 def min_max_time(self, setting):
75 """Return maximum or minimum time from class version list"""
78 for i in self.versions:
79 emerge_times.append(i[1])
84 return emerge_times[-1]
85 elif setting == "min":
86 return emerge_times[0]
91 def print_current_emerge(self):
92 """Function used to print all the current emerge stuff"""
94 print("\t" + GREEN(self.name + '-' + self.version) +
95 "\n\t current time: " + give_time(self.emerge_time))
98 if len(self.versions) == 1:
99 print("\t last time: "),
100 print(give_time(self.average_time()), end='')
102 elif len(self.versions) > 1:
103 print("\t average time: ", end='')
104 print(give_time(self.average_time()), end='')
107 print("\t average time: " + GREEN("unknown\n")),
110 print("\n\t " + '-'*45, end='')
112 print("\n\t time to finish: ", end='')
114 if type(self.emerge_time) != str:
116 finish_time = self.average_time() - self.emerge_time
119 print(give_time(finish_time), "\n")
121 print(GREEN("any time now"))
123 print(GREEN("unknown"))
127 def print_versions(self):
128 """This prints the emerge times for different versions in the
129 'package' operating mode of the script"""
136 for p in self.versions:
137 if len(p[0]) > version_length:
138 version_length = len(p[0])
140 if len(give_time(p[1], True)) > time_length:
141 time_length = len(give_time(p[1], True))
143 # Create the data for plotting in the format (emerge time, emerge date)
144 self.plotData.append((p[1], p[2]))
146 dots = (version_length + time_length + len(self.name)
147 + len(give_date(self.versions[0][2])) + 14)
149 for p in self.versions:
151 pad = time_length - len(give_time(p[1], True))
154 p_time = give_time(p[1])
155 p_date = give_date(p[2])
157 print('-' * dots + "\n" +
158 GREEN(name + (p[0]).ljust(version_length))
159 + " >>> " + p_time + " "*pad + " >>> " + p_date)
161 print("\n" + "Package " + GREEN(self.name) + " emerged"),
163 if len(self.versions) > 1:
164 print(str(len(self.versions)) + " times.\n")
165 elif len(self.versions) == 1:
170 def print_pretended_times(self):
171 """This is used the print all the pretended times"""
174 print("\t" + GREEN(self.name + '-' + self.version)),
176 if len(self.versions) > 1:
177 aver_time = self.average_time()
180 print("\n\taverage time: " + give_time(aver_time))
186 print("\n\t no previous emerges")
191 def print_min_max_ave(self):
193 if len(self.versions) == 1:
196 maxi = self.min_max_time("max")
197 mini = self.min_max_time("min")
198 average = self.average_time()
199 total = self.total_time()
202 "\nMaximum emerge time:\n" +
203 give_time(maxi) + "for version " +
204 GREEN(self.seek_versions("version", maxi).lstrip("-"))
206 give_date(self.seek_versions("date", maxi)))
209 "\nMinimum emerge time:\n" +
210 give_time(mini) + "for version " +
211 GREEN(self.seek_versions("version", mini).lstrip("-"))
213 give_date(self.seek_versions("date", mini)))
216 "\nAverage emerge time:\n" +
220 "\nIn total spent:\n" +
224 def plotToScreen(self):
228 for i in self.plotData:
229 dates.append(datetime.date.fromtimestamp(i[1]))
234 plt.plot_date(dates, times, xdate=True, ydate=False)
236 plt.ylabel("Emerge time [s]")
237 plt.suptitle(self.name)
244 def give_time(time, nocolor=False):
245 """Converts time in seconds to human readable form"""
246 global green_start, color_stop
248 if green_start == "":
255 if type(time) == str:
256 return(GREEN("unknown"))
259 days = time/(3600.0*24.0)
260 hours = (days - int(days))*24.0
261 minutes = (hours - int(hours))*60.0
262 seconds = (minutes - int(minutes))*60.0
266 minutes = int(minutes)
267 seconds = int(round(seconds))
275 pdays = (GREEN(str(days)) + " day ")
277 pdays = (GREEN(str(days)) + " days ")
280 phours = (GREEN(str(hours)) + " hour ")
282 phours = (GREEN(str(hours)) + " hours ")
285 pminutes = (GREEN(str(minutes)) + " minute ")
287 pminutes = (GREEN(str(minutes)) + " minutes ")
290 pseconds = (GREEN(str(seconds)) + " second ")
292 pseconds = (GREEN(str(seconds)) + " seconds ")
295 green_start = "\033[32m"
296 color_stop = "\033[m"
298 return (pdays + phours + pminutes + pseconds)
302 def give_date(emerge_date):
303 """Returns a date string from a standard POSIX time"""
304 date = datetime.datetime.fromtimestamp(emerge_date)
306 date = "{:%d.%m.%Y %H:%M:%S}".format(date)
313 """Attempt to open the LOGFILE."""
316 f = open(LOGFILE, 'r')
317 except IOError as detail:
325 def search_log_for_package(package_class):
326 """Searchs emerge log for given package and adds all found
327 versions with their emerge times to the class"""
332 if ((">>>" in line) and ("emerge" in line)):
333 if package_class.name in line:
335 version = line.partition(package_class.name)[2].partition(' ')[0]
336 digit = version.strip('-')[0].isdigit()
339 time_string = line.partition(">>>")
340 start_time = float(time_string[0].strip().strip(':'))
342 elif ((":::" in line) and ("completed emerge" in line)):
344 if package_class.name in line:
346 time_string = line.partition(":::")
347 stop_time = float(time_string[0].strip().strip(':'))
349 emerge_time = stop_time - start_time
351 package_class.add_version(version, emerge_time, start_time)
355 def search_log_for_all_packages():
356 """Goes through the emerge.log and lists all packages in there"""
362 total_emerge_time = 0
366 if ((">>>" in line) and ("emerge" in line)):
367 pack = line.partition(')')[2].strip().partition(' ')[0]
368 start_time = float(line.partition(':')[0])
370 all_packages.append((pack, start_time))
372 elif ((":::" in line) and ("completed emerge" in line)):
373 for p in all_packages:
375 print("\t" + give_date(p[1]) + " >>> " + GREEN(p[0]))
379 all_packages.pop(all_packages.index(p))
382 print("\n" + GREEN(str(emerge_number)) + " emerges in total found.")
386 def get_package(name):
387 """Take the user-input package name and search for it
390 dirlist = os.listdir(PORTDIR)
391 possible_package = []
394 # If the given name is in the format xxx/zzz
395 # assume that xxx is the package group
397 group = name.partition('/')[0]
398 pkg = name.partition('/')[2]
399 directory = PORTDIR + group
402 dirs = os.listdir(directory)
404 possible_package.append(name)
407 # Go through the directory listing searching for anything
408 # that matches the given name
410 directory = PORTDIR + i
411 if os.path.isdir(directory):
412 dirs = os.listdir(directory)
414 possible_package.append(i + '/' + name)
417 if len(possible_package) > 1:
418 print("Multiple packages found for '" + name + "'.")
419 print("Possible packages: ")
420 for value in possible_package:
424 elif len(possible_package) == 1:
425 package = possible_package[0]
430 print("No package '" + name + "' found")
437 def list_pretended():
438 """List all the pretended packages given by emerge -p
439 output. Create a class out of each of those packages and add them
444 for line in sys.stdin:
445 if "[ebuild" in line:
446 full_name = line.partition("] ")[2].partition(' ')[0]
448 version = full_name.partition('/')[2].partition('-')[2]
449 while not version[0].isdigit():
450 version = version.partition('-')[2]
451 package_name = full_name[:-len(version)-1]
453 PACKAGES.append(package(package_name, version))
457 def list_emerge_processes():
458 """Look for the ebuild process with ps. If the process is found parse
459 the command for the package. With this package search the LOGFILE for
460 the emerge startup time."""
464 now = datetime.datetime.today()
466 for i in os.popen("ps ax"):
467 if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
468 pack = i.partition('[')[2].partition(']')[0]
470 version = pack.partition('/')[2].partition('-')[2]
472 while not version[0].isdigit():
473 version = version.partition('-')[2]
475 package_name = pack[:-len(version)-1]
477 PACKAGES.append(package(package_name, version))
480 if len(PACKAGES) == 0:
481 print("No current emerge process found.")
487 if ((">>>" in line) and ("emerge" in line)):
491 if (p.name + '-' + p.version in line):
493 time = float(line.partition(' ')[0].strip(":"))
495 timestamp = datetime.datetime.fromtimestamp(time)
496 difference = (now - timestamp).total_seconds()
498 if ((p.emerge_time == "infinity") or
499 (difference < p.emerge_time)):
501 p.emerge_time = difference
509 print("These emerge syncs found")
510 print("\tDate Server")
511 print("\t------------------------------")
515 if "=== Sync completed with" in line:
516 time = float(line.partition(' ')[0].strip(":"))
517 server = line.rpartition(' ')[2]
519 print("\t" + GREEN(give_date(time)) +
523 print("\n" + GREEN(str(a)) + " emerge syncs found. ")
526 def main(status, user_package=None):
528 _main(status, user_package)
533 def _main(status, user_package=None):
534 """Main function. Handle all the different modes of operation."""
536 if status == "package":
537 for p in user_package:
538 pack = get_package(p)
542 search_log_for_package(pack)
544 if len(pack.versions) != 0:
545 pack.print_versions()
546 pack.print_min_max_ave()
552 print("Package " + GREEN(pack.name)
553 + " has never been emerged.")
556 elif status == "sync":
561 elif status == "list":
562 search_log_for_all_packages()
566 elif status == "current":
567 if list_emerge_processes():
570 print("Currently emerging:")
573 search_log_for_package(p)
574 p.print_current_emerge()
577 elif status == "pretended":
580 print("This is how long these packages would take to emerge")
582 total_pretended_time = 0
585 search_log_for_package(p)
587 total_pretended_time += p.print_pretended_times()
591 print("Total emerge time of " + GREEN(str(len(PACKAGES)))
592 + " package(s): "+ give_time(total_pretended_time))
596 usage = """Usage: emerge-timer.py [package] [options]
598 Calculate emerge times from emerge log.
601 \t-c, --current \t Show time until currently compiling package finishes
602 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
603 \t-l, --list \t List all emerged packages
604 \t-s, --sync \t Show emerge sync history
605 \t-h, --help \t Show this helpscreen
606 \t-q, --quiet \t Be less verbose
607 \t--no-color \t Use colorless output
608 \t--plot \t\t Plot emerge times into a 2D scatter plot
609 \t\t\t (needs matlibplot installed for this to work)"""
617 if __name__ == "__main__":
619 # Set the default mode as "package"
621 input_packages = None
623 matplotWorking = False
625 for arg in sys.argv[1:]:
627 if arg == "-p" or arg == "--pretended":
630 if arg == "-c" or arg == "--current":
633 if arg == "-h" or arg == "--help":
636 if arg == "-l" or arg == "--list":
639 if arg == "-s" or arg == "--sync":
642 if arg == "-q" or arg == "--quiet":
645 sys.argv.pop(sys.argv.index(arg))
649 import matplotlib.pyplot as plt
650 matplotWorking = True
652 print(RED("Cannot initialize matplotlib!"))
653 print(RED("Check that you have properly installed matplotlib.\n"))
654 matplotWorking = False
656 sys.argv.pop(sys.argv.index(arg))
658 if arg == "--no-color":
662 sys.argv.pop(sys.argv.index(arg))
664 if arg == "--simulate":
668 if len(sys.argv) > 1:
669 input_packages = sys.argv[1:]
673 main(mode, input_packages)