4 import sys, datetime, os
7 PORTDIR = "/usr/portage/"
8 LOGFILE = "/var/log/emerge.log"
11 green_start = "\033[32m"
20 def __init__(self, name, version=0):
22 self.version = version
24 self.emerge_time = 12*3600
27 def add_version(self, version, emerge_time, emerge_date):
28 """Add version to the class version list"""
29 self.versions.append((version, emerge_time, emerge_date))
32 def average_time(self):
33 """Return average time from class version list"""
35 for i in self.versions:
38 average_time = total_time/len(self.versions)
44 """Return total time from class version list"""
46 for i in self.versions:
53 """Return maximum time from class version list"""
56 return self.versions[len(self.versions)-1][1]
60 """Return minimum time from class version list"""
63 return self.versions[0][1]
66 def print_current_emerge(self):
67 """Function used to print all the current emerge stuff"""
69 print("\t" + green_start + self.name + '-' + self.version +
70 color_stop + "\n\t current time: " + time(self.emerge_time) +
71 "\n\t average time: "),
73 if len(self.versions) > 1:
74 print(time(self.average_time())),
78 print("\n\t " + '-'*45),
80 finish_time = self.average_time() - self.emerge_time
82 print("\n\t time to finish: "),
85 print(time(finish_time))
90 def print_versions(self):
91 """This prints the emerge times for different versions in the
92 normal operating mode of the script"""
94 for p in self.versions:
97 green_start + self.name + p[0] + color_stop + " >>> " +
98 time(p[1]) + " >>> " + date(p[2]))
100 print('-'*90 + "\n" + "Package " + green_start +
101 self.name + color_stop + " emerged " +
102 str(len(self.versions)) + " times.")
107 def print_pretended_times(self):
108 """This is used the print all the pretended times"""
109 print("\t" + green_start + self.name + '-' + self.version + color_stop),
111 if len(self.versions) > 1:
112 aver_time = self.average_time()
114 print("\n\taverage time: " + time(aver_time))
119 print("\n\t no previous emerges")
124 def print_min_max_ave(self):
125 maxi = self.max_time()
126 mini = self.min_time()
127 average = self.average_time()
128 total = self.total_time()
130 print("Max time: \t" + time(maxi) +
131 "\nMin time: \t" + time(mini) +
132 "\nAverage time: \t" + time(average) +
133 "\nIn total spent " + time(total) +
134 " emerging " + green_start + self.name + color_stop)
139 """Converts time in seconds to human readable form"""
140 days = time/(3600*24)
141 hours = (days - int(days))*24
142 minutes = (hours - int(hours))*60
143 seconds = (minutes - int(minutes))*60
147 minutes = int(minutes)
148 seconds = int(round(seconds))
156 pdays = (green_start + str(days) +
157 color_stop + " day ")
159 pdays = (green_start + str(days) +
160 color_stop + " days ")
163 phours = (green_start + str(hours) +
164 color_stop + " hour ")
166 phours = (green_start + str(hours) +
167 color_stop + " hours ")
170 pminutes = (green_start + str(minutes) +
171 color_stop + " minute ")
173 pminutes = (green_start + str(minutes) +
174 color_stop + " minutes ")
176 pseconds = (green_start + str(seconds) +
177 color_stop + " second ")
179 pseconds = (green_start + str(seconds) +
180 color_stop + " seconds ")
182 return (pdays + phours + pminutes + pseconds)
186 def date(emerge_date):
187 """Returns a date string from a standard POSIX time"""
188 date = datetime.datetime.fromtimestamp(emerge_date)
190 date = "{:%d.%m.%Y %H:%M:%S}".format(date)
197 """Attempt to open the LOGFILE."""
200 f = open(LOGFILE, 'r')
201 except IOError as detail:
209 def search_log_for_package(package_class):
210 """Searchs emerge log for given package and adds all found
211 versions with their emerge times to the class"""
216 if ((">>>" in line) and ("emerge" in line)):
217 if package_class.name in line:
219 version = line.partition(package_class.name)[2].partition(' ')[0]
220 digit = version.strip('-')[0].isdigit()
223 time_string = line.partition(">>>")
224 start_time = float(time_string[0].strip().strip(':'))
226 elif ((":::" in line) and ("completed emerge" in line)):
228 if package_class.name in line:
230 time_string = line.partition(":::")
231 stop_time = float(time_string[0].strip().strip(':'))
233 emerge_time = stop_time - start_time
235 package_class.add_version(version, emerge_time, start_time)
239 def get_package(name):
240 """Take the user-input package name and search for it
243 dirlist = os.listdir(PORTDIR)
244 possible_package = []
247 # If the given name is in the format xxx/zzz
248 # assume that xxx is the package group
250 group = name.partition('/')[0]
251 pkg = name.partition('/')[2]
252 directory = PORTDIR + group
255 dirs = os.listdir(directory)
257 possible_package.append(name)
260 # Go through the directory listing searching for anything
261 # that matches the given name
263 directory = PORTDIR + i
264 if os.path.isdir(directory):
265 dirs = os.listdir(directory)
267 possible_package.append(i + '/' + name)
270 if len(possible_package) > 1:
271 print("Multiple packages found for '" + name + "'.")
272 print("Possible packages: ")
273 for value in possible_package:
277 elif len(possible_package) == 1:
278 package = possible_package[0]
283 print("No package '" + name + "' found")
290 def list_pretended():
291 """List all the pretended packages given by emerge -p
292 output. Create a class out of each of those packages and add them
297 for line in sys.stdin:
298 if "[ebuild" in line:
299 full_name = line.partition("] ")[2].partition(' ')[0]
301 version = full_name.partition('/')[2].partition('-')[2]
302 while not version[0].isdigit():
303 version = version.partition('-')[2]
304 package_name = full_name[:-len(version)-1]
306 PACKAGES.append(package(package_name, version))
310 def list_emerge_processes():
311 """Look for the ebuild process with ps. If the process is found parse
312 the command for the package. With this package search the LOGFILE for
313 the emerge startup time."""
317 now = datetime.datetime.today()
319 for i in os.popen("ps ax"):
320 if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
321 pack = i.partition('[')[2].partition(']')[0]
323 version = pack.partition('/')[2].partition('-')[2]
325 while not version[0].isdigit():
326 version = version.partition('-')[2]
328 package_name = pack[:-len(version)-1]
330 PACKAGES.append(package(package_name, version))
333 if len(PACKAGES) == 0:
334 print "No current emerge process found."
339 if ((">>>" in line) and ("emerge" in line)):
341 if (p.name + '-' + p.version in line):
343 time = float(line.partition(' ')[0].strip(":"))
345 timestamp = datetime.datetime.fromtimestamp(time)
346 difference = (now - timestamp).total_seconds()
348 if difference < p.emerge_time:
349 p.emerge_time = difference
353 def main(status, user_package=None):
354 """Main function. Hanlde all the different modes of operation."""
356 if status == "package":
357 user_package = get_package(user_package)
359 pack = package(user_package)
361 search_log_for_package(pack)
362 pack.print_versions()
363 pack.print_min_max_ave()
366 elif status == "current":
367 list_emerge_processes()
369 print "Currently emerging:"
372 search_log_for_package(p)
373 p.print_current_emerge()
376 elif status == "pretended":
379 print "This is how long these packages would take to emerge"
381 total_pretended_time = 0
384 search_log_for_package(p)
386 total_pretended_time += p.print_pretended_times()
390 print("Total emerge time of " + green_start + str(len(PACKAGES)) +
391 color_stop + " package(s): "+ time(total_pretended_time))
395 usage = """Usage: emerge-timer.py [package] [options]
397 Calculate emerge times from emerge log.
400 \t-c, --current \t Show time until currently compiling package finishes
401 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
402 \t-h, --help \t Show this helpscreen
404 \t--no-color \t Use colorless output"""
411 if __name__ == "__main__":
413 # Set the default mode as "package"
418 for arg in sys.argv[1:]:
420 if arg == "-p" or arg == "--pretended":
423 if arg == "-c" or arg == "--current":
426 if arg == "-h" or arg == "--help":
429 if arg == "--no-color":
434 if len(sys.argv) > 1:
435 input_package = sys.argv[1]
439 main(mode, input_package)