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 == "version":
44 for i in self.versions:
49 def average_time(self):
50 """Return average time from class version list"""
52 for i in self.versions:
55 average_time = total_time/len(self.versions)
61 """Return total time from class version list"""
63 for i in self.versions:
69 def min_max_time(self, setting):
70 """Return maximum or minimum time from class version list"""
73 for i in self.versions:
74 emerge_times.append(i[1])
79 return emerge_times[-1]
80 elif setting == "min":
81 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.min_max_time("max")
192 mini = self.min_max_time("min")
193 average = self.average_time()
194 total = self.total_time()
196 print("Max time:\t" + give_time(maxi) + "on " +
197 give_date(self.seek_versions("version", maxi)) +
198 "\nMin time:\t" + give_time(mini) + "on " +
199 give_date(self.seek_versions("version", mini)) +
200 "\nAverage time:\t" + give_time(average) +
201 "\n\nIn total spent:\t" + give_time(total) +
202 "emerging " + GREEN(self.name))
204 def plotToScreen(self):
208 for i in self.plotData:
209 dates.append(datetime.date.fromtimestamp(i[1]))
214 plt.plot_date(dates, times, xdate=True, ydate=False)
216 plt.ylabel("Emerge time [s]")
217 plt.suptitle(self.name)
224 def give_time(time, nocolor=False):
225 """Converts time in seconds to human readable form"""
226 global green_start, color_stop
228 if green_start == "":
235 if type(time) == str:
236 return(GREEN("unknown"))
239 days = time/(3600.0*24.0)
240 hours = (days - int(days))*24.0
241 minutes = (hours - int(hours))*60.0
242 seconds = (minutes - int(minutes))*60.0
246 minutes = int(minutes)
247 seconds = int(round(seconds))
255 pdays = (GREEN(str(days)) + " day ")
257 pdays = (GREEN(str(days)) + " days ")
260 phours = (GREEN(str(hours)) + " hour ")
262 phours = (GREEN(str(hours)) + " hours ")
265 pminutes = (GREEN(str(minutes)) + " minute ")
267 pminutes = (GREEN(str(minutes)) + " minutes ")
270 pseconds = (GREEN(str(seconds)) + " second ")
272 pseconds = (GREEN(str(seconds)) + " seconds ")
275 green_start = "\033[32m"
276 color_stop = "\033[m"
278 return (pdays + phours + pminutes + pseconds)
282 def give_date(emerge_date):
283 """Returns a date string from a standard POSIX time"""
284 date = datetime.datetime.fromtimestamp(emerge_date)
286 date = "{:%d.%m.%Y %H:%M:%S}".format(date)
293 """Attempt to open the LOGFILE."""
296 f = open(LOGFILE, 'r')
297 except IOError as detail:
305 def search_log_for_package(package_class):
306 """Searchs emerge log for given package and adds all found
307 versions with their emerge times to the class"""
312 if ((">>>" in line) and ("emerge" in line)):
313 if package_class.name in line:
315 version = line.partition(package_class.name)[2].partition(' ')[0]
316 digit = version.strip('-')[0].isdigit()
319 time_string = line.partition(">>>")
320 start_time = float(time_string[0].strip().strip(':'))
322 elif ((":::" in line) and ("completed emerge" in line)):
324 if package_class.name in line:
326 time_string = line.partition(":::")
327 stop_time = float(time_string[0].strip().strip(':'))
329 emerge_time = stop_time - start_time
331 package_class.add_version(version, emerge_time, start_time)
335 def search_log_for_all_packages():
336 """Goes through the emerge.log and lists all packages in there"""
342 total_emerge_time = 0
346 if ((">>>" in line) and ("emerge" in line)):
347 pack = line.partition(')')[2].strip().partition(' ')[0]
348 start_time = float(line.partition(':')[0])
350 all_packages.append((pack, start_time))
352 elif ((":::" in line) and ("completed emerge" in line)):
353 for p in all_packages:
355 print("\t" + give_date(p[1]) + " >>> " + GREEN(p[0]))
359 all_packages.pop(all_packages.index(p))
362 print("\n" + GREEN(str(emerge_number)) + " emerges in total found.")
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. Handle 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)"""
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 main(mode, input_packages)