#!/usr/bin/python
+
import sys, subprocess, datetime, os
-try:
- f = open('/var/log/emerge.log', 'r')
-except IOError:
- print "Permission denied: '/var/log/emerge.log'"
- sys.exit(1)
-try:
- package_name = sys.argv[1]
-except IndexError:
- f.close()
- sys.exit(1)
+PORTDIR = "/usr/portage/"
+LOGFILE = "/var/log/emerge.log"
+
+
+
+green_start = "\033[32m"
+color_stop = "\033[m"
+
+
+
+
+
+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
+
+ days = int(days)
+ hours = int(hours)
+ minutes = int(minutes)
+ seconds = int(round(seconds))
+
+ 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,
+
+ if minutes > 0:
+ print_minutes = (green_start + str(minutes) + color_stop + " minute")
+ if minutes != 1:
+ print_minutes += "s"
+ print print_minutes,
-emerge_number = 0
-times = []
+ printable_sec = (green_start + str(seconds) + color_stop + " second")
+ if seconds != 1:
+ printable_sec += "s"
+ print printable_sec,
-lista = []
-green_start = "\033[1;32m"
-green_stop = "\033[1;m"
-def get_time(string, part):
- if part == 1:
- string = string.partition(">>>")
- elif part == 2:
- string = line.partition(":::")
- time = float(string[0].strip().strip(":"))
- return time
+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 date_printer(package, time1, time2):
- global emerge_time
+ year = str(date.year)
+ month = str(date.month)
+ day = str(date.day)
+ weekday = date.weekday()
- date = datetime.date.fromtimestamp(time1)
- emerge_time = time2-time1
- date = (str(date.day) + "/" + str(date.month)
- + "/" + str(date.year))
+ 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 '
- print("Started emerging " + green_start + package + green_stop +
- " at " + date)
+ hour = str(date.hour)
+ minute = str(date.minute)
+ second = str(date.second)
- print("merge time: " + green_start + str(int(round(emerge_time/60))) +
- green_stop + " minutes " + green_start + str(int(round(emerge_time%60))) +
- green_stop + " seconds \n")
+ # This is in the format 'Mon 23.05.2011 00:20:14'
+
+ date = weekday + "{:%d.%m.%Y %H:%M:%S}".format(date)
return date
+
+def list_all_packages():
+ """Go through PORTDIR and create a list of all the packages in portage"""
+
+ root = os.listdir(PORTDIR)
+ all_packages = []
+
+ for package_group in root:
+ group_dir = PORTDIR + package_group
+ if (os.path.isdir(group_dir)
+ and (package_group != "licenses")
+ and (package_group != "metadata")):
+
+ name_dir = os.listdir(group_dir)
+
+ for package_name in name_dir:
+ if ".xml" not in package_name:
+
+ all_packages.append((package_group +
+ '/' + package_name))
+
+ return all_packages
+
+
+
+
def get_package(name):
- global package
- dirlist = os.listdir('/usr/portage/')
+ """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)
+
+
+ # Go through the directory listing searching for anything
+ # that matches the given name
for i in dirlist:
- directory = '/usr/portage/' + i
+ directory = PORTDIR + i
if os.path.isdir(directory):
dirs = os.listdir(directory)
if name in dirs:
- package = i + '/' + name
+ possible_package.append(i + '/' + name)
+
+
+ if len(possible_package) > 1:
+ print("Multiple packages found for '" + name + "'.")
+ print("Possible packages: ")
+ for value in possible_package:
+ print("\t" + value)
+
+
+ elif len(possible_package) == 1:
+ package = possible_package[0]
+ return package
+
+
+ else:
+ print("No package '" + name + "' found")
+
+
+ sys.exit(1)
+
+
+
+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."""
-def print_times(times):
times.sort()
times.reverse()
- print(green_start + package + green_stop + " emerged " + green_start +
- str(emerge_number) + green_stop + " time(s)")
- if emerge_number == 1:
- print "Emerge time", int(round(times[0][0]/60)), "min", int(times[0][0]%60),
- print "s", "at", str(times[0][1])
+ # 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
+
+ elif len(times) == 1:
+ print("\t previous emerge time:\t"),
+ organize_times(times[0][0])
+ print("(only one emerge previously)"),
+ return times[0][0]
+
+ else:
+ print("\t average emerge time:\t"),
+ all_times = 0
+ for i in times:
+ all_times += i[0]
+
+ organize_times(all_times/len(times))
+
+ return all_times/len(times)
+
+
+ if len(times) == 1:
+ print(green_start + package + color_stop + " emerged once")
+
+ elif len(times) > 1:
+ print(green_start + package + color_stop + " emerged " + green_start +
+ str(len(times)) + color_stop + " times\n")
+
+ print "Max time:\t",
+ organize_times(times[0][0])
+ print "at", times[0][1]
+
+ print "Min time:\t",
+ organize_times(times[len(times)-1][0])
+ print "at", times[len(times)-1][1]
- else:
- print("Max time " + green_start + str(int(round(times[0][0]/60))) +
- green_stop + " min " + green_start + str(int(times[0][0]%60)) + green_stop +
- " s at " + str(times[0][1]))
- print("Min time " + green_start + str(int(round(times[len(times)-1][0]/60))) +
- green_stop + " min " + green_start + str(int(times[len(times)-1][0]%60)) + green_stop +
- " s at " + str(times[len(times)-1][1]))
-
all_times = 0
for i in times:
all_times += i[0]
- print "Average time", int(round(all_times/len(times)/60)), "min",
- print int(all_times/len(times)%60), "s"
+ print "Average time\t",
+ organize_times(all_times/len(times))
+ print
- total_hours = all_times/(60*60)
- total_minutes = (all_times/(60*60) - int(total_hours))*60
- total_seconds = (total_minutes - int(total_minutes))*60
- print "In total spent", int(round(total_hours)), "h",
- print int(round(total_minutes)), "min", int(round(total_seconds)),
- print "s emerging", package
+ print "In total spent\t",
+ organize_times(all_times)
+ print("emerging " + green_start +
+ package + color_stop)
-get_package(package_name)
-for line in f:
- if package in line:
- if (">>>" in line) and ("emerge" in line):
- st = line.split(' ')
- for i in st:
- if package_name in i:
- full_package = st[st.index(i)]
+def open_log():
+ """Attempt to open the LOGFILE."""
- time = get_time(line, 1)
+ try:
+ f = open(LOGFILE, 'r')
+ except IOError as detail:
+ print detail
+ sys.exit(1)
+ finally:
+ return f
- if (":::" in line) and ("completed emerge" in line):
- emerge_number += 1
- time2 = get_time(line, 2)
- date = date_printer(full_package, time, time2)
+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."""
- times.append((emerge_time, date))
- lista.append([date, int(emerge_time)])
+ now = datetime.datetime.today()
+ packages = []
-if emerge_number == 0:
- print "No package named", package_name, "found"
- sys.exit(1)
+ for i in os.popen("ps ax"):
+ if (("ebuild" in i) and ("/bin/bash" not in i)):
+ pack = i.partition('[')[2].partition(']')[0]
+
+ packages.append([pack, 12*3600])
+
+
+ for line in f:
+ if ((">>>" in line) and ("emerge" in line)):
+ for p in packages:
+ if (p[0] in line):
+
+ time = float(line.partition(' ')[0].strip(":"))
+
+ timestamp = datetime.datetime.fromtimestamp(time)
+ difference = (now - timestamp).total_seconds()
+
+ if difference < p[1]:
+ p[1] = difference
+
+
+ if len(packages) == 0:
+ print "No current emerge process found."
+ return
+
+ print_current_emerges(f, packages)
+
+
+
+
+def print_current_emerges(f, packages):
+ """Print the current packages that are being merged with the
+ current emerge time."""
+
+ all_packages = list_all_packages()
+
+ print("Currently emerging: ")
+
+ for p in packages:
+ print("\t" + green_start + p[0] + color_stop),
+ print("\n\t current emerge time:\t"),
+
+ organize_times(p[1])
+ print
+
+
+ for i in all_packages:
+ if i in p[0]:
+ average_time = main_loop(f, i, True)
+
+ if average_time != 0:
+ print("\n\t " + '-'*45 + "\n\t time to finish: \t"),
+ if (average_time - p[1]) < 0:
+ print(green_start + "Any time now" + color_stop),
+ else:
+ organize_times(average_time - p[1])
+ print "\n"
+
+
+
+def list_pretended(f):
+ """Print the average times of pretended packages"""
+
+ all_packages = list_all_packages()
+
+ packages = []
+ for line in sys.stdin:
+ if "[ebuild" in line:
+ full_name = line.partition('] ')[2].partition(' ')[0]
+
+ for i in all_packages:
+ if i in full_name:
+ packages.append((i, full_name[len(i):]))
+
+ if len(packages) == 0:
+ return
+
+ print "This is how long these packages would take to emerge"
+
+ all_time = 0
+ for pack in packages:
+
+ print('\t' + green_start + pack[0] + pack[1] + color_stop)
+
+ all_time += main_loop(f, pack[0], True)
+
+ print "\n"
+
+
+ if all_time != 0:
+ print("Total emerge time of " + green_start + str(len(packages)) +
+ color_stop + " packages:"),
+ organize_times(all_time)
+
+
+
+
+def main_loop(f, package, silent):
+ """The main loop which parses the LOGFILE and if needed prints out emerge times."""
+
+ 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]
+
+ if version.strip('-')[0].isdigit():
+ full_package = package + version
+
+ time_string = line.partition(">>>")
+ start_time = float(time_string[0].strip().strip(':'))
+
+
+ elif ((":::" in line) and ("completed emerge" in line)):
+ if package in line:
+ if version.strip('-')[0].isdigit():
+
+ time_string = line.partition(":::")
+ end_time = float(time_string[0].strip().strip(':'))
+
+
+ emerge_time = end_time - start_time
+
+ date = get_date(start_time)
+
+
+ if silent == False:
+ print(str(len(times)+1) + ". " +
+ green_start + full_package + color_stop +
+ " >>> " + date + " >>> "),
+
+ organize_times(emerge_time)
+
+ print("\n" + '-'*90)
+
+
+ times.append((emerge_time, date))
+
+
+ average_time = print_times(package, times, silent)
+ return average_time
+
+
+
+def main(status):
+ """Change between current emerge stage and normal operating stage."""
+
+ f = open_log()
+
+ if status == 'current':
+ list_emerge_processes(f)
+ return
+ elif status == 'pretended':
+ list_pretended(f)
+ return
+ else:
+ pass
+
+ package = get_package(package_name)
+
+ print('-'*90)
+
+ main_loop(f, package, False)
+
+ f.close()
+
+
+
+if __name__ == "__main__":
+
+ if len(sys.argv) == 1:
+ main('current')
+ sys.exit(1)
-f.close()
+ elif sys.argv[1] == "-p":
+ main('pretended')
+ sys.exit(1)
-print_times(times)
+ elif ((sys.argv[1] == "-h") or (sys.argv[1] == "--help")):
+ print("Usage: emerge-timer.py [options] [package]\n\nOptions:\n"
+ + green_start + "\t-p" + color_stop +
+ "\tcalculate compile time from piped 'emerge -p' output\n" +
+ green_start + "\t[none]" + color_stop +
+ "\tShow average emerge times for currently compiling packages.")
+ sys.exit(1)
-g = open('times', 'w')
+ if len(sys.argv) > 1:
+ package_name = sys.argv[1]
+ main(0)
-for i in lista:
- line = str(i[0]) + " " + str(i[1]) + "\n"
- g.write(line)
-g.close()