#!/usr/bin/python
-import sys, subprocess, datetime, os, re
+import sys, datetime, os
PORTDIR = "/usr/portage/"
LOGFILE = "/var/log/emerge.log"
+
green_start = "\033[32m"
+red_start = "\033[1;31m"
color_stop = "\033[m"
-packages = []
+QUIET = False
+
+PACKAGES = []
+
+def GREEN(string):
+ return green_start + string + color_stop
+
+def RED(string):
+ return red_start + string + color_stop
class package:
self.name = name
self.version = version
self.versions = []
- self.emerge_time = 12*3600
+ self.emerge_time = "infinity"
- def add_version(self, version, emerge_time, emerge_date):
+ self.plotData = []
+
+ def add_version(self, version, emerge_time, emerge_date):
+ """Add version to the class version list"""
self.versions.append((version, emerge_time, emerge_date))
+ def seek_versions(self, whatToSeek, Input):
+
+ if whatToSeek == "date":
+ for i in self.versions:
+ if i[1] == Input:
+ return i[2]
+
+ if whatToSeek == "version":
+ for i in self.versions:
+ if i[1] == Input:
+ return i[0]
+
+
def average_time(self):
+ """Return average time from class version list"""
total_time = 0
for i in self.versions:
total_time += i[1]
return average_time
+
def total_time(self):
+ """Return total time from class version list"""
total_time = 0
for i in self.versions:
total_time += i[1]
return total_time
- def max_time(self):
- self.versions.sort()
+ def min_max_time(self, setting):
+ """Return maximum or minimum time from class version list"""
+
+ emerge_times = []
+ for i in self.versions:
+ emerge_times.append(i[1])
- return self.versions[len(self.versions)-1][1]
+ emerge_times.sort()
+ if setting == "max":
+ return emerge_times[-1]
+ elif setting == "min":
+ return emerge_times[0]
- def min_time(self):
- self.versions.sort()
- return self.versions[0][1]
def print_current_emerge(self):
+ """Function used to print all the current emerge stuff"""
- print("\t" + green_start + self.name + '-' + self.version +
- color_stop + "\n\t current time: " + self.time(self.emerge_time) +
- "\n\t average time: "),
+ print("\t" + GREEN(self.name + '-' + self.version) +
+ "\n\t current time: " + give_time(self.emerge_time))
+
+
+ if len(self.versions) == 1:
+ print("\t last time: "),
+ print(give_time(self.average_time()), end='')
+
+ elif len(self.versions) > 1:
+ print("\t average time: ", end='')
+ print(give_time(self.average_time()), end='')
- if len(self.versions) > 1:
- print(self.time(self.average_time())),
else:
- print("unknown"),
+ print("\t average time: " + GREEN("unknown\n")),
+ return
- print("\n\t " + '-'*45),
+ print("\n\t " + '-'*45, end='')
- finish_time = self.average_time() - self.emerge_time
+ print("\n\t time to finish: ", end='')
- print("\n\t time to finish: "),
+ if type(self.emerge_time) != str:
- if finish_time > 0:
- print(self.time(finish_time))
+ finish_time = self.average_time() - self.emerge_time
+
+ if finish_time > 0:
+ print(give_time(finish_time), "\n")
+ else:
+ print(GREEN("any time now"))
else:
- print("any time now")
+ print(GREEN("unknown"))
+ print
def print_versions(self):
- for p in self.versions:
- print('-'*90 + "\n" +
- green_start + self.name + p[0] + color_stop + " >>> " +
- self.time(p[1]) + " >>> " +
- self.date(p[2]))
- print('-'*90 + "\n" + "Package " + green_start + self.name + color_stop +
- " emerged " + str(len(self.versions)) + " times.")
- print
+ """This prints the emerge times for different versions in the
+ 'package' operating mode of the script"""
+
+ if QUIET == False:
+
+ version_length = 0
+ time_length = 0
+
+ for p in self.versions:
+ if len(p[0]) > version_length:
+ version_length = len(p[0])
+
+ if len(give_time(p[1], True)) > time_length:
+ time_length = len(give_time(p[1], True))
+
+ # Create the data for plotting in the format (emerge time, emerge date)
+ self.plotData.append((p[1], p[2]))
+
+ dots = (version_length + time_length + len(self.name)
+ + len(give_date(self.versions[0][2])) + 14)
+
+ for p in self.versions:
+
+ pad = time_length - len(give_time(p[1], True))
+
+ name = self.name
+ p_time = give_time(p[1])
+ p_date = give_date(p[2])
+
+ print('-' * dots + "\n" +
+ GREEN(name + (p[0]).ljust(version_length))
+ + " >>> " + p_time + " "*pad + " >>> " + p_date)
+
+ print("\n" + "Package " + GREEN(self.name) + " emerged"),
+
+ if len(self.versions) > 1:
+ print(str(len(self.versions)) + " times.\n")
+ elif len(self.versions) == 1:
+ print("once.\n")
+
+
def print_pretended_times(self):
- print("\t" + green_start + self.name + '-' + self.version + color_stop),
+ """This is used the print all the pretended times"""
+
+ if QUIET == False:
+ print("\t" + GREEN(self.name + '-' + self.version)),
if len(self.versions) > 1:
- print("\n\taverage time: " + self.time(self.average_time()))
+ aver_time = self.average_time()
+
+ if QUIET == False:
+ print("\n\taverage time: " + give_time(aver_time))
+
+ return aver_time
+
else:
- print("\n\t no previous emerges")
+ if QUIET == False:
+ print("\n\t no previous emerges")
+
+ return 0
def print_min_max_ave(self):
- maxi = self.max_time()
- mini = self.min_time()
+
+ if len(self.versions) == 1:
+ return
+
+ maxi = self.min_max_time("max")
+ mini = self.min_max_time("min")
average = self.average_time()
total = self.total_time()
- print("Max time: \t" + self.time(maxi) +
- "\nMin time: \t" + self.time(mini) +
- "\nAverage time: \t" + self.time(average) +
- "\nIn total spent " + self.time(total) +
- " emerging " + green_start + self.name + color_stop)
-
- def time(self, time):
-
- days = time/(3600*24)
- hours = (days - int(days))*24
- minutes = (hours - int(hours))*60
- seconds = (minutes - int(minutes))*60
-
- days = int(days)
- hours = int(hours)
- minutes = int(minutes)
- seconds = int(round(seconds))
-
- pdays = str()
- phours = str()
- pminutes = str()
- pseconds = str()
-
- if days > 0:
- pdays = (green_start + str(days) + color_stop + " day ")
- if days != 1:
- pdays = (green_start + str(days) + color_stop + " days ")
-
- if hours > 0:
- phours = (green_start + str(hours) + color_stop + " hour ")
- if hours != 1:
- phours = (green_start + str(hours) + color_stop + " hours ")
-
- if minutes > 0:
- pminutes = (green_start + str(minutes) + color_stop + " minute ")
- if minutes != 1:
- pminutes = (green_start + str(minutes) + color_stop + " minutes ")
-
- pseconds = (green_start + str(seconds) + color_stop + " second ")
+ print("-"*20 +
+ "\nMaximum emerge time:\n" +
+ give_time(maxi) + "for version " +
+ GREEN(self.seek_versions("version", maxi).lstrip("-"))
+ + " on " +
+ give_date(self.seek_versions("date", maxi)))
+
+ print("-"*20 +
+ "\nMinimum emerge time:\n" +
+ give_time(mini) + "for version " +
+ GREEN(self.seek_versions("version", mini).lstrip("-"))
+ + " on " +
+ give_date(self.seek_versions("date", mini)))
+
+ print("-"*20 +
+ "\nAverage emerge time:\n" +
+ give_time(average))
+
+ print("-"*20 +
+ "\nIn total spent:\n" +
+ give_time(total))
+
+
+ def plotToScreen(self):
+ dates = []
+ times = []
+
+ for i in self.plotData:
+ dates.append(datetime.date.fromtimestamp(i[1]))
+ times.append(i[0])
+
+ fig = plt.figure()
+
+ plt.plot_date(dates, times, xdate=True, ydate=False)
+
+ plt.ylabel("Emerge time [s]")
+ plt.suptitle(self.name)
+ plt.grid()
+ fig.autofmt_xdate()
+ plt.show()
+
+
+
+def give_time(time, nocolor=False):
+ """Converts time in seconds to human readable form"""
+ global green_start, color_stop
+
+ if green_start == "":
+ nocolor = False
+
+ if nocolor == True:
+ green_start = ""
+ color_stop = ""
+
+ if type(time) == str:
+ return(GREEN("unknown"))
+
+
+ days = time/(3600.0*24.0)
+ hours = (days - int(days))*24.0
+ minutes = (hours - int(hours))*60.0
+ seconds = (minutes - int(minutes))*60.0
+
+ days = int(days)
+ hours = int(hours)
+ minutes = int(minutes)
+ seconds = int(round(seconds))
+
+ pdays = str()
+ phours = str()
+ pminutes = str()
+ pseconds = str()
+
+ if days > 0:
+ pdays = (GREEN(str(days)) + " day ")
+ if days != 1:
+ pdays = (GREEN(str(days)) + " days ")
+
+ if hours > 0:
+ phours = (GREEN(str(hours)) + " hour ")
+ if hours != 1:
+ phours = (GREEN(str(hours)) + " hours ")
+
+ if minutes > 0:
+ pminutes = (GREEN(str(minutes)) + " minute ")
+ if minutes != 1:
+ pminutes = (GREEN(str(minutes)) + " minutes ")
+
+ if seconds > 0:
+ pseconds = (GREEN(str(seconds)) + " second ")
if seconds != 1:
- pseconds = (green_start + str(seconds) + color_stop + " seconds ")
+ pseconds = (GREEN(str(seconds)) + " seconds ")
+
+ if nocolor == True:
+ green_start = "\033[32m"
+ color_stop = "\033[m"
- return (pdays + phours + pminutes + pseconds)
+ return (pdays + phours + pminutes + pseconds)
- def date(self, emerge_date):
- date = datetime.datetime.fromtimestamp(emerge_date)
- year = str(date.year)
- month = str(date.month)
- day = str(date.day)
- hour = str(date.hour)
- minute = str(date.minute)
- second = str(date.second)
+def give_date(emerge_date):
+ """Returns a date string from a standard POSIX time"""
+ date = datetime.datetime.fromtimestamp(emerge_date)
- date = "{:%d.%m.%Y %H:%M:%S}".format(date)
+ date = "{:%d.%m.%Y %H:%M:%S}".format(date)
- return date
+ return date
try:
f = open(LOGFILE, 'r')
except IOError as detail:
- print detail
+ print(detail)
sys.exit(1)
- finally:
- return f
+
+ return f
def search_log_for_package(package_class):
+ """Searchs emerge log for given package and adds all found
+ versions with their emerge times to the class"""
log = open_log()
for line in log:
if ((">>>" in line) and ("emerge" in line)):
if package_class.name in line:
+
version = line.partition(package_class.name)[2].partition(' ')[0]
digit = version.strip('-')[0].isdigit()
start_time = float(time_string[0].strip().strip(':'))
elif ((":::" in line) and ("completed emerge" in line)):
+
if package_class.name in line:
if digit:
time_string = line.partition(":::")
package_class.add_version(version, emerge_time, start_time)
+
+def search_log_for_all_packages():
+ """Goes through the emerge.log and lists all packages in there"""
+
+ log = open_log()
+
+ all_packages = []
+
+ total_emerge_time = 0
+ emerge_number = 0
+
+ for line in log:
+ if ((">>>" in line) and ("emerge" in line)):
+ pack = line.partition(')')[2].strip().partition(' ')[0]
+ start_time = float(line.partition(':')[0])
+
+ all_packages.append((pack, start_time))
+
+ elif ((":::" in line) and ("completed emerge" in line)):
+ for p in all_packages:
+ if p[0] in line:
+ print("\t" + give_date(p[1]) + " >>> " + GREEN(p[0]))
+
+ emerge_number += 1
+
+ all_packages.pop(all_packages.index(p))
+
+
+ print("\n" + GREEN(str(emerge_number)) + " emerges in total found.")
+
+
+
def get_package(name):
"""Take the user-input package name and search for it
in PORTDIR. """
sys.exit(1)
+
def list_pretended():
+ """List all the pretended packages given by emerge -p
+ output. Create a class out of each of those packages and add them
+ to the list."""
+
log = open_log()
for line in sys.stdin:
version = version.partition('-')[2]
package_name = full_name[:-len(version)-1]
- packages.append(package(package_name, version))
+ PACKAGES.append(package(package_name, version))
+
def list_emerge_processes():
package_name = pack[:-len(version)-1]
- packages.append(package(package_name, version))
+ PACKAGES.append(package(package_name, version))
- if len(packages) == 0:
- print "No current emerge process found."
- sys.exit(0)
+ if len(PACKAGES) == 0:
+ print("No current emerge process found.")
+
+ return 1
for line in f:
if ((">>>" in line) and ("emerge" in line)):
- for p in packages:
+ for p in PACKAGES:
+ difference = 0
+
if (p.name + '-' + p.version in line):
time = float(line.partition(' ')[0].strip(":"))
timestamp = datetime.datetime.fromtimestamp(time)
difference = (now - timestamp).total_seconds()
- if difference < p.emerge_time:
+ if ((p.emerge_time == "infinity") or
+ (difference < p.emerge_time)):
+
p.emerge_time = difference
+ return 0
+def search_syncs():
+ f = open_log()
+
+ print("These emerge syncs found")
+ print("\tDate Server")
+ print("\t------------------------------")
+
+ a = 0
+ for line in f:
+ if "=== Sync completed with" in line:
+ time = float(line.partition(' ')[0].strip(":"))
+ server = line.rpartition(' ')[2]
+
+ print("\t" + GREEN(give_date(time)) +
+ " === " + server),
+ a += 1
+
+ print("\n" + GREEN(str(a)) + " emerge syncs found. ")
def main(status, user_package=None):
+ try:
+ _main(status, user_package)
+ except IOError:
+ sys.exit()
+
+
+def _main(status, user_package=None):
+ """Main function. Handle all the different modes of operation."""
if status == "package":
- user_package = get_package(user_package)
+ for p in user_package:
+ pack = get_package(p)
- pack = package(user_package)
+ pack = package(pack)
- search_log_for_package(pack)
- pack.print_versions()
- pack.print_min_max_ave()
+ search_log_for_package(pack)
+
+ if len(pack.versions) != 0:
+ pack.print_versions()
+ pack.print_min_max_ave()
+
+ if matplotWorking:
+ pack.plotToScreen()
+
+ else:
+ print("Package " + GREEN(pack.name)
+ + " has never been emerged.")
+
+
+ elif status == "sync":
+ search_syncs()
+ return
+
+
+ elif status == "list":
+ search_log_for_all_packages()
+ return
elif status == "current":
- list_emerge_processes()
+ if list_emerge_processes():
+ return
- print "Currently emerging:"
+ print("Currently emerging:")
- for p in packages:
+ for p in PACKAGES:
search_log_for_package(p)
p.print_current_emerge()
elif status == "pretended":
list_pretended()
- print "This is how long these packages would take to emerge"
+ print("This is how long these packages would take to emerge")
- for p in packages:
+ total_pretended_time = 0
+
+ for p in PACKAGES:
search_log_for_package(p)
- p.print_pretended_times()
+
+ total_pretended_time += p.print_pretended_times()
+
print
+ print("Total emerge time of " + GREEN(str(len(PACKAGES)))
+ + " package(s): "+ give_time(total_pretended_time))
+
+
+def usage():
+ usage = """Usage: emerge-timer.py [package] [options]
+
+Calculate emerge times from emerge log.
+
+Options:
+\t-c, --current \t Show time until currently compiling package finishes
+\t-p, --pretended Calculate compile time from piped 'emerge -p' output
+\t-l, --list \t List all emerged packages
+\t-s, --sync \t Show emerge sync history
+\t-h, --help \t Show this helpscreen
+\t-q, --quiet \t Be less verbose
+\t--no-color \t Use colorless output
+\t--plot \t\t Plot emerge times into a 2D scatter plot
+\t\t\t (needs matlibplot installed for this to work)"""
+
+
+ print(usage)
+
+ sys.exit(0)
+
if __name__ == "__main__":
- if len(sys.argv) == 1:
- main("current")
- sys.exit(1)
+ # Set the default mode as "package"
+ mode = "package"
+ input_packages = None
+ simulation = False
+ matplotWorking = False
- elif sys.argv[1] == "-p":
- main("pretended")
- sys.exit(1)
+ for arg in sys.argv[1:]:
+
+ if arg == "-p" or arg == "--pretended":
+ mode = "pretended"
+
+ if arg == "-c" or arg == "--current":
+ mode = "current"
+
+ if arg == "-h" or arg == "--help":
+ usage()
+
+ if arg == "-l" or arg == "--list":
+ mode = "list"
+
+ if arg == "-s" or arg == "--sync":
+ mode = "sync"
+
+ if arg == "-q" or arg == "--quiet":
+ QUIET = True
- elif len(sys.argv) > 1:
- main("package", sys.argv[1])
+ sys.argv.pop(sys.argv.index(arg))
+
+ if arg == "--plot":
+ try:
+ import matplotlib.pyplot as plt
+ matplotWorking = True
+ except ImportError:
+ print(RED("Cannot initialize matplotlib!"))
+ print(RED("Check that you have properly installed matplotlib.\n"))
+ matplotWorking = False
+
+ sys.argv.pop(sys.argv.index(arg))
+
+ if arg == "--no-color":
+ green_start = ""
+ color_stop = ""
+
+ sys.argv.pop(sys.argv.index(arg))
+
+ if arg == "--simulate":
+ simulation = True
+
+
+ if len(sys.argv) > 1:
+ input_packages = sys.argv[1:]
+ else:
+ usage()
+ main(mode, input_packages)