]> git.itanic.dy.fi Git - emerge-timer/blobdiff - emerge-timer.py
Cleanup the main_loop code
[emerge-timer] / emerge-timer.py
index dc9f4ad27936705c4e3c57c04851b93f05009933..faf4e773a34d70096dbf1d69c8c09d9524c0a9aa 100755 (executable)
 #!/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()