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"""
101 for p in self.versions:
102 if len(p[0]) > version_length:
103 version_length = len(p[0])
105 if len(give_time(p[1])) > time_length:
106 time_length = len(give_time(p[1]))
108 for p in self.versions:
110 print('-'*90 + "\n" +
111 green_start + self.name + (p[0]).ljust(version_length) +
112 color_stop + " >>> " + (give_time(p[1])).ljust(time_length)
113 + " >>> " + give_date(p[2]))
115 print('-'*90 + "\n" + "Package " + green_start +
116 self.name + color_stop + " emerged " +
117 str(len(self.versions)) + " times.")
122 def print_pretended_times(self):
123 """This is used the print all the pretended times"""
126 print("\t" + green_start + self.name + '-' + self.version + color_stop),
128 if len(self.versions) > 1:
129 aver_time = self.average_time()
132 print("\n\taverage time: " + give_time(aver_time))
138 print("\n\t no previous emerges")
143 def print_min_max_ave(self):
144 maxi = self.max_time()
145 mini = self.min_time()
146 average = self.average_time()
147 total = self.total_time()
149 print("Max time: \t" + give_time(maxi) +
150 "\nMin time: \t" + give_time(mini) +
151 "\nAverage time: \t" + give_time(average) +
152 "\nIn total spent " + give_time(total) +
153 " emerging " + green_start + self.name + color_stop)
157 def give_time(time, nocolor=False):
158 """Converts time in seconds to human readable form"""
159 global green_start, color_stop
165 days = time/(3600*24)
166 hours = (days - int(days))*24
167 minutes = (hours - int(hours))*60
168 seconds = (minutes - int(minutes))*60
172 minutes = int(minutes)
173 seconds = int(round(seconds))
181 pdays = (green_start + str(days) +
182 color_stop + " day ")
184 pdays = (green_start + str(days) +
185 color_stop + " days ")
188 phours = (green_start + str(hours) +
189 color_stop + " hour ")
191 phours = (green_start + str(hours) +
192 color_stop + " hours ")
195 pminutes = (green_start + str(minutes) +
196 color_stop + " minute ")
198 pminutes = (green_start + str(minutes) +
199 color_stop + " minutes ")
201 pseconds = (green_start + str(seconds) +
202 color_stop + " second ")
204 pseconds = (green_start + str(seconds) +
205 color_stop + " seconds ")
207 green_start = "\033[32m"
208 color_stop = "\033[m"
210 return (pdays + phours + pminutes + pseconds)
214 def give_date(emerge_date):
215 """Returns a date string from a standard POSIX time"""
216 date = datetime.datetime.fromtimestamp(emerge_date)
218 date = "{:%d.%m.%Y %H:%M:%S}".format(date)
225 """Attempt to open the LOGFILE."""
228 f = open(LOGFILE, 'r')
229 except IOError as detail:
237 def search_log_for_package(package_class):
238 """Searchs emerge log for given package and adds all found
239 versions with their emerge times to the class"""
244 if ((">>>" in line) and ("emerge" in line)):
245 if package_class.name in line:
247 version = line.partition(package_class.name)[2].partition(' ')[0]
248 digit = version.strip('-')[0].isdigit()
251 time_string = line.partition(">>>")
252 start_time = float(time_string[0].strip().strip(':'))
254 elif ((":::" in line) and ("completed emerge" in line)):
256 if package_class.name in line:
258 time_string = line.partition(":::")
259 stop_time = float(time_string[0].strip().strip(':'))
261 emerge_time = stop_time - start_time
263 package_class.add_version(version, emerge_time, start_time)
267 def get_package(name):
268 """Take the user-input package name and search for it
271 dirlist = os.listdir(PORTDIR)
272 possible_package = []
275 # If the given name is in the format xxx/zzz
276 # assume that xxx is the package group
278 group = name.partition('/')[0]
279 pkg = name.partition('/')[2]
280 directory = PORTDIR + group
283 dirs = os.listdir(directory)
285 possible_package.append(name)
288 # Go through the directory listing searching for anything
289 # that matches the given name
291 directory = PORTDIR + i
292 if os.path.isdir(directory):
293 dirs = os.listdir(directory)
295 possible_package.append(i + '/' + name)
298 if len(possible_package) > 1:
299 print("Multiple packages found for '" + name + "'.")
300 print("Possible packages: ")
301 for value in possible_package:
305 elif len(possible_package) == 1:
306 package = possible_package[0]
311 print("No package '" + name + "' found")
318 def list_pretended():
319 """List all the pretended packages given by emerge -p
320 output. Create a class out of each of those packages and add them
325 for line in sys.stdin:
326 if "[ebuild" in line:
327 full_name = line.partition("] ")[2].partition(' ')[0]
329 version = full_name.partition('/')[2].partition('-')[2]
330 while not version[0].isdigit():
331 version = version.partition('-')[2]
332 package_name = full_name[:-len(version)-1]
334 PACKAGES.append(package(package_name, version))
338 def list_emerge_processes():
339 """Look for the ebuild process with ps. If the process is found parse
340 the command for the package. With this package search the LOGFILE for
341 the emerge startup time."""
345 now = datetime.datetime.today()
347 for i in os.popen("ps ax"):
348 if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
349 pack = i.partition('[')[2].partition(']')[0]
351 version = pack.partition('/')[2].partition('-')[2]
353 while not version[0].isdigit():
354 version = version.partition('-')[2]
356 package_name = pack[:-len(version)-1]
358 PACKAGES.append(package(package_name, version))
361 if len(PACKAGES) == 0:
362 print "No current emerge process found."
367 if ((">>>" in line) and ("emerge" in line)):
369 if (p.name + '-' + p.version in line):
371 time = float(line.partition(' ')[0].strip(":"))
373 timestamp = datetime.datetime.fromtimestamp(time)
374 difference = (now - timestamp).total_seconds()
376 if difference < p.emerge_time:
377 p.emerge_time = difference
381 def main(status, user_package=None):
382 """Main function. Hanlde all the different modes of operation."""
384 if status == "package":
385 user_package = get_package(user_package)
387 pack = package(user_package)
389 search_log_for_package(pack)
390 pack.print_versions()
391 pack.print_min_max_ave()
394 elif status == "current":
395 list_emerge_processes()
397 print "Currently emerging:"
400 search_log_for_package(p)
401 p.print_current_emerge()
404 elif status == "pretended":
407 print "This is how long these packages would take to emerge"
409 total_pretended_time = 0
412 search_log_for_package(p)
414 total_pretended_time += p.print_pretended_times()
418 print("Total emerge time of " + green_start + str(len(PACKAGES)) +
419 color_stop + " package(s): "+ give_time(total_pretended_time))
423 usage = """Usage: emerge-timer.py [package] [options]
425 Calculate emerge times from emerge log.
428 \t-c, --current \t Show time until currently compiling package finishes
429 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
430 \t-h, --help \t Show this helpscreen
431 \t-q, --quiet \t Be less verbose
432 \t--no-color \t Use colorless output"""
439 if __name__ == "__main__":
441 # Set the default mode as "package"
446 for arg in sys.argv[1:]:
448 if arg == "-p" or arg == "--pretended":
451 if arg == "-c" or arg == "--current":
454 if arg == "-h" or arg == "--help":
457 if arg == "-q" or arg == "--quiet":
460 if arg == "--no-color":
465 if len(sys.argv) > 1:
466 input_package = sys.argv[1]
470 main(mode, input_package)