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 = "infinity"
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())),
83 print(green_start + "unknown" + color_stop),
85 print("\n\t " + '-'*45),
87 print("\n\t time to finish:"),
89 if type(self.emerge_time) != str:
91 finish_time = self.average_time() - self.emerge_time
94 print(give_time(finish_time))
96 print(green_start + "any time now" + color_stop)
98 print(green_start + "unknown" + color_stop)
102 def print_versions(self):
103 """This prints the emerge times for different versions in the
104 'package' operating mode of the script"""
111 for p in self.versions:
112 if len(p[0]) > version_length:
113 version_length = len(p[0])
115 if len(give_time(p[1], True)) > time_length:
116 time_length = len(give_time(p[1], True))
118 for p in self.versions:
120 pad = time_length - len(give_time(p[1], True))
122 print('-'*90 + "\n" +
123 green_start + self.name + (p[0]).ljust(version_length) +
124 color_stop + " >>> " + (give_time(p[1])) + " "*pad +
125 " >>> " + give_date(p[2]))
127 print('-'*90 + "\n" + "Package " + green_start +
128 self.name + color_stop + " emerged " +
129 str(len(self.versions)) + " times.")
134 def print_pretended_times(self):
135 """This is used the print all the pretended times"""
138 print("\t" + green_start + self.name + '-' + self.version + color_stop),
140 if len(self.versions) > 1:
141 aver_time = self.average_time()
144 print("\n\taverage time: " + give_time(aver_time))
150 print("\n\t no previous emerges")
155 def print_min_max_ave(self):
156 maxi = self.max_time()
157 mini = self.min_time()
158 average = self.average_time()
159 total = self.total_time()
161 print("Max time: \t" + give_time(maxi) +
162 "\nMin time: \t" + give_time(mini) +
163 "\nAverage time: \t" + give_time(average) +
164 "\nIn total spent " + give_time(total) +
165 " emerging " + green_start + self.name + color_stop)
169 def give_time(time, nocolor=False):
170 """Converts time in seconds to human readable form"""
171 global green_start, color_stop
173 if green_start == "":
180 if type(time) == str:
181 return(green_start + "unknown" + color_stop)
184 days = time/(3600*24)
185 hours = (days - int(days))*24
186 minutes = (hours - int(hours))*60
187 seconds = (minutes - int(minutes))*60
191 minutes = int(minutes)
192 seconds = int(round(seconds))
200 pdays = (green_start + str(days) +
201 color_stop + " day ")
203 pdays = (green_start + str(days) +
204 color_stop + " days ")
207 phours = (green_start + str(hours) +
208 color_stop + " hour ")
210 phours = (green_start + str(hours) +
211 color_stop + " hours ")
214 pminutes = (green_start + str(minutes) +
215 color_stop + " minute ")
217 pminutes = (green_start + str(minutes) +
218 color_stop + " minutes ")
220 pseconds = (green_start + str(seconds) +
221 color_stop + " second ")
223 pseconds = (green_start + str(seconds) +
224 color_stop + " seconds ")
227 green_start = "\033[32m"
228 color_stop = "\033[m"
230 return (pdays + phours + pminutes + pseconds)
234 def give_date(emerge_date):
235 """Returns a date string from a standard POSIX time"""
236 date = datetime.datetime.fromtimestamp(emerge_date)
238 date = "{:%d.%m.%Y %H:%M:%S}".format(date)
245 """Attempt to open the LOGFILE."""
248 f = open(LOGFILE, 'r')
249 except IOError as detail:
257 def search_log_for_package(package_class):
258 """Searchs emerge log for given package and adds all found
259 versions with their emerge times to the class"""
264 if ((">>>" in line) and ("emerge" in line)):
265 if package_class.name in line:
267 version = line.partition(package_class.name)[2].partition(' ')[0]
268 digit = version.strip('-')[0].isdigit()
271 time_string = line.partition(">>>")
272 start_time = float(time_string[0].strip().strip(':'))
274 elif ((":::" in line) and ("completed emerge" in line)):
276 if package_class.name in line:
278 time_string = line.partition(":::")
279 stop_time = float(time_string[0].strip().strip(':'))
281 emerge_time = stop_time - start_time
283 package_class.add_version(version, emerge_time, start_time)
287 def get_package(name):
288 """Take the user-input package name and search for it
291 dirlist = os.listdir(PORTDIR)
292 possible_package = []
295 # If the given name is in the format xxx/zzz
296 # assume that xxx is the package group
298 group = name.partition('/')[0]
299 pkg = name.partition('/')[2]
300 directory = PORTDIR + group
303 dirs = os.listdir(directory)
305 possible_package.append(name)
308 # Go through the directory listing searching for anything
309 # that matches the given name
311 directory = PORTDIR + i
312 if os.path.isdir(directory):
313 dirs = os.listdir(directory)
315 possible_package.append(i + '/' + name)
318 if len(possible_package) > 1:
319 print("Multiple packages found for '" + name + "'.")
320 print("Possible packages: ")
321 for value in possible_package:
325 elif len(possible_package) == 1:
326 package = possible_package[0]
331 print("No package '" + name + "' found")
338 def list_pretended():
339 """List all the pretended packages given by emerge -p
340 output. Create a class out of each of those packages and add them
345 for line in sys.stdin:
346 if "[ebuild" in line:
347 full_name = line.partition("] ")[2].partition(' ')[0]
349 version = full_name.partition('/')[2].partition('-')[2]
350 while not version[0].isdigit():
351 version = version.partition('-')[2]
352 package_name = full_name[:-len(version)-1]
354 PACKAGES.append(package(package_name, version))
358 def list_emerge_processes():
359 """Look for the ebuild process with ps. If the process is found parse
360 the command for the package. With this package search the LOGFILE for
361 the emerge startup time."""
365 now = datetime.datetime.today()
367 for i in os.popen("ps ax"):
368 if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
369 pack = i.partition('[')[2].partition(']')[0]
371 version = pack.partition('/')[2].partition('-')[2]
373 while not version[0].isdigit():
374 version = version.partition('-')[2]
376 package_name = pack[:-len(version)-1]
378 PACKAGES.append(package(package_name, version))
381 if len(PACKAGES) == 0:
382 print "No current emerge process found."
388 if ((">>>" in line) and ("emerge" in line)):
392 if (p.name + '-' + p.version in line):
394 time = float(line.partition(' ')[0].strip(":"))
396 timestamp = datetime.datetime.fromtimestamp(time)
397 difference = (now - timestamp).total_seconds()
399 if ((difference < p.emerge_time) or
400 (p.emerge_time == "infinity")):
402 p.emerge_time = difference
408 def main(status, user_package=None):
409 """Main function. Hanlde all the different modes of operation."""
411 if status == "package":
412 user_package = get_package(user_package)
414 pack = package(user_package)
416 search_log_for_package(pack)
418 if len(pack.versions) != 0:
419 pack.print_versions()
420 pack.print_min_max_ave()
423 print("Package " + green_start + pack.name +
424 color_stop + " has never been emerged.")
427 elif status == "current":
428 if list_emerge_processes():
431 print "Currently emerging:"
434 search_log_for_package(p)
435 p.print_current_emerge()
438 elif status == "pretended":
441 print "This is how long these packages would take to emerge"
443 total_pretended_time = 0
446 search_log_for_package(p)
448 total_pretended_time += p.print_pretended_times()
452 print("Total emerge time of " + green_start + str(len(PACKAGES)) +
453 color_stop + " package(s): "+ give_time(total_pretended_time))
457 usage = """Usage: emerge-timer.py [package] [options]
459 Calculate emerge times from emerge log.
462 \t-c, --current \t Show time until currently compiling package finishes
463 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
464 \t-h, --help \t Show this helpscreen
465 \t-q, --quiet \t Be less verbose
466 \t--no-color \t Use colorless output"""
473 if __name__ == "__main__":
475 # Set the default mode as "package"
480 for arg in sys.argv[1:]:
482 if arg == "-p" or arg == "--pretended":
485 if arg == "-c" or arg == "--current":
488 if arg == "-h" or arg == "--help":
491 if arg == "-q" or arg == "--quiet":
494 if arg == "--no-color":
499 if len(sys.argv) > 1:
500 input_package = sys.argv[1]
504 main(mode, input_package)