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:
61 def min_max_time(self, setting):
62 """Return maximum or minimum time from class version list"""
65 for i in self.versions:
66 emerge_times.append(i[1])
71 return emerge_times[-1]
72 elif setting == "min":
73 return emerge_times[0]
78 def print_current_emerge(self):
79 """Function used to print all the current emerge stuff"""
81 print("\t" + GREEN(self.name + '-' + self.version) +
82 "\n\t current time: " + give_time(self.emerge_time))
85 if len(self.versions) == 1:
86 print("\t last time: "),
87 print(give_time(self.average_time())),
89 elif len(self.versions) > 1:
90 print("\t average time:"),
91 print(give_time(self.average_time())),
94 print("\t average time: " + GREEN("unknown\n")),
97 print("\n\t " + '-'*45),
99 print("\n\t time to finish:"),
101 if type(self.emerge_time) != str:
103 finish_time = self.average_time() - self.emerge_time
106 print(give_time(finish_time))
108 print(GREEN("any time now"))
110 print(GREEN("unknown"))
114 def print_versions(self):
115 """This prints the emerge times for different versions in the
116 'package' operating mode of the script"""
123 for p in self.versions:
124 if len(p[0]) > version_length:
125 version_length = len(p[0])
127 if len(give_time(p[1], True)) > time_length:
128 time_length = len(give_time(p[1], True))
130 # Create the data for plotting in the format (emerge time, emerge date)
131 self.plotData.append((p[1], p[2]))
133 dots = (version_length + time_length + len(self.name)
134 + len(give_date(self.versions[0][2])) + 14)
136 for p in self.versions:
138 pad = time_length - len(give_time(p[1], True))
141 p_time = give_time(p[1])
142 p_date = give_date(p[2])
144 print('-' * dots + "\n" +
145 GREEN(name + (p[0]).ljust(version_length))
146 + " >>> " + p_time + " "*pad + " >>> " + p_date)
148 print("\n" + "Package " + GREEN(self.name) + " emerged"),
150 if len(self.versions) > 1:
151 print(str(len(self.versions)) + " times.\n")
152 elif len(self.versions) == 1:
157 def print_pretended_times(self):
158 """This is used the print all the pretended times"""
161 print("\t" + GREEN(self.name + '-' + self.version)),
163 if len(self.versions) > 1:
164 aver_time = self.average_time()
167 print("\n\taverage time: " + give_time(aver_time))
173 print("\n\t no previous emerges")
178 def print_min_max_ave(self):
180 if len(self.versions) == 1:
183 maxi = self.min_max_time("max")
184 mini = self.min_max_time("min")
185 average = self.average_time()
186 total = self.total_time()
188 print("Max time:\t" + give_time(maxi) +
189 "\nMin time:\t" + give_time(mini) +
190 "\nAverage time:\t" + give_time(average) +
191 "\n\nIn total spent:\t" + give_time(total) +
192 "emerging " + GREEN(self.name))
194 def plotToScreen(self):
198 for i in self.plotData:
199 dates.append(datetime.date.fromtimestamp(i[1]))
204 plt.plot_date(dates, times, xdate=True, ydate=False)
206 plt.ylabel("Emerge time [s]")
207 plt.suptitle(self.name)
214 def give_time(time, nocolor=False):
215 """Converts time in seconds to human readable form"""
216 global green_start, color_stop
218 if green_start == "":
225 if type(time) == str:
226 return(GREEN("unknown"))
229 days = time/(3600.0*24.0)
230 hours = (days - int(days))*24.0
231 minutes = (hours - int(hours))*60.0
232 seconds = (minutes - int(minutes))*60.0
236 minutes = int(minutes)
237 seconds = int(round(seconds))
245 pdays = (GREEN(str(days)) + " day ")
247 pdays = (GREEN(str(days)) + " days ")
250 phours = (GREEN(str(hours)) + " hour ")
252 phours = (GREEN(str(hours)) + " hours ")
255 pminutes = (GREEN(str(minutes)) + " minute ")
257 pminutes = (GREEN(str(minutes)) + " minutes ")
260 pseconds = (GREEN(str(seconds)) + " second ")
262 pseconds = (GREEN(str(seconds)) + " seconds ")
265 green_start = "\033[32m"
266 color_stop = "\033[m"
268 return (pdays + phours + pminutes + pseconds)
272 def give_date(emerge_date):
273 """Returns a date string from a standard POSIX time"""
274 date = datetime.datetime.fromtimestamp(emerge_date)
276 date = "{:%d.%m.%Y %H:%M:%S}".format(date)
283 """Attempt to open the LOGFILE."""
286 f = open(LOGFILE, 'r')
287 except IOError as detail:
295 def search_log_for_package(package_class):
296 """Searchs emerge log for given package and adds all found
297 versions with their emerge times to the class"""
302 if ((">>>" in line) and ("emerge" in line)):
303 if package_class.name in line:
305 version = line.partition(package_class.name)[2].partition(' ')[0]
306 digit = version.strip('-')[0].isdigit()
309 time_string = line.partition(">>>")
310 start_time = float(time_string[0].strip().strip(':'))
312 elif ((":::" in line) and ("completed emerge" in line)):
314 if package_class.name in line:
316 time_string = line.partition(":::")
317 stop_time = float(time_string[0].strip().strip(':'))
319 emerge_time = stop_time - start_time
321 package_class.add_version(version, emerge_time, start_time)
325 def search_log_for_all_packages():
326 """Goes through the emerge.log and lists all packages in there"""
332 total_emerge_time = 0
336 if ((">>>" in line) and ("emerge" in line)):
337 pack = line.partition(')')[2].strip().partition(' ')[0]
338 start_time = float(line.partition(':')[0])
340 all_packages.append((pack, start_time))
342 elif ((":::" in line) and ("completed emerge" in line)):
343 for p in all_packages:
345 print("\t" + give_date(p[1]) + " >>> " + GREEN(p[0]))
349 all_packages.pop(all_packages.index(p))
352 print("\n" + GREEN(str(emerge_number)) + " emerges in total found.")
356 def get_package(name):
357 """Take the user-input package name and search for it
360 dirlist = os.listdir(PORTDIR)
361 possible_package = []
364 # If the given name is in the format xxx/zzz
365 # assume that xxx is the package group
367 group = name.partition('/')[0]
368 pkg = name.partition('/')[2]
369 directory = PORTDIR + group
372 dirs = os.listdir(directory)
374 possible_package.append(name)
377 # Go through the directory listing searching for anything
378 # that matches the given name
380 directory = PORTDIR + i
381 if os.path.isdir(directory):
382 dirs = os.listdir(directory)
384 possible_package.append(i + '/' + name)
387 if len(possible_package) > 1:
388 print("Multiple packages found for '" + name + "'.")
389 print("Possible packages: ")
390 for value in possible_package:
394 elif len(possible_package) == 1:
395 package = possible_package[0]
400 print("No package '" + name + "' found")
407 def list_pretended():
408 """List all the pretended packages given by emerge -p
409 output. Create a class out of each of those packages and add them
414 for line in sys.stdin:
415 if "[ebuild" in line:
416 full_name = line.partition("] ")[2].partition(' ')[0]
418 version = full_name.partition('/')[2].partition('-')[2]
419 while not version[0].isdigit():
420 version = version.partition('-')[2]
421 package_name = full_name[:-len(version)-1]
423 PACKAGES.append(package(package_name, version))
427 def list_emerge_processes():
428 """Look for the ebuild process with ps. If the process is found parse
429 the command for the package. With this package search the LOGFILE for
430 the emerge startup time."""
434 now = datetime.datetime.today()
436 for i in os.popen("ps ax"):
437 if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
438 pack = i.partition('[')[2].partition(']')[0]
440 version = pack.partition('/')[2].partition('-')[2]
442 while not version[0].isdigit():
443 version = version.partition('-')[2]
445 package_name = pack[:-len(version)-1]
447 PACKAGES.append(package(package_name, version))
450 if len(PACKAGES) == 0:
451 print "No current emerge process found."
457 if ((">>>" in line) and ("emerge" in line)):
461 if (p.name + '-' + p.version in line):
463 time = float(line.partition(' ')[0].strip(":"))
465 timestamp = datetime.datetime.fromtimestamp(time)
466 difference = (now - timestamp).total_seconds()
468 if ((difference < p.emerge_time) or
469 (p.emerge_time == "infinity")):
471 p.emerge_time = difference
479 print "These emerge syncs found"
480 print "\tDate Server"
481 print "\t------------------------------"
484 if "=== Sync completed with" in line:
485 time = float(line.partition(' ')[0].strip(":"))
486 server = line.rpartition(' ')[2]
488 print("\t" + GREEN(give_date(time)) +
493 def main(status, user_package=None):
495 _main(status, user_package)
500 def _main(status, user_package=None):
501 """Main function. Handle all the different modes of operation."""
503 if status == "package":
504 for p in user_package:
505 pack = get_package(p)
509 search_log_for_package(pack)
511 if len(pack.versions) != 0:
512 pack.print_versions()
513 pack.print_min_max_ave()
519 print("Package " + GREEN(pack.name)
520 + " has never been emerged.")
523 elif status == "sync":
528 elif status == "list":
529 search_log_for_all_packages()
533 elif status == "current":
534 if list_emerge_processes():
537 print "Currently emerging:"
540 search_log_for_package(p)
541 p.print_current_emerge()
544 elif status == "pretended":
547 print "This is how long these packages would take to emerge"
549 total_pretended_time = 0
552 search_log_for_package(p)
554 total_pretended_time += p.print_pretended_times()
558 print("Total emerge time of " + GREEN(str(len(PACKAGES)))
559 + " package(s): "+ give_time(total_pretended_time))
563 usage = """Usage: emerge-timer.py [package] [options]
565 Calculate emerge times from emerge log.
568 \t-c, --current \t Show time until currently compiling package finishes
569 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
570 \t-l, --list \t List all emerged packages
571 \t-s, --sync \t Show emerge sync history
572 \t-h, --help \t Show this helpscreen
573 \t-q, --quiet \t Be less verbose
574 \t--no-color \t Use colorless output
575 \t--plot \t\t Plot emerge times into a 2D scatter plot
576 \t\t\t (needs matlibplot installed for this to work)"""
584 if __name__ == "__main__":
586 # Set the default mode as "package"
588 input_packages = None
590 matplotWorking = False
592 for arg in sys.argv[1:]:
594 if arg == "-p" or arg == "--pretended":
597 if arg == "-c" or arg == "--current":
600 if arg == "-h" or arg == "--help":
603 if arg == "-l" or arg == "--list":
606 if arg == "-s" or arg == "--sync":
609 if arg == "-q" or arg == "--quiet":
612 sys.argv.pop(sys.argv.index(arg))
616 import matplotlib.pyplot as plt
617 matplotWorking = True
619 print(RED("Cannot initialize matplotlib!"))
620 print(RED("Check that you have properly installed matplotlib.\n"))
621 matplotWorking = False
623 sys.argv.pop(sys.argv.index(arg))
625 if arg == "--no-color":
629 sys.argv.pop(sys.argv.index(arg))
631 if arg == "--simulate":
635 if len(sys.argv) > 1:
636 input_packages = sys.argv[1:]
640 main(mode, input_packages)