4 import sys, datetime, os
7 PORTDIR = "/usr/portage/"
8 LOGFILE = "/var/log/emerge.log"
11 green_start = "\033[32m"
12 red_start = "\033[1;31m"
22 def __init__(self, name, version=0):
24 self.version = version
26 self.emerge_time = "infinity"
29 def add_version(self, version, emerge_time, emerge_date):
30 """Add version to the class version list"""
31 self.versions.append((version, emerge_time, emerge_date))
34 def average_time(self):
35 """Return average time from class version list"""
37 for i in self.versions:
40 average_time = total_time/len(self.versions)
46 """Return total time from class version list"""
48 for i in self.versions:
55 """Return maximum time from class version list"""
58 for i in self.versions:
59 emerge_times.append(i[1])
63 return emerge_times[-1]
67 """Return minimum time from class version list"""
70 for i in self.versions:
71 emerge_times.append(i[1])
75 return emerge_times[0]
79 def print_current_emerge(self):
80 """Function used to print all the current emerge stuff"""
82 print("\t" + green_start + self.name + '-' + self.version +
83 color_stop + "\n\t current time: " + give_time(self.emerge_time))
86 if len(self.versions) == 1:
87 print("\t last time: "),
88 print(give_time(self.average_time())),
90 elif len(self.versions) > 1:
91 print("\t average time:"),
92 print(give_time(self.average_time())),
95 print("\t average time: " + green_start + "unknown\n" + color_stop),
98 print("\n\t " + '-'*45),
100 print("\n\t time to finish:"),
102 if type(self.emerge_time) != str:
104 finish_time = self.average_time() - self.emerge_time
107 print(give_time(finish_time))
109 print(green_start + "any time now" + color_stop)
111 print(green_start + "unknown" + color_stop)
115 def print_versions(self):
116 """This prints the emerge times for different versions in the
117 'package' operating mode of the script"""
124 for p in self.versions:
125 if len(p[0]) > version_length:
126 version_length = len(p[0])
128 if len(give_time(p[1], True)) > time_length:
129 time_length = len(give_time(p[1], True))
131 for p in self.versions:
133 pad = time_length - len(give_time(p[1], True))
135 print('-'*90 + "\n" +
136 green_start + self.name + (p[0]).ljust(version_length) +
137 color_stop + " >>> " + (give_time(p[1])) + " "*pad +
138 " >>> " + give_date(p[2]))
140 print('-'*90 + "\n" + "Package " + green_start +
141 self.name + color_stop + " emerged " +
142 str(len(self.versions)) + " times.")
147 def print_pretended_times(self):
148 """This is used the print all the pretended times"""
151 print("\t" + green_start + self.name + '-' + self.version + color_stop),
153 if len(self.versions) > 1:
154 aver_time = self.average_time()
157 print("\n\taverage time: " + give_time(aver_time))
163 print("\n\t no previous emerges")
168 def print_min_max_ave(self):
169 maxi = self.max_time()
170 mini = self.min_time()
171 average = self.average_time()
172 total = self.total_time()
174 print("Max time:\t" + give_time(maxi) +
175 "\nMin time:\t" + give_time(mini) +
176 "\nAverage time:\t" + give_time(average) +
177 "\nIn total spent:\t" + give_time(total) +
178 "emerging " + green_start + self.name + color_stop)
182 def give_time(time, nocolor=False):
183 """Converts time in seconds to human readable form"""
184 global green_start, color_stop
186 if green_start == "":
193 if type(time) == str:
194 return(green_start + "unknown" + color_stop)
197 days = time/(3600.0*24.0)
198 hours = (days - int(days))*24.0
199 minutes = (hours - int(hours))*60.0
200 seconds = (minutes - int(minutes))*60.0
204 minutes = int(minutes)
205 seconds = int(round(seconds))
213 pdays = (green_start + str(days) +
214 color_stop + " day ")
216 pdays = (green_start + str(days) +
217 color_stop + " days ")
220 phours = (green_start + str(hours) +
221 color_stop + " hour ")
223 phours = (green_start + str(hours) +
224 color_stop + " hours ")
227 pminutes = (green_start + str(minutes) +
228 color_stop + " minute ")
230 pminutes = (green_start + str(minutes) +
231 color_stop + " minutes ")
234 pseconds = (green_start + str(seconds) +
235 color_stop + " second ")
237 pseconds = (green_start + str(seconds) +
238 color_stop + " seconds ")
241 green_start = "\033[32m"
242 color_stop = "\033[m"
244 return (pdays + phours + pminutes + pseconds)
248 def give_date(emerge_date):
249 """Returns a date string from a standard POSIX time"""
250 date = datetime.datetime.fromtimestamp(emerge_date)
252 date = "{:%d.%m.%Y %H:%M:%S}".format(date)
259 """Attempt to open the LOGFILE."""
262 f = open(LOGFILE, 'r')
263 except IOError as detail:
271 def search_log_for_package(package_class):
272 """Searchs emerge log for given package and adds all found
273 versions with their emerge times to the class"""
278 if ((">>>" in line) and ("emerge" in line)):
279 if package_class.name in line:
281 version = line.partition(package_class.name)[2].partition(' ')[0]
282 digit = version.strip('-')[0].isdigit()
285 time_string = line.partition(">>>")
286 start_time = float(time_string[0].strip().strip(':'))
288 elif ((":::" in line) and ("completed emerge" in line)):
290 if package_class.name in line:
292 time_string = line.partition(":::")
293 stop_time = float(time_string[0].strip().strip(':'))
295 emerge_time = stop_time - start_time
297 package_class.add_version(version, emerge_time, start_time)
301 def get_package(name):
302 """Take the user-input package name and search for it
305 dirlist = os.listdir(PORTDIR)
306 possible_package = []
309 # If the given name is in the format xxx/zzz
310 # assume that xxx is the package group
312 group = name.partition('/')[0]
313 pkg = name.partition('/')[2]
314 directory = PORTDIR + group
317 dirs = os.listdir(directory)
319 possible_package.append(name)
322 # Go through the directory listing searching for anything
323 # that matches the given name
325 directory = PORTDIR + i
326 if os.path.isdir(directory):
327 dirs = os.listdir(directory)
329 possible_package.append(i + '/' + name)
332 if len(possible_package) > 1:
333 print("Multiple packages found for '" + name + "'.")
334 print("Possible packages: ")
335 for value in possible_package:
339 elif len(possible_package) == 1:
340 package = possible_package[0]
345 print("No package '" + name + "' found")
352 def list_pretended():
353 """List all the pretended packages given by emerge -p
354 output. Create a class out of each of those packages and add them
359 for line in sys.stdin:
360 if "[ebuild" in line:
361 full_name = line.partition("] ")[2].partition(' ')[0]
363 version = full_name.partition('/')[2].partition('-')[2]
364 while not version[0].isdigit():
365 version = version.partition('-')[2]
366 package_name = full_name[:-len(version)-1]
368 PACKAGES.append(package(package_name, version))
372 def list_emerge_processes():
373 """Look for the ebuild process with ps. If the process is found parse
374 the command for the package. With this package search the LOGFILE for
375 the emerge startup time."""
379 now = datetime.datetime.today()
381 for i in os.popen("ps ax"):
382 if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
383 pack = i.partition('[')[2].partition(']')[0]
385 version = pack.partition('/')[2].partition('-')[2]
387 while not version[0].isdigit():
388 version = version.partition('-')[2]
390 package_name = pack[:-len(version)-1]
392 PACKAGES.append(package(package_name, version))
395 if len(PACKAGES) == 0:
396 print "No current emerge process found."
402 if ((">>>" in line) and ("emerge" in line)):
406 if (p.name + '-' + p.version in line):
408 time = float(line.partition(' ')[0].strip(":"))
410 timestamp = datetime.datetime.fromtimestamp(time)
411 difference = (now - timestamp).total_seconds()
413 if ((difference < p.emerge_time) or
414 (p.emerge_time == "infinity")):
416 p.emerge_time = difference
422 def main(status, user_package=None):
423 """Main function. Hanlde all the different modes of operation."""
425 if status == "package":
426 user_package = get_package(user_package)
428 pack = package(user_package)
430 search_log_for_package(pack)
432 if len(pack.versions) != 0:
433 pack.print_versions()
434 pack.print_min_max_ave()
437 print("Package " + green_start + pack.name +
438 color_stop + " has never been emerged.")
441 elif status == "current":
442 if list_emerge_processes():
445 print "Currently emerging:"
448 search_log_for_package(p)
449 p.print_current_emerge()
452 elif status == "pretended":
455 print "This is how long these packages would take to emerge"
457 total_pretended_time = 0
460 search_log_for_package(p)
462 total_pretended_time += p.print_pretended_times()
466 print("Total emerge time of " + green_start + str(len(PACKAGES)) +
467 color_stop + " package(s): "+ give_time(total_pretended_time))
471 usage = """Usage: emerge-timer.py [package] [options]
473 Calculate emerge times from emerge log.
476 \t-c, --current \t Show time until currently compiling package finishes
477 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
478 \t-h, --help \t Show this helpscreen
479 \t-q, --quiet \t Be less verbose
480 \t--no-color \t Use colorless output
481 \t--simulate \t Do a simulation run"""
488 if __name__ == "__main__":
490 # Set the default mode as "package"
495 for arg in sys.argv[1:]:
497 if arg == "-p" or arg == "--pretended":
500 if arg == "-c" or arg == "--current":
503 if arg == "-h" or arg == "--help":
506 if arg == "-q" or arg == "--quiet":
509 if arg == "--no-color":
513 if arg == "--simulate":
517 if len(sys.argv) > 1:
518 input_package = sys.argv[1]
522 if simulation == True:
524 print(red_start + "\n" + '*'*25 + "\n" + "THIS IS A SIMULATION RUN\n"
527 print("Beginning 'package' mode check")
529 print("Checking for one emerge\n" + color_stop)
531 LOGFILE = "simulate/fake_emerge.log"
532 PORTDIR = "simulate/"
534 main("package", "first_fake_package")
536 print(red_start + "\nChecking for three emerges\n" + color_stop)
538 main("package", "second_fake_package")
540 print(red_start + "\n'package' mode check complete\n")
544 print("\nBeginning 'current' mode check")
545 print("Current emerge with no emerge process\n" + color_stop)
547 main("current", None)
549 print(red_start + "\nCurrent emerge with emerge processes\n" + color_stop)
551 PACKAGES.append(package("test-group/second_fake_package", "2.9-r2"))
552 PACKAGES[0].emerge_time = 60
553 PACKAGES.append(package("test-group/first_fake_package", "1.10.2-r1"))
554 PACKAGES[1].emerge_time = 120
556 main("current", None)
558 print(red_start + "\nCurrent emerge with incomplete emerge log" +
559 "(causes error in some cases)\n" + color_stop)
562 PACKAGES.append(package("test-group/third_fake_package", "2.9-r2"))
564 main("current", None)
566 print(red_start + "\n" + '*'*20 + "\n" + "SIMULATION FINISHED\n" +
571 main(mode, input_package)