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 " +
152 str(len(self.versions)) + " times.\n")
156 def print_pretended_times(self):
157 """This is used the print all the pretended times"""
160 print("\t" + GREEN(self.name + '-' + self.version)),
162 if len(self.versions) > 1:
163 aver_time = self.average_time()
166 print("\n\taverage time: " + give_time(aver_time))
172 print("\n\t no previous emerges")
177 def print_min_max_ave(self):
178 maxi = self.max_time()
179 mini = self.min_time()
180 average = self.average_time()
181 total = self.total_time()
183 print("Max time:\t" + give_time(maxi) +
184 "\nMin time:\t" + give_time(mini) +
185 "\nAverage time:\t" + give_time(average) +
186 "\nIn total spent:\t" + give_time(total) +
187 "emerging " + GREEN(self.name))
191 def give_time(time, nocolor=False):
192 """Converts time in seconds to human readable form"""
193 global green_start, color_stop
195 if green_start == "":
202 if type(time) == str:
203 return(GREEN("unknown"))
206 days = time/(3600.0*24.0)
207 hours = (days - int(days))*24.0
208 minutes = (hours - int(hours))*60.0
209 seconds = (minutes - int(minutes))*60.0
213 minutes = int(minutes)
214 seconds = int(round(seconds))
222 pdays = (GREEN(str(days)) + " day ")
224 pdays = (GREEN(str(days)) + " days ")
227 phours = (GREEN(str(hours)) + " hour ")
229 phours = (GREEN(str(hours)) + " hours ")
232 pminutes = (GREEN(str(minutes)) + " minute ")
234 pminutes = (GREEN(str(minutes)) + " minutes ")
237 pseconds = (GREEN(str(seconds)) + " second ")
239 pseconds = (GREEN(str(seconds)) + " seconds ")
242 green_start = "\033[32m"
243 color_stop = "\033[m"
245 return (pdays + phours + pminutes + pseconds)
249 def give_date(emerge_date):
250 """Returns a date string from a standard POSIX time"""
251 date = datetime.datetime.fromtimestamp(emerge_date)
253 date = "{:%d.%m.%Y %H:%M:%S}".format(date)
260 """Attempt to open the LOGFILE."""
263 f = open(LOGFILE, 'r')
264 except IOError as detail:
272 def search_log_for_package(package_class):
273 """Searchs emerge log for given package and adds all found
274 versions with their emerge times to the class"""
279 if ((">>>" in line) and ("emerge" in line)):
280 if package_class.name in line:
282 version = line.partition(package_class.name)[2].partition(' ')[0]
283 digit = version.strip('-')[0].isdigit()
286 time_string = line.partition(">>>")
287 start_time = float(time_string[0].strip().strip(':'))
289 elif ((":::" in line) and ("completed emerge" in line)):
291 if package_class.name in line:
293 time_string = line.partition(":::")
294 stop_time = float(time_string[0].strip().strip(':'))
296 emerge_time = stop_time - start_time
298 package_class.add_version(version, emerge_time, start_time)
302 def search_log_for_all_packages():
303 """Goes through the emerge.log and lists all packages in there"""
309 total_emerge_time = 0
313 if ((">>>" in line) and ("emerge" in line)):
314 pack = line.partition(')')[2].strip().partition(' ')[0]
315 start_time = float(line.partition(':')[0])
317 all_packages.append((pack, start_time))
319 elif ((":::" in line) and ("completed emerge" in line)):
320 for p in all_packages:
322 stop_time = float(line.partition(':')[0])
324 print("\t" + give_date(p[1]) + " >>> " + GREEN(p[0]))
326 total_emerge_time += stop_time - p[1]
329 all_packages.pop(all_packages.index(p))
331 print("\nTotal emerge time of " + GREEN(str(emerge_number)) +
332 " merges: " + give_time(total_emerge_time))
336 def get_package(name):
337 """Take the user-input package name and search for it
340 dirlist = os.listdir(PORTDIR)
341 possible_package = []
344 # If the given name is in the format xxx/zzz
345 # assume that xxx is the package group
347 group = name.partition('/')[0]
348 pkg = name.partition('/')[2]
349 directory = PORTDIR + group
352 dirs = os.listdir(directory)
354 possible_package.append(name)
357 # Go through the directory listing searching for anything
358 # that matches the given name
360 directory = PORTDIR + i
361 if os.path.isdir(directory):
362 dirs = os.listdir(directory)
364 possible_package.append(i + '/' + name)
367 if len(possible_package) > 1:
368 print("Multiple packages found for '" + name + "'.")
369 print("Possible packages: ")
370 for value in possible_package:
374 elif len(possible_package) == 1:
375 package = possible_package[0]
380 print("No package '" + name + "' found")
387 def list_pretended():
388 """List all the pretended packages given by emerge -p
389 output. Create a class out of each of those packages and add them
394 for line in sys.stdin:
395 if "[ebuild" in line:
396 full_name = line.partition("] ")[2].partition(' ')[0]
398 version = full_name.partition('/')[2].partition('-')[2]
399 while not version[0].isdigit():
400 version = version.partition('-')[2]
401 package_name = full_name[:-len(version)-1]
403 PACKAGES.append(package(package_name, version))
407 def list_emerge_processes():
408 """Look for the ebuild process with ps. If the process is found parse
409 the command for the package. With this package search the LOGFILE for
410 the emerge startup time."""
414 now = datetime.datetime.today()
416 for i in os.popen("ps ax"):
417 if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
418 pack = i.partition('[')[2].partition(']')[0]
420 version = pack.partition('/')[2].partition('-')[2]
422 while not version[0].isdigit():
423 version = version.partition('-')[2]
425 package_name = pack[:-len(version)-1]
427 PACKAGES.append(package(package_name, version))
430 if len(PACKAGES) == 0:
431 print "No current emerge process found."
437 if ((">>>" in line) and ("emerge" in line)):
441 if (p.name + '-' + p.version in line):
443 time = float(line.partition(' ')[0].strip(":"))
445 timestamp = datetime.datetime.fromtimestamp(time)
446 difference = (now - timestamp).total_seconds()
448 if ((difference < p.emerge_time) or
449 (p.emerge_time == "infinity")):
451 p.emerge_time = difference
457 def main(status, user_package=None):
458 """Main function. Hanlde all the different modes of operation."""
460 if status == "package":
461 for p in user_package:
462 pack = get_package(p)
466 search_log_for_package(pack)
468 if len(pack.versions) != 0:
469 pack.print_versions()
470 pack.print_min_max_ave()
473 print("Package " + GREEN(pack.name)
474 + " has never been emerged.")
479 elif status == "current":
480 if list_emerge_processes():
483 print "Currently emerging:"
486 search_log_for_package(p)
487 p.print_current_emerge()
490 elif status == "pretended":
493 print "This is how long these packages would take to emerge"
495 total_pretended_time = 0
498 search_log_for_package(p)
500 total_pretended_time += p.print_pretended_times()
504 print("Total emerge time of " + GREEN(str(len(PACKAGES)))
505 + " package(s): "+ give_time(total_pretended_time))
509 usage = """Usage: emerge-timer.py [package] [options]
511 Calculate emerge times from emerge log.
514 \t-c, --current \t Show time until currently compiling package finishes
515 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
516 \t-l, --list \t List all emerged packages
517 \t-h, --help \t Show this helpscreen
518 \t-q, --quiet \t Be less verbose
519 \t--no-color \t Use colorless output
520 \t--simulate \t Do a simulation run"""
527 if __name__ == "__main__":
529 # Set the default mode as "package"
531 input_packages = None
534 for arg in sys.argv[1:]:
536 if arg == "-p" or arg == "--pretended":
539 if arg == "-c" or arg == "--current":
542 if arg == "-h" or arg == "--help":
545 if arg == "-l" or arg == "--list":
546 search_log_for_all_packages()
549 if arg == "-q" or arg == "--quiet":
552 sys.argv.pop(sys.argv.index(arg))
554 if arg == "--no-color":
558 sys.argv.pop(sys.argv.index(arg))
560 if arg == "--simulate":
564 if len(sys.argv) > 1:
565 input_packages = sys.argv[1:]
569 if simulation == True:
571 print(RED("\n" + '*'*25 + "\n" + "THIS IS A SIMULATION RUN\n"
574 print(RED("Beginning 'package' mode check"))
576 print(RED("Checking for one emerge\n"))
578 LOGFILE = "simulate/fake_emerge.log"
579 PORTDIR = "simulate/"
581 main("package", "first_fake_package")
583 print(RED("\nChecking for three emerges\n"))
585 main("package", "second_fake_package")
587 print(RED("\n'package' mode check complete\n"))
591 print(RED("\nBeginning 'current' mode check"))
592 print(RED("Current emerge with no emerge process\n"))
594 main("current", None)
596 print(RED("\nCurrent emerge with emerge processes\n"))
598 PACKAGES.append(package("test-group/second_fake_package", "2.9-r2"))
599 PACKAGES[0].emerge_time = 60
600 PACKAGES.append(package("test-group/first_fake_package", "1.10.2-r1"))
601 PACKAGES[1].emerge_time = 120
603 main("current", None)
605 print(RED("\nCurrent emerge with incomplete emerge log " +
606 "(causes error in some cases)\n"))
609 PACKAGES.append(package("test-group/third_fake_package", "2.9-r2"))
611 main("current", None)
613 print(RED("\n" + '*'*20 + "\n" + "SIMULATION FINISHED\n" +
618 main(mode, input_packages)