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))
91 def print_versions(self):
92 """This prints the emerge times for different versions in the
93 normal operating mode of the script"""
97 for p in self.versions:
100 green_start + self.name + p[0] + color_stop +
101 " >>> " + give_time(p[1]) + " >>> " + give_date(p[2]))
103 print('-'*90 + "\n" + "Package " + green_start +
104 self.name + color_stop + " emerged " +
105 str(len(self.versions)) + " times.")
110 def print_pretended_times(self):
111 """This is used the print all the pretended times"""
114 print("\t" + green_start + self.name + '-' + self.version + color_stop),
116 if len(self.versions) > 1:
117 aver_time = self.average_time()
120 print("\n\taverage time: " + give_time(aver_time))
126 print("\n\t no previous emerges")
131 def print_min_max_ave(self):
132 maxi = self.max_time()
133 mini = self.min_time()
134 average = self.average_time()
135 total = self.total_time()
137 print("Max time: \t" + give_time(maxi) +
138 "\nMin time: \t" + give_time(mini) +
139 "\nAverage time: \t" + give_time(average) +
140 "\nIn total spent " + give_time(total) +
141 " emerging " + green_start + self.name + color_stop)
146 """Converts time in seconds to human readable form"""
147 days = time/(3600*24)
148 hours = (days - int(days))*24
149 minutes = (hours - int(hours))*60
150 seconds = (minutes - int(minutes))*60
154 minutes = int(minutes)
155 seconds = int(round(seconds))
163 pdays = (green_start + str(days) +
164 color_stop + " day ")
166 pdays = (green_start + str(days) +
167 color_stop + " days ")
170 phours = (green_start + str(hours) +
171 color_stop + " hour ")
173 phours = (green_start + str(hours) +
174 color_stop + " hours ")
177 pminutes = (green_start + str(minutes) +
178 color_stop + " minute ")
180 pminutes = (green_start + str(minutes) +
181 color_stop + " minutes ")
183 pseconds = (green_start + str(seconds) +
184 color_stop + " second ")
186 pseconds = (green_start + str(seconds) +
187 color_stop + " seconds ")
189 return (pdays + phours + pminutes + pseconds)
193 def give_date(emerge_date):
194 """Returns a date string from a standard POSIX time"""
195 date = datetime.datetime.fromtimestamp(emerge_date)
197 date = "{:%d.%m.%Y %H:%M:%S}".format(date)
204 """Attempt to open the LOGFILE."""
207 f = open(LOGFILE, 'r')
208 except IOError as detail:
216 def search_log_for_package(package_class):
217 """Searchs emerge log for given package and adds all found
218 versions with their emerge times to the class"""
223 if ((">>>" in line) and ("emerge" in line)):
224 if package_class.name in line:
226 version = line.partition(package_class.name)[2].partition(' ')[0]
227 digit = version.strip('-')[0].isdigit()
230 time_string = line.partition(">>>")
231 start_time = float(time_string[0].strip().strip(':'))
233 elif ((":::" in line) and ("completed emerge" in line)):
235 if package_class.name in line:
237 time_string = line.partition(":::")
238 stop_time = float(time_string[0].strip().strip(':'))
240 emerge_time = stop_time - start_time
242 package_class.add_version(version, emerge_time, start_time)
246 def get_package(name):
247 """Take the user-input package name and search for it
250 dirlist = os.listdir(PORTDIR)
251 possible_package = []
254 # If the given name is in the format xxx/zzz
255 # assume that xxx is the package group
257 group = name.partition('/')[0]
258 pkg = name.partition('/')[2]
259 directory = PORTDIR + group
262 dirs = os.listdir(directory)
264 possible_package.append(name)
267 # Go through the directory listing searching for anything
268 # that matches the given name
270 directory = PORTDIR + i
271 if os.path.isdir(directory):
272 dirs = os.listdir(directory)
274 possible_package.append(i + '/' + name)
277 if len(possible_package) > 1:
278 print("Multiple packages found for '" + name + "'.")
279 print("Possible packages: ")
280 for value in possible_package:
284 elif len(possible_package) == 1:
285 package = possible_package[0]
290 print("No package '" + name + "' found")
297 def list_pretended():
298 """List all the pretended packages given by emerge -p
299 output. Create a class out of each of those packages and add them
304 for line in sys.stdin:
305 if "[ebuild" in line:
306 full_name = line.partition("] ")[2].partition(' ')[0]
308 version = full_name.partition('/')[2].partition('-')[2]
309 while not version[0].isdigit():
310 version = version.partition('-')[2]
311 package_name = full_name[:-len(version)-1]
313 PACKAGES.append(package(package_name, version))
317 def list_emerge_processes():
318 """Look for the ebuild process with ps. If the process is found parse
319 the command for the package. With this package search the LOGFILE for
320 the emerge startup time."""
324 now = datetime.datetime.today()
326 for i in os.popen("ps ax"):
327 if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
328 pack = i.partition('[')[2].partition(']')[0]
330 version = pack.partition('/')[2].partition('-')[2]
332 while not version[0].isdigit():
333 version = version.partition('-')[2]
335 package_name = pack[:-len(version)-1]
337 PACKAGES.append(package(package_name, version))
340 if len(PACKAGES) == 0:
341 print "No current emerge process found."
346 if ((">>>" in line) and ("emerge" in line)):
348 if (p.name + '-' + p.version in line):
350 time = float(line.partition(' ')[0].strip(":"))
352 timestamp = datetime.datetime.fromtimestamp(time)
353 difference = (now - timestamp).total_seconds()
355 if difference < p.emerge_time:
356 p.emerge_time = difference
360 def main(status, user_package=None):
361 """Main function. Hanlde all the different modes of operation."""
363 if status == "package":
364 user_package = get_package(user_package)
366 pack = package(user_package)
368 search_log_for_package(pack)
369 pack.print_versions()
370 pack.print_min_max_ave()
373 elif status == "current":
374 list_emerge_processes()
376 print "Currently emerging:"
379 search_log_for_package(p)
380 p.print_current_emerge()
383 elif status == "pretended":
386 print "This is how long these packages would take to emerge"
388 total_pretended_time = 0
391 search_log_for_package(p)
393 total_pretended_time += p.print_pretended_times()
397 print("Total emerge time of " + green_start + str(len(PACKAGES)) +
398 color_stop + " package(s): "+ give_time(total_pretended_time))
402 usage = """Usage: emerge-timer.py [package] [options]
404 Calculate emerge times from emerge log.
407 \t-c, --current \t Show time until currently compiling package finishes
408 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
409 \t-h, --help \t Show this helpscreen
410 \t-q, --quiet \t Be less verbose
411 \t--no-color \t Use colorless output"""
418 if __name__ == "__main__":
420 # Set the default mode as "package"
425 for arg in sys.argv[1:]:
427 if arg == "-p" or arg == "--pretended":
430 if arg == "-c" or arg == "--current":
433 if arg == "-h" or arg == "--help":
436 if arg == "-q" or arg == "--quiet":
439 if arg == "--no-color":
444 if len(sys.argv) > 1:
445 input_package = sys.argv[1]
449 main(mode, input_package)