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 dots = (version_length + time_length + len(self.name)
132 + len(give_date(self.versions[0][2])) + 14)
134 for p in self.versions:
136 pad = time_length - len(give_time(p[1], True))
139 p_time = give_time(p[1])
140 p_date = give_date(p[2])
142 print('-' * dots + "\n" +
143 green_start + name + (p[0]).ljust(version_length) +
144 color_stop + " >>> " + p_time + " "*pad +
147 print("\n" + "Package " + green_start +
148 self.name + color_stop + " emerged " +
149 str(len(self.versions)) + " times.\n")
153 def print_pretended_times(self):
154 """This is used the print all the pretended times"""
157 print("\t" + green_start + self.name + '-' + self.version + color_stop),
159 if len(self.versions) > 1:
160 aver_time = self.average_time()
163 print("\n\taverage time: " + give_time(aver_time))
169 print("\n\t no previous emerges")
174 def print_min_max_ave(self):
175 maxi = self.max_time()
176 mini = self.min_time()
177 average = self.average_time()
178 total = self.total_time()
180 print("Max time:\t" + give_time(maxi) +
181 "\nMin time:\t" + give_time(mini) +
182 "\nAverage time:\t" + give_time(average) +
183 "\nIn total spent:\t" + give_time(total) +
184 "emerging " + green_start + self.name + color_stop)
188 def give_time(time, nocolor=False):
189 """Converts time in seconds to human readable form"""
190 global green_start, color_stop
192 if green_start == "":
199 if type(time) == str:
200 return(green_start + "unknown" + color_stop)
203 days = time/(3600.0*24.0)
204 hours = (days - int(days))*24.0
205 minutes = (hours - int(hours))*60.0
206 seconds = (minutes - int(minutes))*60.0
210 minutes = int(minutes)
211 seconds = int(round(seconds))
219 pdays = (green_start + str(days) +
220 color_stop + " day ")
222 pdays = (green_start + str(days) +
223 color_stop + " days ")
226 phours = (green_start + str(hours) +
227 color_stop + " hour ")
229 phours = (green_start + str(hours) +
230 color_stop + " hours ")
233 pminutes = (green_start + str(minutes) +
234 color_stop + " minute ")
236 pminutes = (green_start + str(minutes) +
237 color_stop + " minutes ")
240 pseconds = (green_start + str(seconds) +
241 color_stop + " second ")
243 pseconds = (green_start + str(seconds) +
244 color_stop + " seconds ")
247 green_start = "\033[32m"
248 color_stop = "\033[m"
250 return (pdays + phours + pminutes + pseconds)
254 def give_date(emerge_date):
255 """Returns a date string from a standard POSIX time"""
256 date = datetime.datetime.fromtimestamp(emerge_date)
258 date = "{:%d.%m.%Y %H:%M:%S}".format(date)
265 """Attempt to open the LOGFILE."""
268 f = open(LOGFILE, 'r')
269 except IOError as detail:
277 def search_log_for_package(package_class):
278 """Searchs emerge log for given package and adds all found
279 versions with their emerge times to the class"""
284 if ((">>>" in line) and ("emerge" in line)):
285 if package_class.name in line:
287 version = line.partition(package_class.name)[2].partition(' ')[0]
288 digit = version.strip('-')[0].isdigit()
291 time_string = line.partition(">>>")
292 start_time = float(time_string[0].strip().strip(':'))
294 elif ((":::" in line) and ("completed emerge" in line)):
296 if package_class.name in line:
298 time_string = line.partition(":::")
299 stop_time = float(time_string[0].strip().strip(':'))
301 emerge_time = stop_time - start_time
303 package_class.add_version(version, emerge_time, start_time)
307 def search_log_for_all_packages():
308 """Goes through the emerge.log and lists all packages in there"""
314 total_emerge_time = 0
318 if ((">>>" in line) and ("emerge" in line)):
319 pack = line.partition(')')[2].strip().partition(' ')[0]
320 start_time = float(line.partition(':')[0])
322 all_packages.append((pack, start_time))
324 elif ((":::" in line) and ("completed emerge" in line)):
325 for p in all_packages:
327 stop_time = float(line.partition(':')[0])
329 print("\t" + give_date(p[1]) + " >>> " + green_start + p[0] + color_stop)
331 total_emerge_time += stop_time - p[1]
334 all_packages.pop(all_packages.index(p))
336 print("\nTotal emerge time of " + green_start + str(emerge_number) +
337 color_stop + " merges: " + give_time(total_emerge_time))
341 def get_package(name):
342 """Take the user-input package name and search for it
345 dirlist = os.listdir(PORTDIR)
346 possible_package = []
349 # If the given name is in the format xxx/zzz
350 # assume that xxx is the package group
352 group = name.partition('/')[0]
353 pkg = name.partition('/')[2]
354 directory = PORTDIR + group
357 dirs = os.listdir(directory)
359 possible_package.append(name)
362 # Go through the directory listing searching for anything
363 # that matches the given name
365 directory = PORTDIR + i
366 if os.path.isdir(directory):
367 dirs = os.listdir(directory)
369 possible_package.append(i + '/' + name)
372 if len(possible_package) > 1:
373 print("Multiple packages found for '" + name + "'.")
374 print("Possible packages: ")
375 for value in possible_package:
379 elif len(possible_package) == 1:
380 package = possible_package[0]
385 print("No package '" + name + "' found")
392 def list_pretended():
393 """List all the pretended packages given by emerge -p
394 output. Create a class out of each of those packages and add them
399 for line in sys.stdin:
400 if "[ebuild" in line:
401 full_name = line.partition("] ")[2].partition(' ')[0]
403 version = full_name.partition('/')[2].partition('-')[2]
404 while not version[0].isdigit():
405 version = version.partition('-')[2]
406 package_name = full_name[:-len(version)-1]
408 PACKAGES.append(package(package_name, version))
412 def list_emerge_processes():
413 """Look for the ebuild process with ps. If the process is found parse
414 the command for the package. With this package search the LOGFILE for
415 the emerge startup time."""
419 now = datetime.datetime.today()
421 for i in os.popen("ps ax"):
422 if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
423 pack = i.partition('[')[2].partition(']')[0]
425 version = pack.partition('/')[2].partition('-')[2]
427 while not version[0].isdigit():
428 version = version.partition('-')[2]
430 package_name = pack[:-len(version)-1]
432 PACKAGES.append(package(package_name, version))
435 if len(PACKAGES) == 0:
436 print "No current emerge process found."
442 if ((">>>" in line) and ("emerge" in line)):
446 if (p.name + '-' + p.version in line):
448 time = float(line.partition(' ')[0].strip(":"))
450 timestamp = datetime.datetime.fromtimestamp(time)
451 difference = (now - timestamp).total_seconds()
453 if ((difference < p.emerge_time) or
454 (p.emerge_time == "infinity")):
456 p.emerge_time = difference
462 def main(status, user_package=None):
463 """Main function. Hanlde all the different modes of operation."""
465 if status == "package":
466 for p in user_package:
467 pack = get_package(p)
471 search_log_for_package(pack)
473 if len(pack.versions) != 0:
474 pack.print_versions()
475 pack.print_min_max_ave()
478 print("Package " + green_start + pack.name +
479 color_stop + " has never been emerged.")
484 elif status == "current":
485 if list_emerge_processes():
488 print "Currently emerging:"
491 search_log_for_package(p)
492 p.print_current_emerge()
495 elif status == "pretended":
498 print "This is how long these packages would take to emerge"
500 total_pretended_time = 0
503 search_log_for_package(p)
505 total_pretended_time += p.print_pretended_times()
509 print("Total emerge time of " + green_start + str(len(PACKAGES)) +
510 color_stop + " package(s): "+ give_time(total_pretended_time))
514 usage = """Usage: emerge-timer.py [package] [options]
516 Calculate emerge times from emerge log.
519 \t-c, --current \t Show time until currently compiling package finishes
520 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
521 \t-l, --list \t List all emerged packages
522 \t-h, --help \t Show this helpscreen
523 \t-q, --quiet \t Be less verbose
524 \t--no-color \t Use colorless output
525 \t--simulate \t Do a simulation run"""
532 if __name__ == "__main__":
534 # Set the default mode as "package"
536 input_packages = None
539 for arg in sys.argv[1:]:
541 if arg == "-p" or arg == "--pretended":
544 if arg == "-c" or arg == "--current":
547 if arg == "-h" or arg == "--help":
550 if arg == "-l" or arg == "--list":
551 search_log_for_all_packages()
554 if arg == "-q" or arg == "--quiet":
557 sys.argv.pop(sys.argv.index(arg))
559 if arg == "--no-color":
563 sys.argv.pop(sys.argv.index(arg))
565 if arg == "--simulate":
569 if len(sys.argv) > 1:
570 input_packages = sys.argv[1:]
574 if simulation == True:
576 print(red_start + "\n" + '*'*25 + "\n" + "THIS IS A SIMULATION RUN\n"
579 print("Beginning 'package' mode check")
581 print("Checking for one emerge\n" + color_stop)
583 LOGFILE = "simulate/fake_emerge.log"
584 PORTDIR = "simulate/"
586 main("package", "first_fake_package")
588 print(red_start + "\nChecking for three emerges\n" + color_stop)
590 main("package", "second_fake_package")
592 print(red_start + "\n'package' mode check complete\n")
596 print("\nBeginning 'current' mode check")
597 print("Current emerge with no emerge process\n" + color_stop)
599 main("current", None)
601 print(red_start + "\nCurrent emerge with emerge processes\n" + color_stop)
603 PACKAGES.append(package("test-group/second_fake_package", "2.9-r2"))
604 PACKAGES[0].emerge_time = 60
605 PACKAGES.append(package("test-group/first_fake_package", "1.10.2-r1"))
606 PACKAGES[1].emerge_time = 120
608 main("current", None)
610 print(red_start + "\nCurrent emerge with incomplete emerge log" +
611 "(causes error in some cases)\n" + color_stop)
614 PACKAGES.append(package("test-group/third_fake_package", "2.9-r2"))
616 main("current", None)
618 print(red_start + "\n" + '*'*20 + "\n" + "SIMULATION FINISHED\n" +
623 main(mode, input_packages)