LOGFILE = "/var/log/emerge.log"
-
green_start = "\033[32m"
+red_start = "\033[1;31m"
color_stop = "\033[m"
+QUIET = False
+PACKAGES = []
+def GREEN(string):
+ return green_start + string + color_stop
+def RED(string):
+ return red_start + string + color_stop
-def organize_times(time):
- """Takes the emerge time in seconds, organizes it into
- days, hours, minutes or seconds and finally prints that out."""
- days = time/(3600*24)
- hours = (days - int(days))*24
- minutes = (hours - int(hours))*60
- seconds = (minutes - int(minutes))*60
+class package:
+ def __init__(self, name, version=0):
+ self.name = name
+ self.version = version
+ self.versions = []
+ self.emerge_time = "infinity"
- days = int(days)
- hours = int(hours)
- minutes = int(minutes)
- seconds = int(round(seconds))
+ self.plotData = []
- if days > 0:
- print_days = (green_start + str(days) + color_stop + " day")
- if days != 1:
- print_days += "s"
- print print_days,
- if hours > 0:
- print_hours = (green_start + str(hours) + color_stop + " hour")
- if hours != 1:
- print_hours += "s"
- print print_hours,
+ def add_version(self, version, emerge_time, emerge_date):
+ """Add version to the class version list"""
+ self.versions.append((version, emerge_time, emerge_date))
- if minutes > 0:
- print_minutes = (green_start + str(minutes) + color_stop + " minute")
- if minutes != 1:
- print_minutes += "s"
- print print_minutes,
- printable_sec = (green_start + str(seconds) + color_stop + " second")
- if seconds != 1:
- printable_sec += "s"
- print printable_sec,
+ 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 get_date(emerge_start):
- """Take the emerge startup time in seconds and turn it into a
- correct date."""
- date = datetime.datetime.fromtimestamp(emerge_start)
+ def average_time(self):
+ """Return average time from class version list"""
+ total_time = 0
+ for i in self.versions:
+ total_time += i[1]
- weekday = date.weekday()
+ average_time = total_time/len(self.versions)
- if weekday == 0: weekday = 'Mon '
- if weekday == 1: weekday = 'Tue '
- if weekday == 2: weekday = 'Wed '
- if weekday == 3: weekday = 'Thu '
- if weekday == 4: weekday = 'Fri '
- if weekday == 5: weekday = 'Sat '
- if weekday == 6: weekday = 'Sun '
+ return average_time
- # This is in the format 'Mon 23.05.2011 00:20:14'
+ def total_time(self):
+ """Return total time from class version list"""
+ total_time = 0
+ for i in self.versions:
+ total_time += i[1]
- date = weekday + "{:%d.%m.%Y %H:%M:%S}".format(date)
+ return total_time
- return date
+ 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])
+ emerge_times.sort()
-def get_package(name):
- """Take the user-input package name and search for it
- in PORTDIR. """
+ if setting == "max":
+ return emerge_times[-1]
+ elif setting == "min":
+ return emerge_times[0]
- dirlist = os.listdir(PORTDIR)
- possible_package = []
- # If the given name is in the format xxx/zzz
- # assume that xxx is the package group
- if '/' in name:
- group = name.partition('/')[0]
- pkg = name.partition('/')[2]
- directory = PORTDIR + group
- if group in dirlist:
- dirs = os.listdir(directory)
- if pkg in dirs:
- possible_package.append(name)
+ def print_current_emerge(self):
+ """Function used to print all the current emerge stuff"""
+ print("\t" + GREEN(self.name + '-' + self.version) +
+ "\n\t current time: " + give_time(self.emerge_time))
- # Go through the directory listing searching for anything
- # that matches the given name
- for i in dirlist:
- directory = PORTDIR + i
- if os.path.isdir(directory):
- dirs = os.listdir(directory)
- if name in dirs:
- possible_package.append(i + '/' + name)
+ if len(self.versions) == 1:
+ print("\t last time: "),
+ print(give_time(self.average_time()), end='')
- if len(possible_package) > 1:
- print("Multiple packages found for '" + name + "'.")
- print("Possible packages: ")
- for value in possible_package:
- print("\t" + value)
+ elif len(self.versions) > 1:
+ print("\t average time: ", end='')
+ print(give_time(self.average_time()), end='')
+ else:
+ print("\t average time: " + GREEN("unknown\n")),
+ return
- elif len(possible_package) == 1:
- package = possible_package[0]
- return package
+ print("\n\t " + '-'*45, end='')
+ print("\n\t time to finish: ", end='')
- else:
- print("No package '" + name + "' found")
+ if type(self.emerge_time) != str:
+ finish_time = self.average_time() - self.emerge_time
- sys.exit(1)
+ if finish_time > 0:
+ print(give_time(finish_time), "\n")
+ else:
+ print(GREEN("any time now"))
+ else:
+ print(GREEN("unknown"))
+ print
+ def print_versions(self):
+ """This prints the emerge times for different versions in the
+ 'package' operating mode of the script"""
-def print_times(package, times, silent):
- """Print the maximum/minimum/average times of the given emerge package.
- If we're in the 'current emerge stage' (the 'silent' flag is True)
- print the appropriate comment for that package."""
+ if QUIET == False:
+ version_length = 0
+ time_length = 0
- times.sort()
- times.reverse()
+ 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))
- # This should be True if we're in current emerge stage
- if silent == True:
- if len(times) == 0:
- print("\t no previous emerges found for this package"),
- return 0
+ # 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")
- elif len(times) == 1:
- print("\t previous emerge time:\t"),
- organize_times(times[0][0])
- print("(" + green_start + "1" + color_stop + ")"),
- return times[0][0]
+
+
+ def print_pretended_times(self):
+ """This is used the print all the pretended times"""
+
+ if QUIET == False:
+ print("\t" + GREEN(self.name + '-' + self.version)),
+
+ if len(self.versions) > 1:
+ aver_time = self.average_time()
+
+ if QUIET == False:
+ print("\n\taverage time: " + give_time(aver_time))
+
+ return aver_time
else:
- print("\t average emerge time:\t"),
- all_times = 0
- for i in times:
- all_times += i[0]
+ if QUIET == False:
+ print("\n\t no previous emerges")
- organize_times(all_times/len(times))
- print("(" + green_start + str(len(times)) + color_stop + ")"),
- return all_times/len(times)
+ return 0
- if len(times) == 1:
- print(green_start + package + color_stop + " emerged once")
+ def print_min_max_ave(self):
- elif len(times) > 1:
- print(green_start + package + color_stop + " emerged " + green_start +
- str(len(times)) + color_stop + " times\n")
+ if len(self.versions) == 1:
+ return
- print "Max time:\t",
- organize_times(times[0][0])
- print "at", times[0][1]
+ maxi = self.min_max_time("max")
+ mini = self.min_max_time("min")
+ average = self.average_time()
+ total = self.total_time()
- print "Min time:\t",
- organize_times(times[len(times)-1][0])
- print "at", times[len(times)-1][1]
+ 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)))
- all_times = 0
- for i in times:
- all_times += i[0]
+ 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 "Average time\t",
- organize_times(all_times/len(times))
- print
+ 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()
- print "In total spent\t",
- organize_times(all_times)
- print("emerging " + green_start +
- package + color_stop)
+ 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(str(seconds)) + " seconds ")
+
+ if nocolor == True:
+ green_start = "\033[32m"
+ color_stop = "\033[m"
+
+ return (pdays + phours + pminutes + pseconds)
+
+
+
+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)
+
+ return date
try:
f = open(LOGFILE, 'r')
except IOError as detail:
- print detail
+ print(detail)
sys.exit(1)
return f
-def list_emerge_processes(f):
- """Look for the ebuild process with ps. If the process is found parse
- the command for the package. With this package search the LOGFILE for
- the emerge startup time."""
+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"""
- now = datetime.datetime.today()
- packages = []
+ log = open_log()
- for i in os.popen("ps ax"):
- if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
- pack = i.partition('[')[2].partition(']')[0]
+ for line in log:
+ if ((">>>" in line) and ("emerge" in line)):
+ if package_class.name in line:
- version = pack.partition('/')[2].partition('-')[2]
+ version = line.partition(package_class.name)[2].partition(' ')[0]
+ digit = version.strip('-')[0].isdigit()
- while not version[0].isdigit():
- version = version.partition('-')[2]
+ if digit:
+ time_string = line.partition(">>>")
+ start_time = float(time_string[0].strip().strip(':'))
- package_name = pack[:-len(version)-1]
+ elif ((":::" in line) and ("completed emerge" in line)):
+
+ if package_class.name in line:
+ if digit:
+ time_string = line.partition(":::")
+ stop_time = float(time_string[0].strip().strip(':'))
- packages.append([package_name, '-'+version, 12*3600])
+ emerge_time = stop_time - start_time
+ package_class.add_version(version, emerge_time, start_time)
- for line in f:
+
+
+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)):
- for p in packages:
- if (p[0]+p[1] in line):
+ pack = line.partition(')')[2].strip().partition(' ')[0]
+ start_time = float(line.partition(':')[0])
- time = float(line.partition(' ')[0].strip(":"))
+ all_packages.append((pack, start_time))
- timestamp = datetime.datetime.fromtimestamp(time)
- difference = (now - timestamp).total_seconds()
+ 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]))
- if difference < p[2]:
- p[2] = difference
+ emerge_number += 1
+ all_packages.pop(all_packages.index(p))
- if len(packages) == 0:
- print "No current emerge process found."
- return
- print_current_emerges(f, packages)
+ 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. """
+
+ dirlist = os.listdir(PORTDIR)
+ possible_package = []
+ # If the given name is in the format xxx/zzz
+ # assume that xxx is the package group
+ if '/' in name:
+ group = name.partition('/')[0]
+ pkg = name.partition('/')[2]
+ directory = PORTDIR + group
+
+ if group in dirlist:
+ dirs = os.listdir(directory)
+ if pkg in dirs:
+ possible_package.append(name)
-def print_current_emerges(f, packages):
- """Print the current packages that are being merged with the
- current emerge time."""
+ # Go through the directory listing searching for anything
+ # that matches the given name
+ for i in dirlist:
+ directory = PORTDIR + i
+ if os.path.isdir(directory):
+ dirs = os.listdir(directory)
+ if name in dirs:
+ possible_package.append(i + '/' + name)
- print("Currently emerging: ")
+ if len(possible_package) > 1:
+ print("Multiple packages found for '" + name + "'.")
+ print("Possible packages: ")
+ for value in possible_package:
+ print("\t" + value)
- for p in packages:
- print("\t" + green_start + p[0] + p[1] + color_stop),
- print("\n\t current emerge time:\t"),
- organize_times(p[2])
- print
+ elif len(possible_package) == 1:
+ package = possible_package[0]
+ return package
- average_time = main_loop(f, p[0], True)
- if average_time != 0:
- print("\n\t " + '-'*45 + "\n\t time to finish: \t"),
+ else:
+ print("No package '" + name + "' found")
- if (average_time - p[2]) < 0:
- print(green_start + "Any time now" + color_stop),
- else:
- organize_times(average_time - p[2])
+ sys.exit(1)
- print "\n"
+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."""
-def list_pretended(f):
- """Print the average times of pretended packages"""
+ log = open_log()
- packages = []
for line in sys.stdin:
if "[ebuild" in line:
- full_name = line.partition('] ')[2].partition(' ')[0]
+ full_name = line.partition("] ")[2].partition(' ')[0]
version = full_name.partition('/')[2].partition('-')[2]
while not version[0].isdigit():
version = version.partition('-')[2]
-
package_name = full_name[:-len(version)-1]
- packages.append((package_name, '-' + version))
+ PACKAGES.append(package(package_name, version))
- if len(packages) == 0:
- return
- print "This is how long these packages would take to emerge"
+def list_emerge_processes():
+ """Look for the ebuild process with ps. If the process is found parse
+ the command for the package. With this package search the LOGFILE for
+ the emerge startup time."""
- all_time = 0
- for pack in packages:
+ f = open_log()
- print('\t' + green_start + pack[0] + pack[1] + color_stop)
+ now = datetime.datetime.today()
- all_time += main_loop(f, pack[0], True)
+ for i in os.popen("ps ax"):
+ if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
+ pack = i.partition('[')[2].partition(']')[0]
- print "\n"
+ version = pack.partition('/')[2].partition('-')[2]
+ while not version[0].isdigit():
+ version = version.partition('-')[2]
- if len(packages) > 1:
- print("Total emerge time of " + green_start + str(len(packages)) +
- color_stop + " packages:"),
- organize_times(all_time)
+ package_name = pack[:-len(version)-1]
+ PACKAGES.append(package(package_name, version))
+ if len(PACKAGES) == 0:
+ print("No current emerge process found.")
-def main_loop(f, package, silent):
- """The main loop which parses the LOGFILE and if needed prints out emerge times."""
+ return 1
- f.seek(0) # Seek to the beginning of the file
- times = []
- # MAIN LOOP
for line in f:
if ((">>>" in line) and ("emerge" in line)):
- if package in line:
- version = line.partition(package)[2].partition(' ')[0]
+ for p in PACKAGES:
+ difference = 0
- if version.strip('-')[0].isdigit():
- full_package = package + version
+ if (p.name + '-' + p.version in line):
- time_string = line.partition(">>>")
- start_time = float(time_string[0].strip().strip(':'))
+ time = float(line.partition(' ')[0].strip(":"))
+ timestamp = datetime.datetime.fromtimestamp(time)
+ difference = (now - timestamp).total_seconds()
- elif ((":::" in line) and ("completed emerge" in line)):
- if package in line:
- if version.strip('-')[0].isdigit():
+ if ((p.emerge_time == "infinity") or
+ (difference < p.emerge_time)):
- time_string = line.partition(":::")
- end_time = float(time_string[0].strip().strip(':'))
+ p.emerge_time = difference
+
+ return 0
- emerge_time = end_time - start_time
+def search_syncs():
+ f = open_log()
- date = get_date(start_time)
+ 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]
- if silent == False:
- print(str(len(times)+1) + ". " +
- green_start + full_package + color_stop +
- " >>> " + date + " >>> "),
+ print("\t" + GREEN(give_date(time)) +
+ " === " + server),
+ a += 1
- organize_times(emerge_time)
+ print("\n" + GREEN(str(a)) + " emerge syncs found. ")
- print("\n" + '-'*90)
+def main(status, user_package=None):
+ try:
+ _main(status, user_package)
+ except IOError:
+ sys.exit()
- times.append((emerge_time, date))
+def _main(status, user_package=None):
+ """Main function. Handle all the different modes of operation."""
- average_time = print_times(package, times, silent)
- return average_time
+ if status == "package":
+ for p in user_package:
+ pack = get_package(p)
+ pack = package(pack)
+ search_log_for_package(pack)
-def main(status):
- """Change between current emerge stage and normal operating stage."""
+ 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.")
- f = open_log()
- if status == 'current':
- list_emerge_processes(f)
+ elif status == "sync":
+ search_syncs()
return
- elif status == 'pretended':
- list_pretended(f)
+
+
+ elif status == "list":
+ search_log_for_all_packages()
return
- else:
- pass
- package = get_package(package_name)
- print('-'*90)
+ elif status == "current":
+ if list_emerge_processes():
+ return
+
+ print("Currently emerging:")
+
+ 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")
- main_loop(f, package, False)
+ total_pretended_time = 0
- f.close()
+ for p in PACKAGES:
+ search_log_for_package(p)
+
+ 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():
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--no-color \t Use colorless output"""
+\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
+ print(usage)
sys.exit(0)
if __name__ == "__main__":
- mode = str()
+ # Set the default mode as "package"
+ mode = "package"
+ input_packages = None
+ simulation = False
+ matplotWorking = False
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 == "-c" or arg == "--current":
- mode = "current"
+ if arg == "-l" or arg == "--list":
+ mode = "list"
+
+ if arg == "-s" or arg == "--sync":
+ mode = "sync"
+
+ if arg == "-q" or arg == "--quiet":
+ QUIET = True
+
+ 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 = ''
+ green_start = ""
+ color_stop = ""
- if len(sys.argv) > 1:
- package_name = sys.argv[1]
- else:
- usage()
+ sys.argv.pop(sys.argv.index(arg))
+ if arg == "--simulate":
+ simulation = True
- main(mode)
- sys.exit(0)
+ if len(sys.argv) > 1:
+ input_packages = sys.argv[1:]
+ else:
+ usage()
+ main(mode, input_packages)