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 print("\n\taverage time: " + time(self.average_time()))
114 print("\n\t no previous emerges")
117 def print_min_max_ave(self):
118 maxi = self.max_time()
119 mini = self.min_time()
120 average = self.average_time()
121 total = self.total_time()
123 print("Max time: \t" + time(maxi) +
124 "\nMin time: \t" + time(mini) +
125 "\nAverage time: \t" + time(average) +
126 "\nIn total spent " + time(total) +
127 " emerging " + green_start + self.name + color_stop)
131 """Converts time in seconds to human readable form"""
132 days = time/(3600*24)
133 hours = (days - int(days))*24
134 minutes = (hours - int(hours))*60
135 seconds = (minutes - int(minutes))*60
139 minutes = int(minutes)
140 seconds = int(round(seconds))
148 pdays = (green_start + str(days) +
149 color_stop + " day ")
151 pdays = (green_start + str(days) +
152 color_stop + " days ")
155 phours = (green_start + str(hours) +
156 color_stop + " hour ")
158 phours = (green_start + str(hours) +
159 color_stop + " hours ")
162 pminutes = (green_start + str(minutes) +
163 color_stop + " minute ")
165 pminutes = (green_start + str(minutes) +
166 color_stop + " minutes ")
168 pseconds = (green_start + str(seconds) +
169 color_stop + " second ")
171 pseconds = (green_start + str(seconds) +
172 color_stop + " seconds ")
174 return (pdays + phours + pminutes + pseconds)
177 def date(emerge_date):
178 """Returns a date string from a standard POSIX time"""
179 date = datetime.datetime.fromtimestamp(emerge_date)
181 date = "{:%d.%m.%Y %H:%M:%S}".format(date)
188 """Attempt to open the LOGFILE."""
191 f = open(LOGFILE, 'r')
192 except IOError as detail:
200 def search_log_for_package(package_class):
201 """Searchs emerge log for given package and adds all found
202 versions with their emerge times to the class"""
207 if ((">>>" in line) and ("emerge" in line)):
208 if package_class.name in line:
210 version = line.partition(package_class.name)[2].partition(' ')[0]
211 digit = version.strip('-')[0].isdigit()
214 time_string = line.partition(">>>")
215 start_time = float(time_string[0].strip().strip(':'))
217 elif ((":::" in line) and ("completed emerge" in line)):
219 if package_class.name in line:
221 time_string = line.partition(":::")
222 stop_time = float(time_string[0].strip().strip(':'))
224 emerge_time = stop_time - start_time
226 package_class.add_version(version, emerge_time, start_time)
230 def get_package(name):
231 """Take the user-input package name and search for it
234 dirlist = os.listdir(PORTDIR)
235 possible_package = []
238 # If the given name is in the format xxx/zzz
239 # assume that xxx is the package group
241 group = name.partition('/')[0]
242 pkg = name.partition('/')[2]
243 directory = PORTDIR + group
246 dirs = os.listdir(directory)
248 possible_package.append(name)
251 # Go through the directory listing searching for anything
252 # that matches the given name
254 directory = PORTDIR + i
255 if os.path.isdir(directory):
256 dirs = os.listdir(directory)
258 possible_package.append(i + '/' + name)
261 if len(possible_package) > 1:
262 print("Multiple packages found for '" + name + "'.")
263 print("Possible packages: ")
264 for value in possible_package:
268 elif len(possible_package) == 1:
269 package = possible_package[0]
274 print("No package '" + name + "' found")
281 def list_pretended():
282 """List all the pretended packages given by emerge -p
283 output. Create a class out of each of those packages and add them
288 for line in sys.stdin:
289 if "[ebuild" in line:
290 full_name = line.partition("] ")[2].partition(' ')[0]
292 version = full_name.partition('/')[2].partition('-')[2]
293 while not version[0].isdigit():
294 version = version.partition('-')[2]
295 package_name = full_name[:-len(version)-1]
297 PACKAGES.append(package(package_name, version))
301 def list_emerge_processes():
302 """Look for the ebuild process with ps. If the process is found parse
303 the command for the package. With this package search the LOGFILE for
304 the emerge startup time."""
308 now = datetime.datetime.today()
310 for i in os.popen("ps ax"):
311 if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
312 pack = i.partition('[')[2].partition(']')[0]
314 version = pack.partition('/')[2].partition('-')[2]
316 while not version[0].isdigit():
317 version = version.partition('-')[2]
319 package_name = pack[:-len(version)-1]
321 PACKAGES.append(package(package_name, version))
324 if len(PACKAGES) == 0:
325 print "No current emerge process found."
330 if ((">>>" in line) and ("emerge" in line)):
332 if (p.name + '-' + p.version in line):
334 time = float(line.partition(' ')[0].strip(":"))
336 timestamp = datetime.datetime.fromtimestamp(time)
337 difference = (now - timestamp).total_seconds()
339 if difference < p.emerge_time:
340 p.emerge_time = difference
344 def main(status, user_package=None):
345 """Main function. Hanlde all the different modes of operation."""
347 if status == "package":
348 user_package = get_package(user_package)
350 pack = package(user_package)
352 search_log_for_package(pack)
353 pack.print_versions()
354 pack.print_min_max_ave()
357 elif status == "current":
358 list_emerge_processes()
360 print "Currently emerging:"
363 search_log_for_package(p)
364 p.print_current_emerge()
367 elif status == "pretended":
370 print "This is how long these packages would take to emerge"
373 search_log_for_package(p)
374 p.print_pretended_times()
380 usage = """Usage: emerge-timer.py [package] [options]
382 Calculate emerge times from emerge log.
385 \t-c, --current \t Show time until currently compiling package finishes
386 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
387 \t-h, --help \t Show this helpscreen
389 \t--no-color \t Use colorless output"""
396 if __name__ == "__main__":
398 # Set the default mode as "package"
403 for arg in sys.argv[1:]:
405 if arg == "-p" or arg == "--pretended":
408 if arg == "-c" or arg == "--current":
411 if arg == "-h" or arg == "--help":
414 if arg == "--no-color":
419 if len(sys.argv) > 1:
420 input_package = sys.argv[1]
424 main(mode, input_package)