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"
20 return green_start + string + color_stop
23 return red_start + string + color_stop
27 def __init__(self, name, version=0):
29 self.version = version
31 self.emerge_time = "infinity"
34 def add_version(self, version, emerge_time, emerge_date):
35 """Add version to the class version list"""
36 self.versions.append((version, emerge_time, emerge_date))
39 def average_time(self):
40 """Return average time from class version list"""
42 for i in self.versions:
45 average_time = total_time/len(self.versions)
51 """Return total time from class version list"""
53 for i in self.versions:
60 """Return maximum time from class version list"""
63 for i in self.versions:
64 emerge_times.append(i[1])
68 return emerge_times[-1]
72 """Return minimum time from class version list"""
75 for i in self.versions:
76 emerge_times.append(i[1])
80 return emerge_times[0]
84 def print_current_emerge(self):
85 """Function used to print all the current emerge stuff"""
87 print("\t" + GREEN(self.name + '-' + self.version) +
88 "\n\t current time: " + give_time(self.emerge_time))
91 if len(self.versions) == 1:
92 print("\t last time: "),
93 print(give_time(self.average_time())),
95 elif len(self.versions) > 1:
96 print("\t average time:"),
97 print(give_time(self.average_time())),
100 print("\t average time: " + GREEN("unknown\n")),
103 print("\n\t " + '-'*45),
105 print("\n\t time to finish:"),
107 if type(self.emerge_time) != str:
109 finish_time = self.average_time() - self.emerge_time
112 print(give_time(finish_time))
114 print(GREEN("any time now"))
116 print(GREEN("unknown"))
120 def print_versions(self):
121 """This prints the emerge times for different versions in the
122 'package' operating mode of the script"""
129 for p in self.versions:
130 if len(p[0]) > version_length:
131 version_length = len(p[0])
133 if len(give_time(p[1], True)) > time_length:
134 time_length = len(give_time(p[1], True))
136 dots = (version_length + time_length + len(self.name)
137 + len(give_date(self.versions[0][2])) + 14)
139 for p in self.versions:
141 pad = time_length - len(give_time(p[1], True))
144 p_time = give_time(p[1])
145 p_date = give_date(p[2])
147 print('-' * dots + "\n" +
148 GREEN(name + (p[0]).ljust(version_length))
149 + " >>> " + p_time + " "*pad + " >>> " + p_date)
151 print("\n" + "Package " + GREEN(self.name) + " emerged"),
153 if len(self.versions) > 1:
154 print(str(len(self.versions)) + " times.\n")
155 elif len(self.versions) == 1:
160 def print_pretended_times(self):
161 """This is used the print all the pretended times"""
164 print("\t" + GREEN(self.name + '-' + self.version)),
166 if len(self.versions) > 1:
167 aver_time = self.average_time()
170 print("\n\taverage time: " + give_time(aver_time))
176 print("\n\t no previous emerges")
181 def print_min_max_ave(self):
183 if len(self.versions) == 1:
186 maxi = self.max_time()
187 mini = self.min_time()
188 average = self.average_time()
189 total = self.total_time()
191 print("Max time:\t" + give_time(maxi) +
192 "\nMin time:\t" + give_time(mini) +
193 "\nAverage time:\t" + give_time(average) +
194 "\nIn total spent:\t" + give_time(total) +
195 "emerging " + GREEN(self.name))
199 def give_time(time, nocolor=False):
200 """Converts time in seconds to human readable form"""
201 global green_start, color_stop
203 if green_start == "":
210 if type(time) == str:
211 return(GREEN("unknown"))
214 days = time/(3600.0*24.0)
215 hours = (days - int(days))*24.0
216 minutes = (hours - int(hours))*60.0
217 seconds = (minutes - int(minutes))*60.0
221 minutes = int(minutes)
222 seconds = int(round(seconds))
230 pdays = (GREEN(str(days)) + " day ")
232 pdays = (GREEN(str(days)) + " days ")
235 phours = (GREEN(str(hours)) + " hour ")
237 phours = (GREEN(str(hours)) + " hours ")
240 pminutes = (GREEN(str(minutes)) + " minute ")
242 pminutes = (GREEN(str(minutes)) + " minutes ")
245 pseconds = (GREEN(str(seconds)) + " second ")
247 pseconds = (GREEN(str(seconds)) + " seconds ")
250 green_start = "\033[32m"
251 color_stop = "\033[m"
253 return (pdays + phours + pminutes + pseconds)
257 def give_date(emerge_date):
258 """Returns a date string from a standard POSIX time"""
259 date = datetime.datetime.fromtimestamp(emerge_date)
261 date = "{:%d.%m.%Y %H:%M:%S}".format(date)
268 """Attempt to open the LOGFILE."""
271 f = open(LOGFILE, 'r')
272 except IOError as detail:
280 def search_log_for_package(package_class):
281 """Searchs emerge log for given package and adds all found
282 versions with their emerge times to the class"""
287 if ((">>>" in line) and ("emerge" in line)):
288 if package_class.name in line:
290 version = line.partition(package_class.name)[2].partition(' ')[0]
291 digit = version.strip('-')[0].isdigit()
294 time_string = line.partition(">>>")
295 start_time = float(time_string[0].strip().strip(':'))
297 elif ((":::" in line) and ("completed emerge" in line)):
299 if package_class.name in line:
301 time_string = line.partition(":::")
302 stop_time = float(time_string[0].strip().strip(':'))
304 emerge_time = stop_time - start_time
306 package_class.add_version(version, emerge_time, start_time)
310 def search_log_for_all_packages():
311 """Goes through the emerge.log and lists all packages in there"""
317 total_emerge_time = 0
321 if ((">>>" in line) and ("emerge" in line)):
322 pack = line.partition(')')[2].strip().partition(' ')[0]
323 start_time = float(line.partition(':')[0])
325 all_packages.append((pack, start_time))
327 elif ((":::" in line) and ("completed emerge" in line)):
328 for p in all_packages:
330 stop_time = float(line.partition(':')[0])
332 print("\t" + give_date(p[1]) + " >>> " + GREEN(p[0]))
334 total_emerge_time += stop_time - p[1]
337 all_packages.pop(all_packages.index(p))
339 print("\nTotal emerge time of " + GREEN(str(emerge_number)) +
340 " merges: " + give_time(total_emerge_time))
344 def get_package(name):
345 """Take the user-input package name and search for it
348 dirlist = os.listdir(PORTDIR)
349 possible_package = []
352 # If the given name is in the format xxx/zzz
353 # assume that xxx is the package group
355 group = name.partition('/')[0]
356 pkg = name.partition('/')[2]
357 directory = PORTDIR + group
360 dirs = os.listdir(directory)
362 possible_package.append(name)
365 # Go through the directory listing searching for anything
366 # that matches the given name
368 directory = PORTDIR + i
369 if os.path.isdir(directory):
370 dirs = os.listdir(directory)
372 possible_package.append(i + '/' + name)
375 if len(possible_package) > 1:
376 print("Multiple packages found for '" + name + "'.")
377 print("Possible packages: ")
378 for value in possible_package:
382 elif len(possible_package) == 1:
383 package = possible_package[0]
388 print("No package '" + name + "' found")
395 def list_pretended():
396 """List all the pretended packages given by emerge -p
397 output. Create a class out of each of those packages and add them
402 for line in sys.stdin:
403 if "[ebuild" in line:
404 full_name = line.partition("] ")[2].partition(' ')[0]
406 version = full_name.partition('/')[2].partition('-')[2]
407 while not version[0].isdigit():
408 version = version.partition('-')[2]
409 package_name = full_name[:-len(version)-1]
411 PACKAGES.append(package(package_name, version))
415 def list_emerge_processes():
416 """Look for the ebuild process with ps. If the process is found parse
417 the command for the package. With this package search the LOGFILE for
418 the emerge startup time."""
422 now = datetime.datetime.today()
424 for i in os.popen("ps ax"):
425 if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
426 pack = i.partition('[')[2].partition(']')[0]
428 version = pack.partition('/')[2].partition('-')[2]
430 while not version[0].isdigit():
431 version = version.partition('-')[2]
433 package_name = pack[:-len(version)-1]
435 PACKAGES.append(package(package_name, version))
438 if len(PACKAGES) == 0:
439 print "No current emerge process found."
445 if ((">>>" in line) and ("emerge" in line)):
449 if (p.name + '-' + p.version in line):
451 time = float(line.partition(' ')[0].strip(":"))
453 timestamp = datetime.datetime.fromtimestamp(time)
454 difference = (now - timestamp).total_seconds()
456 if ((difference < p.emerge_time) or
457 (p.emerge_time == "infinity")):
459 p.emerge_time = difference
465 def main(status, user_package=None):
466 """Main function. Hanlde all the different modes of operation."""
468 if status == "package":
469 for p in user_package:
470 pack = get_package(p)
474 search_log_for_package(pack)
476 if len(pack.versions) != 0:
477 pack.print_versions()
478 pack.print_min_max_ave()
481 print("Package " + GREEN(pack.name)
482 + " has never been emerged.")
486 elif status == "current":
487 if list_emerge_processes():
490 print "Currently emerging:"
493 search_log_for_package(p)
494 p.print_current_emerge()
497 elif status == "pretended":
500 print "This is how long these packages would take to emerge"
502 total_pretended_time = 0
505 search_log_for_package(p)
507 total_pretended_time += p.print_pretended_times()
511 print("Total emerge time of " + GREEN(str(len(PACKAGES)))
512 + " package(s): "+ give_time(total_pretended_time))
516 usage = """Usage: emerge-timer.py [package] [options]
518 Calculate emerge times from emerge log.
521 \t-c, --current \t Show time until currently compiling package finishes
522 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
523 \t-l, --list \t List all emerged packages
524 \t-h, --help \t Show this helpscreen
525 \t-q, --quiet \t Be less verbose
526 \t--no-color \t Use colorless output
527 \t--simulate \t Do a simulation run"""
534 if __name__ == "__main__":
536 # Set the default mode as "package"
538 input_packages = None
541 for arg in sys.argv[1:]:
543 if arg == "-p" or arg == "--pretended":
546 if arg == "-c" or arg == "--current":
549 if arg == "-h" or arg == "--help":
552 if arg == "-l" or arg == "--list":
553 search_log_for_all_packages()
556 if arg == "-q" or arg == "--quiet":
559 sys.argv.pop(sys.argv.index(arg))
561 if arg == "--no-color":
565 sys.argv.pop(sys.argv.index(arg))
567 if arg == "--simulate":
571 if len(sys.argv) > 1:
572 input_packages = sys.argv[1:]
576 if simulation == True:
578 print(RED("\n" + '*'*25 + "\n" + "THIS IS A SIMULATION RUN\n"
581 print(RED("Beginning 'package' mode check"))
583 print(RED("Checking for one emerge\n"))
585 LOGFILE = "simulate/fake_emerge.log"
586 PORTDIR = "simulate/"
588 main("package", "first_fake_package")
590 print(RED("\nChecking for three emerges\n"))
592 main("package", "second_fake_package")
594 print(RED("\n'package' mode check complete\n"))
598 print(RED("\nBeginning 'current' mode check"))
599 print(RED("Current emerge with no emerge process\n"))
601 main("current", None)
603 print(RED("\nCurrent emerge with emerge processes\n"))
605 PACKAGES.append(package("test-group/second_fake_package", "2.9-r2"))
606 PACKAGES[0].emerge_time = 60
607 PACKAGES.append(package("test-group/first_fake_package", "1.10.2-r1"))
608 PACKAGES[1].emerge_time = 120
610 main("current", None)
612 print(RED("\nCurrent emerge with incomplete emerge log " +
613 "(causes error in some cases)\n"))
616 PACKAGES.append(package("test-group/third_fake_package", "2.9-r2"))
618 main("current", None)
620 print(RED("\n" + '*'*20 + "\n" + "SIMULATION FINISHED\n" +
625 main(mode, input_packages)