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
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))
74 if len(self.versions) == 1:
75 print("\t last time: "),
76 print(give_time(self.average_time())),
78 elif len(self.versions) > 1:
79 print("\t average time:"),
80 print(give_time(self.average_time())),
85 print("\n\t " + '-'*45),
87 finish_time = self.average_time() - self.emerge_time
89 print("\n\t time to finish:"),
92 print(give_time(finish_time))
94 print(green_start + "any time now" + color_stop)
98 def print_versions(self):
99 """This prints the emerge times for different versions in the
100 'package' operating mode of the script"""
107 for p in self.versions:
108 if len(p[0]) > version_length:
109 version_length = len(p[0])
111 if len(give_time(p[1], True)) > time_length:
112 time_length = len(give_time(p[1], True))
114 for p in self.versions:
116 pad = time_length - len(give_time(p[1], True))
118 print('-'*90 + "\n" +
119 green_start + self.name + (p[0]).ljust(version_length) +
120 color_stop + " >>> " + (give_time(p[1])) + " "*pad +
121 " >>> " + give_date(p[2]))
123 print('-'*90 + "\n" + "Package " + green_start +
124 self.name + color_stop + " emerged " +
125 str(len(self.versions)) + " times.")
130 def print_pretended_times(self):
131 """This is used the print all the pretended times"""
134 print("\t" + green_start + self.name + '-' + self.version + color_stop),
136 if len(self.versions) > 1:
137 aver_time = self.average_time()
140 print("\n\taverage time: " + give_time(aver_time))
146 print("\n\t no previous emerges")
151 def print_min_max_ave(self):
152 maxi = self.max_time()
153 mini = self.min_time()
154 average = self.average_time()
155 total = self.total_time()
157 print("Max time: \t" + give_time(maxi) +
158 "\nMin time: \t" + give_time(mini) +
159 "\nAverage time: \t" + give_time(average) +
160 "\nIn total spent " + give_time(total) +
161 " emerging " + green_start + self.name + color_stop)
165 def give_time(time, nocolor=False):
166 """Converts time in seconds to human readable form"""
167 global green_start, color_stop
169 if green_start == "":
176 days = time/(3600*24)
177 hours = (days - int(days))*24
178 minutes = (hours - int(hours))*60
179 seconds = (minutes - int(minutes))*60
183 minutes = int(minutes)
184 seconds = int(round(seconds))
192 pdays = (green_start + str(days) +
193 color_stop + " day ")
195 pdays = (green_start + str(days) +
196 color_stop + " days ")
199 phours = (green_start + str(hours) +
200 color_stop + " hour ")
202 phours = (green_start + str(hours) +
203 color_stop + " hours ")
206 pminutes = (green_start + str(minutes) +
207 color_stop + " minute ")
209 pminutes = (green_start + str(minutes) +
210 color_stop + " minutes ")
212 pseconds = (green_start + str(seconds) +
213 color_stop + " second ")
215 pseconds = (green_start + str(seconds) +
216 color_stop + " seconds ")
219 green_start = "\033[32m"
220 color_stop = "\033[m"
222 return (pdays + phours + pminutes + pseconds)
226 def give_date(emerge_date):
227 """Returns a date string from a standard POSIX time"""
228 date = datetime.datetime.fromtimestamp(emerge_date)
230 date = "{:%d.%m.%Y %H:%M:%S}".format(date)
237 """Attempt to open the LOGFILE."""
240 f = open(LOGFILE, 'r')
241 except IOError as detail:
249 def search_log_for_package(package_class):
250 """Searchs emerge log for given package and adds all found
251 versions with their emerge times to the class"""
256 if ((">>>" in line) and ("emerge" in line)):
257 if package_class.name in line:
259 version = line.partition(package_class.name)[2].partition(' ')[0]
260 digit = version.strip('-')[0].isdigit()
263 time_string = line.partition(">>>")
264 start_time = float(time_string[0].strip().strip(':'))
266 elif ((":::" in line) and ("completed emerge" in line)):
268 if package_class.name in line:
270 time_string = line.partition(":::")
271 stop_time = float(time_string[0].strip().strip(':'))
273 emerge_time = stop_time - start_time
275 package_class.add_version(version, emerge_time, start_time)
279 def get_package(name):
280 """Take the user-input package name and search for it
283 dirlist = os.listdir(PORTDIR)
284 possible_package = []
287 # If the given name is in the format xxx/zzz
288 # assume that xxx is the package group
290 group = name.partition('/')[0]
291 pkg = name.partition('/')[2]
292 directory = PORTDIR + group
295 dirs = os.listdir(directory)
297 possible_package.append(name)
300 # Go through the directory listing searching for anything
301 # that matches the given name
303 directory = PORTDIR + i
304 if os.path.isdir(directory):
305 dirs = os.listdir(directory)
307 possible_package.append(i + '/' + name)
310 if len(possible_package) > 1:
311 print("Multiple packages found for '" + name + "'.")
312 print("Possible packages: ")
313 for value in possible_package:
317 elif len(possible_package) == 1:
318 package = possible_package[0]
323 print("No package '" + name + "' found")
330 def list_pretended():
331 """List all the pretended packages given by emerge -p
332 output. Create a class out of each of those packages and add them
337 for line in sys.stdin:
338 if "[ebuild" in line:
339 full_name = line.partition("] ")[2].partition(' ')[0]
341 version = full_name.partition('/')[2].partition('-')[2]
342 while not version[0].isdigit():
343 version = version.partition('-')[2]
344 package_name = full_name[:-len(version)-1]
346 PACKAGES.append(package(package_name, version))
350 def list_emerge_processes():
351 """Look for the ebuild process with ps. If the process is found parse
352 the command for the package. With this package search the LOGFILE for
353 the emerge startup time."""
357 now = datetime.datetime.today()
359 for i in os.popen("ps ax"):
360 if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
361 pack = i.partition('[')[2].partition(']')[0]
363 version = pack.partition('/')[2].partition('-')[2]
365 while not version[0].isdigit():
366 version = version.partition('-')[2]
368 package_name = pack[:-len(version)-1]
370 PACKAGES.append(package(package_name, version))
373 if len(PACKAGES) == 0:
374 print "No current emerge process found."
380 if ((">>>" in line) and ("emerge" in line)):
382 difference = "infinity"
385 if (p.name + '-' + p.version in line):
387 time = float(line.partition(' ')[0].strip(":"))
389 timestamp = datetime.datetime.fromtimestamp(time)
390 new_difference = (now - timestamp).total_seconds()
392 if ((new_difference < difference) or
393 (difference == "infinity")):
394 difference = new_difference
396 p.emerge_time = difference
402 def main(status, user_package=None):
403 """Main function. Hanlde all the different modes of operation."""
405 if status == "package":
406 user_package = get_package(user_package)
408 pack = package(user_package)
410 search_log_for_package(pack)
412 if len(pack.versions) != 0:
413 pack.print_versions()
414 pack.print_min_max_ave()
417 print("Package " + green_start + pack.name +
418 color_stop + " has never been emerged.")
421 elif status == "current":
422 if list_emerge_processes():
425 print "Currently emerging:"
428 search_log_for_package(p)
429 p.print_current_emerge()
432 elif status == "pretended":
435 print "This is how long these packages would take to emerge"
437 total_pretended_time = 0
440 search_log_for_package(p)
442 total_pretended_time += p.print_pretended_times()
446 print("Total emerge time of " + green_start + str(len(PACKAGES)) +
447 color_stop + " package(s): "+ give_time(total_pretended_time))
451 usage = """Usage: emerge-timer.py [package] [options]
453 Calculate emerge times from emerge log.
456 \t-c, --current \t Show time until currently compiling package finishes
457 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
458 \t-h, --help \t Show this helpscreen
459 \t-q, --quiet \t Be less verbose
460 \t--no-color \t Use colorless output"""
467 if __name__ == "__main__":
469 # Set the default mode as "package"
474 for arg in sys.argv[1:]:
476 if arg == "-p" or arg == "--pretended":
479 if arg == "-c" or arg == "--current":
482 if arg == "-h" or arg == "--help":
485 if arg == "-q" or arg == "--quiet":
488 if arg == "--no-color":
493 if len(sys.argv) > 1:
494 input_package = sys.argv[1]
498 main(mode, input_package)