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)
222 def give_time(time, nocolor=False):
223 """Converts time in seconds to human readable form"""
224 global green_start, color_stop
226 if green_start == "":
233 if type(time) == str:
234 return(GREEN("unknown"))
237 days = time/(3600.0*24.0)
238 hours = (days - int(days))*24.0
239 minutes = (hours - int(hours))*60.0
240 seconds = (minutes - int(minutes))*60.0
244 minutes = int(minutes)
245 seconds = int(round(seconds))
253 pdays = (GREEN(str(days)) + " day ")
255 pdays = (GREEN(str(days)) + " days ")
258 phours = (GREEN(str(hours)) + " hour ")
260 phours = (GREEN(str(hours)) + " hours ")
263 pminutes = (GREEN(str(minutes)) + " minute ")
265 pminutes = (GREEN(str(minutes)) + " minutes ")
268 pseconds = (GREEN(str(seconds)) + " second ")
270 pseconds = (GREEN(str(seconds)) + " seconds ")
273 green_start = "\033[32m"
274 color_stop = "\033[m"
276 return (pdays + phours + pminutes + pseconds)
280 def give_date(emerge_date):
281 """Returns a date string from a standard POSIX time"""
282 date = datetime.datetime.fromtimestamp(emerge_date)
284 date = "{:%d.%m.%Y %H:%M:%S}".format(date)
291 """Attempt to open the LOGFILE."""
294 f = open(LOGFILE, 'r')
295 except IOError as detail:
303 def search_log_for_package(package_class):
304 """Searchs emerge log for given package and adds all found
305 versions with their emerge times to the class"""
310 if ((">>>" in line) and ("emerge" in line)):
311 if package_class.name in line:
313 version = line.partition(package_class.name)[2].partition(' ')[0]
314 digit = version.strip('-')[0].isdigit()
317 time_string = line.partition(">>>")
318 start_time = float(time_string[0].strip().strip(':'))
320 elif ((":::" in line) and ("completed emerge" in line)):
322 if package_class.name in line:
324 time_string = line.partition(":::")
325 stop_time = float(time_string[0].strip().strip(':'))
327 emerge_time = stop_time - start_time
329 package_class.add_version(version, emerge_time, start_time)
333 def search_log_for_all_packages():
334 """Goes through the emerge.log and lists all packages in there"""
340 total_emerge_time = 0
344 if ((">>>" in line) and ("emerge" in line)):
345 pack = line.partition(')')[2].strip().partition(' ')[0]
346 start_time = float(line.partition(':')[0])
348 all_packages.append((pack, start_time))
350 elif ((":::" in line) and ("completed emerge" in line)):
351 for p in all_packages:
353 print("\t" + give_date(p[1]) + " >>> " + GREEN(p[0]))
357 all_packages.pop(all_packages.index(p))
360 print("\n" + GREEN(str(emerge_number)) + " emerges in total found.")
364 def get_package(name):
365 """Take the user-input package name and search for it
368 dirlist = os.listdir(PORTDIR)
369 possible_package = []
372 # If the given name is in the format xxx/zzz
373 # assume that xxx is the package group
375 group = name.partition('/')[0]
376 pkg = name.partition('/')[2]
377 directory = PORTDIR + group
380 dirs = os.listdir(directory)
382 possible_package.append(name)
385 # Go through the directory listing searching for anything
386 # that matches the given name
388 directory = PORTDIR + i
389 if os.path.isdir(directory):
390 dirs = os.listdir(directory)
392 possible_package.append(i + '/' + name)
395 if len(possible_package) > 1:
396 print("Multiple packages found for '" + name + "'.")
397 print("Possible packages: ")
398 for value in possible_package:
402 elif len(possible_package) == 1:
403 package = possible_package[0]
408 print("No package '" + name + "' found")
415 def list_pretended():
416 """List all the pretended packages given by emerge -p
417 output. Create a class out of each of those packages and add them
422 for line in sys.stdin:
423 if "[ebuild" in line:
424 full_name = line.partition("] ")[2].partition(' ')[0]
426 version = full_name.partition('/')[2].partition('-')[2]
427 while not version[0].isdigit():
428 version = version.partition('-')[2]
429 package_name = full_name[:-len(version)-1]
431 PACKAGES.append(package(package_name, version))
435 def list_emerge_processes():
436 """Look for the ebuild process with ps. If the process is found parse
437 the command for the package. With this package search the LOGFILE for
438 the emerge startup time."""
442 now = datetime.datetime.today()
444 for i in os.popen("ps ax"):
445 if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
446 pack = i.partition('[')[2].partition(']')[0]
448 version = pack.partition('/')[2].partition('-')[2]
450 while not version[0].isdigit():
451 version = version.partition('-')[2]
453 package_name = pack[:-len(version)-1]
455 PACKAGES.append(package(package_name, version))
458 if len(PACKAGES) == 0:
459 print "No current emerge process found."
465 if ((">>>" in line) and ("emerge" in line)):
469 if (p.name + '-' + p.version in line):
471 time = float(line.partition(' ')[0].strip(":"))
473 timestamp = datetime.datetime.fromtimestamp(time)
474 difference = (now - timestamp).total_seconds()
476 if ((difference < p.emerge_time) or
477 (p.emerge_time == "infinity")):
479 p.emerge_time = difference
487 print "These emerge syncs found"
488 print "\tDate Server"
489 print "\t------------------------------"
492 if "=== Sync completed with" in line:
493 time = float(line.partition(' ')[0].strip(":"))
494 server = line.rpartition(' ')[2]
496 print("\t" + GREEN(give_date(time)) +
501 def main(status, user_package=None):
503 _main(status, user_package)
508 def _main(status, user_package=None):
509 """Main function. Hanlde all the different modes of operation."""
511 if status == "package":
512 for p in user_package:
513 pack = get_package(p)
517 search_log_for_package(pack)
519 if len(pack.versions) != 0:
520 pack.print_versions()
521 pack.print_min_max_ave()
527 print("Package " + GREEN(pack.name)
528 + " has never been emerged.")
531 elif status == "sync":
536 elif status == "list":
537 search_log_for_all_packages()
541 elif status == "current":
542 if list_emerge_processes():
545 print "Currently emerging:"
548 search_log_for_package(p)
549 p.print_current_emerge()
552 elif status == "pretended":
555 print "This is how long these packages would take to emerge"
557 total_pretended_time = 0
560 search_log_for_package(p)
562 total_pretended_time += p.print_pretended_times()
566 print("Total emerge time of " + GREEN(str(len(PACKAGES)))
567 + " package(s): "+ give_time(total_pretended_time))
571 usage = """Usage: emerge-timer.py [package] [options]
573 Calculate emerge times from emerge log.
576 \t-c, --current \t Show time until currently compiling package finishes
577 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
578 \t-l, --list \t List all emerged packages
579 \t-s, --sync \t Show emerge sync history
580 \t-h, --help \t Show this helpscreen
581 \t-q, --quiet \t Be less verbose
582 \t--no-color \t Use colorless output
583 \t--plot \t\t Plot emerge times into a 2D scatter plot
584 \t\t\t (needs matlibplot installed for this to work)"""
592 if __name__ == "__main__":
594 # Set the default mode as "package"
596 input_packages = None
598 matplotWorking = False
600 for arg in sys.argv[1:]:
602 if arg == "-p" or arg == "--pretended":
605 if arg == "-c" or arg == "--current":
608 if arg == "-h" or arg == "--help":
611 if arg == "-l" or arg == "--list":
614 if arg == "-s" or arg == "--sync":
617 if arg == "-q" or arg == "--quiet":
620 sys.argv.pop(sys.argv.index(arg))
624 import matplotlib.pyplot as plt
625 matplotWorking = True
627 print(RED("Cannot initialize matplotlib!"))
628 print(RED("Check that you have properly installed matplotlib.\n"))
629 matplotWorking = False
631 sys.argv.pop(sys.argv.index(arg))
633 if arg == "--no-color":
637 sys.argv.pop(sys.argv.index(arg))
639 if arg == "--simulate":
643 if len(sys.argv) > 1:
644 input_packages = sys.argv[1:]
648 main(mode, input_packages)