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.")
485 elif status == "list":
486 search_log_for_all_packages()
490 elif status == "current":
491 if list_emerge_processes():
494 print "Currently emerging:"
497 search_log_for_package(p)
498 p.print_current_emerge()
501 elif status == "pretended":
504 print "This is how long these packages would take to emerge"
506 total_pretended_time = 0
509 search_log_for_package(p)
511 total_pretended_time += p.print_pretended_times()
515 print("Total emerge time of " + GREEN(str(len(PACKAGES)))
516 + " package(s): "+ give_time(total_pretended_time))
520 usage = """Usage: emerge-timer.py [package] [options]
522 Calculate emerge times from emerge log.
525 \t-c, --current \t Show time until currently compiling package finishes
526 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
527 \t-l, --list \t List all emerged packages
528 \t-h, --help \t Show this helpscreen
529 \t-q, --quiet \t Be less verbose
530 \t--no-color \t Use colorless output
531 \t--simulate \t Do a simulation run"""
538 if __name__ == "__main__":
540 # Set the default mode as "package"
542 input_packages = None
545 for arg in sys.argv[1:]:
547 if arg == "-p" or arg == "--pretended":
550 if arg == "-c" or arg == "--current":
553 if arg == "-h" or arg == "--help":
556 if arg == "-l" or arg == "--list":
559 if arg == "-q" or arg == "--quiet":
562 sys.argv.pop(sys.argv.index(arg))
564 if arg == "--no-color":
568 sys.argv.pop(sys.argv.index(arg))
570 if arg == "--simulate":
574 if len(sys.argv) > 1:
575 input_packages = sys.argv[1:]
579 if simulation == True:
581 print(RED("\n" + '*'*25 + "\n" + "THIS IS A SIMULATION RUN\n"
584 print(RED("Beginning 'package' mode check"))
586 print(RED("Checking for one emerge\n"))
588 LOGFILE = "simulate/fake_emerge.log"
589 PORTDIR = "simulate/"
591 main("package", "first_fake_package")
593 print(RED("\nChecking for three emerges\n"))
595 main("package", "second_fake_package")
597 print(RED("\n'package' mode check complete\n"))
601 print(RED("\nBeginning 'current' mode check"))
602 print(RED("Current emerge with no emerge process\n"))
604 main("current", None)
606 print(RED("\nCurrent emerge with emerge processes\n"))
608 PACKAGES.append(package("test-group/second_fake_package", "2.9-r2"))
609 PACKAGES[0].emerge_time = 60
610 PACKAGES.append(package("test-group/first_fake_package", "1.10.2-r1"))
611 PACKAGES[1].emerge_time = 120
613 main("current", None)
615 print(RED("\nCurrent emerge with incomplete emerge log " +
616 "(causes error in some cases)\n"))
619 PACKAGES.append(package("test-group/third_fake_package", "2.9-r2"))
621 main("current", None)
623 print(RED("\n" + '*'*20 + "\n" + "SIMULATION FINISHED\n" +
628 main(mode, input_packages)