4 import sys, subprocess, datetime, os
7 PORTDIR = "/usr/portage/"
8 LOGFILE = "/var/log/emerge.log"
14 green_start = "\033[32m"
21 def organize_times(time):
22 """Takes the emerge time in seconds, organizes it into
23 days, hours, minutes or seconds and finally prints that out."""
26 hours = (days - int(days))*24
27 minutes = (hours - int(hours))*60
28 seconds = (minutes - int(minutes))*60
32 minutes = int(minutes)
33 seconds = int(round(seconds))
36 print_days = (green_start + str(days) + color_stop + " day")
42 print_hours = (green_start + str(hours) + color_stop + " hour")
48 print_minutes = (green_start + str(minutes) + color_stop + " minute")
53 printable_sec = (green_start + str(seconds) + color_stop + " second")
60 def get_date(emerge_start):
61 """Take the emerge startup time in seconds and turn it into a
64 date = datetime.datetime.fromtimestamp(emerge_start)
67 month = str(date.month)
69 weekday = date.weekday()
71 if weekday == 0: weekday = 'Mon '
72 if weekday == 1: weekday = 'Tue '
73 if weekday == 2: weekday = 'Wed '
74 if weekday == 3: weekday = 'Thu '
75 if weekday == 4: weekday = 'Fri '
76 if weekday == 5: weekday = 'Sat '
77 if weekday == 6: weekday = 'Sun '
80 minute = str(date.minute)
81 second = str(date.second)
83 # This is in the format 'Mon 23.05.2011 00:20:14'
85 date = weekday + "{:%d.%m.%Y %H:%M:%S}".format(date)
91 def list_all_packages():
92 """Go through PORTDIR and create a list of all the packages in portage"""
94 root = os.listdir(PORTDIR)
97 for package_group in root:
98 group_dir = PORTDIR + package_group
99 if (os.path.isdir(group_dir)
100 and (package_group != "licenses")
101 and (package_group != "metadata")):
103 name_dir = os.listdir(group_dir)
105 for package_name in name_dir:
106 if ".xml" not in package_name:
108 all_packages.append((package_group +
116 def get_package(name):
117 """Take the user-input package name and search for it
120 dirlist = os.listdir(PORTDIR)
121 possible_package = []
124 # If the given name is in the format xxx/zzz
125 # assume that xxx is the package group
127 group = name.partition('/')[0]
128 pkg = name.partition('/')[2]
129 directory = PORTDIR + group
132 dirs = os.listdir(directory)
134 possible_package.append(name)
137 # Go through the directory listing searching for anything
138 # that matches the given name
140 directory = PORTDIR + i
141 if os.path.isdir(directory):
142 dirs = os.listdir(directory)
144 possible_package.append(i + '/' + name)
147 if len(possible_package) > 1:
148 print("Multiple packages found for '" + name + "'.")
149 print("Possible packages: ")
150 for value in possible_package:
154 elif len(possible_package) == 1:
155 package = possible_package[0]
160 print("No package '" + name + "' found")
167 def print_times(package, times, silent):
168 """Print the maximum/minimum/average times of the given emerge package.
169 If we're in the 'current emerge stage' (the 'silent' flag is True)
170 print the appropriate comment for that package."""
177 # This should be True if we're in current emerge stage
180 print("\t no previous emerges found for this package"),
183 elif len(times) == 1:
184 print("\t previous emerge time:\t"),
185 organize_times(times[0][0])
186 print("(only one emerge previously)"),
190 print("\t average emerge time:\t"),
195 organize_times(all_times/len(times))
197 return all_times/len(times)
201 print(green_start + package + color_stop + " emerged once")
204 print(green_start + package + color_stop + " emerged " + green_start +
205 str(len(times)) + color_stop + " times\n")
208 organize_times(times[0][0])
209 print "at", times[0][1]
212 organize_times(times[len(times)-1][0])
213 print "at", times[len(times)-1][1]
219 print "Average time\t",
220 organize_times(all_times/len(times))
223 print "In total spent\t",
224 organize_times(all_times)
225 print("emerging " + green_start +
226 package + color_stop)
231 """Attempt to open the LOGFILE."""
234 f = open(LOGFILE, 'r')
235 except IOError as detail:
243 def list_emerge_processes(f):
244 """Look for the ebuild process with ps. If the process is found parse
245 the command for the package. With this package search the LOGFILE for
246 the emerge startup time."""
248 now = datetime.datetime.today()
251 for i in os.popen("ps ax"):
252 if (("ebuild" in i) and ("/bin/bash" not in i)):
253 pack = i.partition('[')[2].partition(']')[0]
255 packages.append([pack, 12*3600])
259 if ((">>>" in line) and ("emerge" in line)):
263 time = float(line.partition(' ')[0].strip(":"))
265 timestamp = datetime.datetime.fromtimestamp(time)
266 difference = (now - timestamp).total_seconds()
268 if difference < p[1]:
272 if len(packages) == 0:
273 print "No current emerge process found."
276 print_current_emerges(f, packages)
281 def print_current_emerges(f, packages):
282 """Print the current packages that are being merged with the
283 current emerge time."""
285 all_packages = list_all_packages()
287 print("Currently emerging: ")
290 print("\t" + green_start + p[0] + color_stop),
291 print("\n\t current emerge time:\t"),
297 for i in all_packages:
299 average_time = main_loop(f, i, True)
301 if average_time != 0:
302 print("\n\t " + '-'*45 + "\n\t time to finish: \t"),
303 if (average_time - p[1]) < 0:
304 print(green_start + "Any time now" + color_stop),
306 organize_times(average_time - p[1])
311 def list_pretended(f):
312 """Print the average times of pretended packages"""
314 all_packages = list_all_packages()
317 for line in sys.stdin:
318 if "[ebuild" in line:
319 full_name = line.partition('] ')[2].partition(' ')[0]
321 for i in all_packages:
323 packages.append((i, full_name[len(i):]))
325 if len(packages) == 0:
328 print "This is how long these packages would take to emerge"
331 for pack in packages:
333 print('\t' + green_start + pack[0] + pack[1] + color_stop)
335 all_time += main_loop(f, pack[0], True)
341 print("Total emerge time of " + green_start + str(len(packages)) +
342 color_stop + " packages:"),
343 organize_times(all_time)
348 def main_loop(f, package, silent):
349 """The main loop which parses the LOGFILE and if needed prints out emerge times."""
351 f.seek(0) # Seek to the beginning of the file
360 if ((package in string) and (len(string) > len(package)+1)
361 and (string[len(package)+1].isdigit())):
362 full_package = st[st.index(string)]
365 if ((">>>" in line) and ("emerge" in line)):
366 time_string = line.partition(">>>")
367 time = float(time_string[0].strip().strip(":"))
370 if (":::" in line) and ("completed emerge" in line):
371 time_string = line.partition(":::")
372 time2 = float(time_string[0].strip().strip(":"))
375 emerge_time = time2-time
377 date = get_date(time)
381 print(str(len(times)+1) + "."),
382 print(green_start + full_package + color_stop + " >>> "
385 organize_times(emerge_time)
389 times.append((emerge_time, date))
393 average_time = print_times(package, times, silent)
399 """Change between current emerge stage and normal operating stage."""
403 if status == 'current':
404 list_emerge_processes(f)
406 elif status == 'pretended':
412 package = get_package(package_name)
416 main_loop(f, package, False)
419 print("Package '" + package + "' has never been emerged")
426 if __name__ == "__main__":
428 if len(sys.argv) == 1:
432 elif sys.argv[1] == "-p":
436 elif ((sys.argv[1] == "-h") or (sys.argv[1] == "--help")):
437 print("Usage: emerge-timer.py [options] [package]\n\nOptions:\n"
438 + green_start + "\t-p" + color_stop +
439 "\tcalculate compile time from piped 'emerge -p' output\n" +
440 green_start + "\t[none]" + color_stop +
441 "\tShow average emerge times for currently compiling packages.")
444 if len(sys.argv) > 1:
445 package_name = sys.argv[1]