#!/usr/bin/python import sys, subprocess, datetime, os 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, printable_sec = (green_start + str(seconds) + color_stop + " second") if seconds != 1: printable_sec += "s" print printable_sec, 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) year = str(date.year) month = str(date.month) day = str(date.day) weekday = date.weekday() 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 ' hour = str(date.hour) minute = str(date.minute) second = str(date.second) # 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): """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 = PORTDIR + i if os.path.isdir(directory): dirs = os.listdir(directory) if name in dirs: 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.""" times.sort() times.reverse() # 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] all_times = 0 for i in times: all_times += i[0] print "Average time\t", organize_times(all_times/len(times)) print print "In total spent\t", organize_times(all_times) print("emerging " + green_start + package + color_stop) def open_log(): """Attempt to open the LOGFILE.""" try: f = open(LOGFILE, 'r') except IOError as detail: print detail sys.exit(1) finally: 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.""" now = datetime.datetime.today() packages = [] 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""" packages = [] for line in sys.stdin: if "[ebuild" in line: 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)) 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 len(packages) > 1: 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) elif sys.argv[1] == "-p": main('pretended') sys.exit(1) 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) if len(sys.argv) > 1: package_name = sys.argv[1] main(0)