4 import sys, subprocess, datetime, os
7 PORTDIR = "/usr/portage/"
8 LOGFILE = "/var/log/emerge.log"
12 green_start = "\033[32m"
19 def organize_times(time):
20 """Takes the emerge time in seconds, organizes it into
21 days, hours, minutes or seconds and finally prints that out."""
24 hours = (days - int(days))*24
25 minutes = (hours - int(hours))*60
26 seconds = (minutes - int(minutes))*60
30 minutes = int(minutes)
31 seconds = int(round(seconds))
34 print_days = (green_start + str(days) + color_stop + " day")
40 print_hours = (green_start + str(hours) + color_stop + " hour")
46 print_minutes = (green_start + str(minutes) + color_stop + " minute")
51 printable_sec = (green_start + str(seconds) + color_stop + " second")
58 def get_date(emerge_start):
59 """Take the emerge startup time in seconds and turn it into a
62 date = datetime.datetime.fromtimestamp(emerge_start)
65 month = str(date.month)
67 weekday = date.weekday()
69 if weekday == 0: weekday = 'Mon '
70 if weekday == 1: weekday = 'Tue '
71 if weekday == 2: weekday = 'Wed '
72 if weekday == 3: weekday = 'Thu '
73 if weekday == 4: weekday = 'Fri '
74 if weekday == 5: weekday = 'Sat '
75 if weekday == 6: weekday = 'Sun '
78 minute = str(date.minute)
79 second = str(date.second)
81 # This is in the format 'Mon 23.05.2011 00:20:14'
83 date = weekday + "{:%d.%m.%Y %H:%M:%S}".format(date)
89 def list_all_packages():
90 """Go through PORTDIR and create a list of all the packages in portage"""
92 root = os.listdir(PORTDIR)
95 for package_group in root:
96 group_dir = PORTDIR + package_group
97 if (os.path.isdir(group_dir)
98 and (package_group != "licenses")
99 and (package_group != "metadata")):
101 name_dir = os.listdir(group_dir)
103 for package_name in name_dir:
104 if ".xml" not in package_name:
106 all_packages.append((package_group +
114 def get_package(name):
115 """Take the user-input package name and search for it
118 dirlist = os.listdir(PORTDIR)
119 possible_package = []
122 # If the given name is in the format xxx/zzz
123 # assume that xxx is the package group
125 group = name.partition('/')[0]
126 pkg = name.partition('/')[2]
127 directory = PORTDIR + group
130 dirs = os.listdir(directory)
132 possible_package.append(name)
135 # Go through the directory listing searching for anything
136 # that matches the given name
138 directory = PORTDIR + i
139 if os.path.isdir(directory):
140 dirs = os.listdir(directory)
142 possible_package.append(i + '/' + name)
145 if len(possible_package) > 1:
146 print("Multiple packages found for '" + name + "'.")
147 print("Possible packages: ")
148 for value in possible_package:
152 elif len(possible_package) == 1:
153 package = possible_package[0]
158 print("No package '" + name + "' found")
165 def print_times(package, times, silent):
166 """Print the maximum/minimum/average times of the given emerge package.
167 If we're in the 'current emerge stage' (the 'silent' flag is True)
168 print the appropriate comment for that package."""
175 # This should be True if we're in current emerge stage
178 print("\t no previous emerges found for this package"),
181 elif len(times) == 1:
182 print("\t previous emerge time:\t"),
183 organize_times(times[0][0])
184 print("(only one emerge previously)"),
188 print("\t average emerge time:\t"),
193 organize_times(all_times/len(times))
195 return all_times/len(times)
199 print(green_start + package + color_stop + " emerged once")
202 print(green_start + package + color_stop + " emerged " + green_start +
203 str(len(times)) + color_stop + " times\n")
206 organize_times(times[0][0])
207 print "at", times[0][1]
210 organize_times(times[len(times)-1][0])
211 print "at", times[len(times)-1][1]
217 print "Average time\t",
218 organize_times(all_times/len(times))
221 print "In total spent\t",
222 organize_times(all_times)
223 print("emerging " + green_start +
224 package + color_stop)
229 """Attempt to open the LOGFILE."""
232 f = open(LOGFILE, 'r')
233 except IOError as detail:
241 def list_emerge_processes(f):
242 """Look for the ebuild process with ps. If the process is found parse
243 the command for the package. With this package search the LOGFILE for
244 the emerge startup time."""
246 now = datetime.datetime.today()
249 for i in os.popen("ps ax"):
250 if (("ebuild" in i) and ("/bin/bash" not in i)):
251 pack = i.partition('[')[2].partition(']')[0]
253 packages.append([pack, 12*3600])
257 if ((">>>" in line) and ("emerge" in line)):
261 time = float(line.partition(' ')[0].strip(":"))
263 timestamp = datetime.datetime.fromtimestamp(time)
264 difference = (now - timestamp).total_seconds()
266 if difference < p[1]:
270 if len(packages) == 0:
271 print "No current emerge process found."
274 print_current_emerges(f, packages)
279 def print_current_emerges(f, packages):
280 """Print the current packages that are being merged with the
281 current emerge time."""
283 all_packages = list_all_packages()
285 print("Currently emerging: ")
288 print("\t" + green_start + p[0] + color_stop),
289 print("\n\t current emerge time:\t"),
295 for i in all_packages:
297 average_time = main_loop(f, i, True)
299 if average_time != 0:
300 print("\n\t " + '-'*45 + "\n\t time to finish: \t"),
301 if (average_time - p[1]) < 0:
302 print(green_start + "Any time now" + color_stop),
304 organize_times(average_time - p[1])
309 def list_pretended(f):
310 """Print the average times of pretended packages"""
312 all_packages = list_all_packages()
315 for line in sys.stdin:
316 if "[ebuild" in line:
317 full_name = line.partition('] ')[2].partition(' ')[0]
319 version = full_name.partition('/')[2].partition('-')[2]
320 while not version[0].isdigit():
321 version = version.partition('-')[2]
323 package_name = full_name[:-len(version)-1]
325 packages.append((package_name, '-' + version))
328 if len(packages) == 0:
331 print "This is how long these packages would take to emerge"
334 for pack in packages:
336 print('\t' + green_start + pack[0] + pack[1] + color_stop)
338 all_time += main_loop(f, pack[0], True)
344 print("Total emerge time of " + green_start + str(len(packages)) +
345 color_stop + " packages:"),
346 organize_times(all_time)
351 def main_loop(f, package, silent):
352 """The main loop which parses the LOGFILE and if needed prints out emerge times."""
354 f.seek(0) # Seek to the beginning of the file
359 if ((">>>" in line) and ("emerge" in line)):
361 version = line.partition(package)[2].partition(' ')[0]
363 if version.strip('-')[0].isdigit():
364 full_package = package + version
366 time_string = line.partition(">>>")
367 start_time = float(time_string[0].strip().strip(':'))
370 elif ((":::" in line) and ("completed emerge" in line)):
372 if version.strip('-')[0].isdigit():
374 time_string = line.partition(":::")
375 end_time = float(time_string[0].strip().strip(':'))
378 emerge_time = end_time - start_time
380 date = get_date(start_time)
384 print(str(len(times)+1) + ". " +
385 green_start + full_package + color_stop +
386 " >>> " + date + " >>> "),
388 organize_times(emerge_time)
393 times.append((emerge_time, date))
396 average_time = print_times(package, times, silent)
402 """Change between current emerge stage and normal operating stage."""
406 if status == 'current':
407 list_emerge_processes(f)
409 elif status == 'pretended':
415 package = get_package(package_name)
419 main_loop(f, package, False)
425 if __name__ == "__main__":
427 if len(sys.argv) == 1:
431 elif sys.argv[1] == "-p":
435 elif ((sys.argv[1] == "-h") or (sys.argv[1] == "--help")):
436 print("Usage: emerge-timer.py [options] [package]\n\nOptions:\n"
437 + green_start + "\t-p" + color_stop +
438 "\tcalculate compile time from piped 'emerge -p' output\n" +
439 green_start + "\t[none]" + color_stop +
440 "\tShow average emerge times for currently compiling packages.")
443 if len(sys.argv) > 1:
444 package_name = sys.argv[1]