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"""
99 for p in self.versions:
100 if len(p[0]) > version_length:
101 version_length = len(p[0])
103 for p in self.versions:
105 print('-'*90 + "\n" +
106 green_start + self.name + (p[0]).ljust(version_length) +
107 color_stop + " >>> " + give_time(p[1]) + " >>> " +
110 print('-'*90 + "\n" + "Package " + green_start +
111 self.name + color_stop + " emerged " +
112 str(len(self.versions)) + " times.")
117 def print_pretended_times(self):
118 """This is used the print all the pretended times"""
121 print("\t" + green_start + self.name + '-' + self.version + color_stop),
123 if len(self.versions) > 1:
124 aver_time = self.average_time()
127 print("\n\taverage time: " + give_time(aver_time))
133 print("\n\t no previous emerges")
138 def print_min_max_ave(self):
139 maxi = self.max_time()
140 mini = self.min_time()
141 average = self.average_time()
142 total = self.total_time()
144 print("Max time: \t" + give_time(maxi) +
145 "\nMin time: \t" + give_time(mini) +
146 "\nAverage time: \t" + give_time(average) +
147 "\nIn total spent " + give_time(total) +
148 " emerging " + green_start + self.name + color_stop)
153 """Converts time in seconds to human readable form"""
154 days = time/(3600*24)
155 hours = (days - int(days))*24
156 minutes = (hours - int(hours))*60
157 seconds = (minutes - int(minutes))*60
161 minutes = int(minutes)
162 seconds = int(round(seconds))
170 pdays = (green_start + str(days) +
171 color_stop + " day ")
173 pdays = (green_start + str(days) +
174 color_stop + " days ")
177 phours = (green_start + str(hours) +
178 color_stop + " hour ")
180 phours = (green_start + str(hours) +
181 color_stop + " hours ")
184 pminutes = (green_start + str(minutes) +
185 color_stop + " minute ")
187 pminutes = (green_start + str(minutes) +
188 color_stop + " minutes ")
190 pseconds = (green_start + str(seconds) +
191 color_stop + " second ")
193 pseconds = (green_start + str(seconds) +
194 color_stop + " seconds ")
196 return (pdays + phours + pminutes + pseconds)
200 def give_date(emerge_date):
201 """Returns a date string from a standard POSIX time"""
202 date = datetime.datetime.fromtimestamp(emerge_date)
204 date = "{:%d.%m.%Y %H:%M:%S}".format(date)
211 """Attempt to open the LOGFILE."""
214 f = open(LOGFILE, 'r')
215 except IOError as detail:
223 def search_log_for_package(package_class):
224 """Searchs emerge log for given package and adds all found
225 versions with their emerge times to the class"""
230 if ((">>>" in line) and ("emerge" in line)):
231 if package_class.name in line:
233 version = line.partition(package_class.name)[2].partition(' ')[0]
234 digit = version.strip('-')[0].isdigit()
237 time_string = line.partition(">>>")
238 start_time = float(time_string[0].strip().strip(':'))
240 elif ((":::" in line) and ("completed emerge" in line)):
242 if package_class.name in line:
244 time_string = line.partition(":::")
245 stop_time = float(time_string[0].strip().strip(':'))
247 emerge_time = stop_time - start_time
249 package_class.add_version(version, emerge_time, start_time)
253 def get_package(name):
254 """Take the user-input package name and search for it
257 dirlist = os.listdir(PORTDIR)
258 possible_package = []
261 # If the given name is in the format xxx/zzz
262 # assume that xxx is the package group
264 group = name.partition('/')[0]
265 pkg = name.partition('/')[2]
266 directory = PORTDIR + group
269 dirs = os.listdir(directory)
271 possible_package.append(name)
274 # Go through the directory listing searching for anything
275 # that matches the given name
277 directory = PORTDIR + i
278 if os.path.isdir(directory):
279 dirs = os.listdir(directory)
281 possible_package.append(i + '/' + name)
284 if len(possible_package) > 1:
285 print("Multiple packages found for '" + name + "'.")
286 print("Possible packages: ")
287 for value in possible_package:
291 elif len(possible_package) == 1:
292 package = possible_package[0]
297 print("No package '" + name + "' found")
304 def list_pretended():
305 """List all the pretended packages given by emerge -p
306 output. Create a class out of each of those packages and add them
311 for line in sys.stdin:
312 if "[ebuild" in line:
313 full_name = line.partition("] ")[2].partition(' ')[0]
315 version = full_name.partition('/')[2].partition('-')[2]
316 while not version[0].isdigit():
317 version = version.partition('-')[2]
318 package_name = full_name[:-len(version)-1]
320 PACKAGES.append(package(package_name, version))
324 def list_emerge_processes():
325 """Look for the ebuild process with ps. If the process is found parse
326 the command for the package. With this package search the LOGFILE for
327 the emerge startup time."""
331 now = datetime.datetime.today()
333 for i in os.popen("ps ax"):
334 if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
335 pack = i.partition('[')[2].partition(']')[0]
337 version = pack.partition('/')[2].partition('-')[2]
339 while not version[0].isdigit():
340 version = version.partition('-')[2]
342 package_name = pack[:-len(version)-1]
344 PACKAGES.append(package(package_name, version))
347 if len(PACKAGES) == 0:
348 print "No current emerge process found."
353 if ((">>>" in line) and ("emerge" in line)):
355 if (p.name + '-' + p.version in line):
357 time = float(line.partition(' ')[0].strip(":"))
359 timestamp = datetime.datetime.fromtimestamp(time)
360 difference = (now - timestamp).total_seconds()
362 if difference < p.emerge_time:
363 p.emerge_time = difference
367 def main(status, user_package=None):
368 """Main function. Hanlde all the different modes of operation."""
370 if status == "package":
371 user_package = get_package(user_package)
373 pack = package(user_package)
375 search_log_for_package(pack)
376 pack.print_versions()
377 pack.print_min_max_ave()
380 elif status == "current":
381 list_emerge_processes()
383 print "Currently emerging:"
386 search_log_for_package(p)
387 p.print_current_emerge()
390 elif status == "pretended":
393 print "This is how long these packages would take to emerge"
395 total_pretended_time = 0
398 search_log_for_package(p)
400 total_pretended_time += p.print_pretended_times()
404 print("Total emerge time of " + green_start + str(len(PACKAGES)) +
405 color_stop + " package(s): "+ give_time(total_pretended_time))
409 usage = """Usage: emerge-timer.py [package] [options]
411 Calculate emerge times from emerge log.
414 \t-c, --current \t Show time until currently compiling package finishes
415 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
416 \t-h, --help \t Show this helpscreen
417 \t-q, --quiet \t Be less verbose
418 \t--no-color \t Use colorless output"""
425 if __name__ == "__main__":
427 # Set the default mode as "package"
432 for arg in sys.argv[1:]:
434 if arg == "-p" or arg == "--pretended":
437 if arg == "-c" or arg == "--current":
440 if arg == "-h" or arg == "--help":
443 if arg == "-q" or arg == "--quiet":
446 if arg == "--no-color":
451 if len(sys.argv) > 1:
452 input_package = sys.argv[1]
456 main(mode, input_package)