4 import sys, datetime, os
7 PORTDIR = "/usr/portage/"
8 LOGFILE = "/var/log/emerge.log"
11 green_start = "\033[32m"
21 def __init__(self, name, version=0):
23 self.version = version
25 self.emerge_time = 12*3600
28 def add_version(self, version, emerge_time, emerge_date):
29 """Add version to the class version list"""
30 self.versions.append((version, emerge_time, emerge_date))
33 def average_time(self):
34 """Return average time from class version list"""
36 for i in self.versions:
39 average_time = total_time/len(self.versions)
45 """Return total time from class version list"""
47 for i in self.versions:
54 """Return maximum time from class version list"""
57 return self.versions[len(self.versions)-1][1]
61 """Return minimum time from class version list"""
64 return self.versions[0][1]
67 def print_current_emerge(self):
68 """Function used to print all the current emerge stuff"""
70 print("\t" + green_start + self.name + '-' + self.version +
71 color_stop + "\n\t current time: " + give_time(self.emerge_time) +
72 "\n\t average time: "),
74 if len(self.versions) > 1:
75 print(give_time(self.average_time())),
79 print("\n\t " + '-'*45),
81 finish_time = self.average_time() - self.emerge_time
83 print("\n\t time to finish: "),
86 print(give_time(finish_time))
92 def print_versions(self):
93 """This prints the emerge times for different versions in the
94 normal operating mode of the script"""
98 for p in self.versions:
100 print('-'*90 + "\n" +
101 green_start + self.name + p[0] + color_stop +
102 " >>> " + give_time(p[1]) + " >>> " + give_date(p[2]))
104 print('-'*90 + "\n" + "Package " + green_start +
105 self.name + color_stop + " emerged " +
106 str(len(self.versions)) + " times.")
111 def print_pretended_times(self):
112 """This is used the print all the pretended times"""
115 print("\t" + green_start + self.name + '-' + self.version + color_stop),
117 if len(self.versions) > 1:
118 aver_time = self.average_time()
121 print("\n\taverage time: " + give_time(aver_time))
127 print("\n\t no previous emerges")
132 def print_min_max_ave(self):
133 maxi = self.max_time()
134 mini = self.min_time()
135 average = self.average_time()
136 total = self.total_time()
138 print("Max time: \t" + give_time(maxi) +
139 "\nMin time: \t" + give_time(mini) +
140 "\nAverage time: \t" + give_time(average) +
141 "\nIn total spent " + give_time(total) +
142 " emerging " + green_start + self.name + color_stop)
147 """Converts time in seconds to human readable form"""
148 days = time/(3600*24)
149 hours = (days - int(days))*24
150 minutes = (hours - int(hours))*60
151 seconds = (minutes - int(minutes))*60
155 minutes = int(minutes)
156 seconds = int(round(seconds))
164 pdays = (green_start + str(days) +
165 color_stop + " day ")
167 pdays = (green_start + str(days) +
168 color_stop + " days ")
171 phours = (green_start + str(hours) +
172 color_stop + " hour ")
174 phours = (green_start + str(hours) +
175 color_stop + " hours ")
178 pminutes = (green_start + str(minutes) +
179 color_stop + " minute ")
181 pminutes = (green_start + str(minutes) +
182 color_stop + " minutes ")
184 pseconds = (green_start + str(seconds) +
185 color_stop + " second ")
187 pseconds = (green_start + str(seconds) +
188 color_stop + " seconds ")
190 return (pdays + phours + pminutes + pseconds)
194 def give_date(emerge_date):
195 """Returns a date string from a standard POSIX time"""
196 date = datetime.datetime.fromtimestamp(emerge_date)
198 date = "{:%d.%m.%Y %H:%M:%S}".format(date)
205 """Attempt to open the LOGFILE."""
208 f = open(LOGFILE, 'r')
209 except IOError as detail:
217 def search_log_for_package(package_class):
218 """Searchs emerge log for given package and adds all found
219 versions with their emerge times to the class"""
224 if ((">>>" in line) and ("emerge" in line)):
225 if package_class.name in line:
227 version = line.partition(package_class.name)[2].partition(' ')[0]
228 digit = version.strip('-')[0].isdigit()
231 time_string = line.partition(">>>")
232 start_time = float(time_string[0].strip().strip(':'))
234 elif ((":::" in line) and ("completed emerge" in line)):
236 if package_class.name in line:
238 time_string = line.partition(":::")
239 stop_time = float(time_string[0].strip().strip(':'))
241 emerge_time = stop_time - start_time
243 package_class.add_version(version, emerge_time, start_time)
247 def get_package(name):
248 """Take the user-input package name and search for it
251 dirlist = os.listdir(PORTDIR)
252 possible_package = []
255 # If the given name is in the format xxx/zzz
256 # assume that xxx is the package group
258 group = name.partition('/')[0]
259 pkg = name.partition('/')[2]
260 directory = PORTDIR + group
263 dirs = os.listdir(directory)
265 possible_package.append(name)
268 # Go through the directory listing searching for anything
269 # that matches the given name
271 directory = PORTDIR + i
272 if os.path.isdir(directory):
273 dirs = os.listdir(directory)
275 possible_package.append(i + '/' + name)
278 if len(possible_package) > 1:
279 print("Multiple packages found for '" + name + "'.")
280 print("Possible packages: ")
281 for value in possible_package:
285 elif len(possible_package) == 1:
286 package = possible_package[0]
291 print("No package '" + name + "' found")
298 def list_pretended():
299 """List all the pretended packages given by emerge -p
300 output. Create a class out of each of those packages and add them
305 for line in sys.stdin:
306 if "[ebuild" in line:
307 full_name = line.partition("] ")[2].partition(' ')[0]
309 version = full_name.partition('/')[2].partition('-')[2]
310 while not version[0].isdigit():
311 version = version.partition('-')[2]
312 package_name = full_name[:-len(version)-1]
314 PACKAGES.append(package(package_name, version))
318 def list_emerge_processes():
319 """Look for the ebuild process with ps. If the process is found parse
320 the command for the package. With this package search the LOGFILE for
321 the emerge startup time."""
325 now = datetime.datetime.today()
327 for i in os.popen("ps ax"):
328 if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
329 pack = i.partition('[')[2].partition(']')[0]
331 version = pack.partition('/')[2].partition('-')[2]
333 while not version[0].isdigit():
334 version = version.partition('-')[2]
336 package_name = pack[:-len(version)-1]
338 PACKAGES.append(package(package_name, version))
341 if len(PACKAGES) == 0:
342 print "No current emerge process found."
347 if ((">>>" in line) and ("emerge" in line)):
349 if (p.name + '-' + p.version in line):
351 time = float(line.partition(' ')[0].strip(":"))
353 timestamp = datetime.datetime.fromtimestamp(time)
354 difference = (now - timestamp).total_seconds()
356 if difference < p.emerge_time:
357 p.emerge_time = difference
361 def main(status, user_package=None):
362 """Main function. Hanlde all the different modes of operation."""
364 if status == "package":
365 user_package = get_package(user_package)
367 pack = package(user_package)
369 search_log_for_package(pack)
370 pack.print_versions()
371 pack.print_min_max_ave()
374 elif status == "current":
375 list_emerge_processes()
377 print "Currently emerging:"
380 search_log_for_package(p)
381 p.print_current_emerge()
384 elif status == "pretended":
387 print "This is how long these packages would take to emerge"
389 total_pretended_time = 0
392 search_log_for_package(p)
394 total_pretended_time += p.print_pretended_times()
398 print("Total emerge time of " + green_start + str(len(PACKAGES)) +
399 color_stop + " package(s): "+ give_time(total_pretended_time))
403 usage = """Usage: emerge-timer.py [package] [options]
405 Calculate emerge times from emerge log.
408 \t-c, --current \t Show time until currently compiling package finishes
409 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
410 \t-h, --help \t Show this helpscreen
411 \t-q, --quiet \t Be less verbose
412 \t--no-color \t Use colorless output"""
419 if __name__ == "__main__":
421 # Set the default mode as "package"
426 for arg in sys.argv[1:]:
428 if arg == "-p" or arg == "--pretended":
431 if arg == "-c" or arg == "--current":
434 if arg == "-h" or arg == "--help":
437 if arg == "-q" or arg == "--quiet":
440 if arg == "--no-color":
445 if len(sys.argv) > 1:
446 input_package = sys.argv[1]
450 main(mode, input_package)