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)
305 def search_log_for_all_packages():
306 """Goes through the emerge.log and lists all packages in there"""
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_start + p[0] + color_stop)
326 all_packages.pop(all_packages.index(p))
329 def get_package(name):
330 """Take the user-input package name and search for it
333 dirlist = os.listdir(PORTDIR)
334 possible_package = []
337 # If the given name is in the format xxx/zzz
338 # assume that xxx is the package group
340 group = name.partition('/')[0]
341 pkg = name.partition('/')[2]
342 directory = PORTDIR + group
345 dirs = os.listdir(directory)
347 possible_package.append(name)
350 # Go through the directory listing searching for anything
351 # that matches the given name
353 directory = PORTDIR + i
354 if os.path.isdir(directory):
355 dirs = os.listdir(directory)
357 possible_package.append(i + '/' + name)
360 if len(possible_package) > 1:
361 print("Multiple packages found for '" + name + "'.")
362 print("Possible packages: ")
363 for value in possible_package:
367 elif len(possible_package) == 1:
368 package = possible_package[0]
373 print("No package '" + name + "' found")
380 def list_pretended():
381 """List all the pretended packages given by emerge -p
382 output. Create a class out of each of those packages and add them
387 for line in sys.stdin:
388 if "[ebuild" in line:
389 full_name = line.partition("] ")[2].partition(' ')[0]
391 version = full_name.partition('/')[2].partition('-')[2]
392 while not version[0].isdigit():
393 version = version.partition('-')[2]
394 package_name = full_name[:-len(version)-1]
396 PACKAGES.append(package(package_name, version))
400 def list_emerge_processes():
401 """Look for the ebuild process with ps. If the process is found parse
402 the command for the package. With this package search the LOGFILE for
403 the emerge startup time."""
407 now = datetime.datetime.today()
409 for i in os.popen("ps ax"):
410 if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
411 pack = i.partition('[')[2].partition(']')[0]
413 version = pack.partition('/')[2].partition('-')[2]
415 while not version[0].isdigit():
416 version = version.partition('-')[2]
418 package_name = pack[:-len(version)-1]
420 PACKAGES.append(package(package_name, version))
423 if len(PACKAGES) == 0:
424 print "No current emerge process found."
430 if ((">>>" in line) and ("emerge" in line)):
434 if (p.name + '-' + p.version in line):
436 time = float(line.partition(' ')[0].strip(":"))
438 timestamp = datetime.datetime.fromtimestamp(time)
439 difference = (now - timestamp).total_seconds()
441 if ((difference < p.emerge_time) or
442 (p.emerge_time == "infinity")):
444 p.emerge_time = difference
450 def main(status, user_package=None):
451 """Main function. Hanlde all the different modes of operation."""
453 if status == "package":
454 for p in user_package:
455 pack = get_package(p)
459 search_log_for_package(pack)
461 if len(pack.versions) != 0:
462 pack.print_versions()
463 pack.print_min_max_ave()
466 print("Package " + green_start + pack.name +
467 color_stop + " has never been emerged.")
472 elif status == "current":
473 if list_emerge_processes():
476 print "Currently emerging:"
479 search_log_for_package(p)
480 p.print_current_emerge()
483 elif status == "pretended":
486 print "This is how long these packages would take to emerge"
488 total_pretended_time = 0
491 search_log_for_package(p)
493 total_pretended_time += p.print_pretended_times()
497 print("Total emerge time of " + green_start + str(len(PACKAGES)) +
498 color_stop + " package(s): "+ give_time(total_pretended_time))
502 usage = """Usage: emerge-timer.py [package] [options]
504 Calculate emerge times from emerge log.
507 \t-c, --current \t Show time until currently compiling package finishes
508 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
509 \t-l, --list \t List all emerged packages
510 \t-h, --help \t Show this helpscreen
511 \t-q, --quiet \t Be less verbose
512 \t--no-color \t Use colorless output
513 \t--simulate \t Do a simulation run"""
520 if __name__ == "__main__":
522 # Set the default mode as "package"
524 input_packages = None
527 for arg in sys.argv[1:]:
529 if arg == "-p" or arg == "--pretended":
532 if arg == "-c" or arg == "--current":
535 if arg == "-h" or arg == "--help":
538 if arg == "-l" or arg == "--list":
539 search_log_for_all_packages()
542 if arg == "-q" or arg == "--quiet":
545 sys.argv.pop(sys.argv.index(arg))
547 if arg == "--no-color":
551 sys.argv.pop(sys.argv.index(arg))
553 if arg == "--simulate":
557 if len(sys.argv) > 1:
558 input_packages = sys.argv[1:]
562 if simulation == True:
564 print(red_start + "\n" + '*'*25 + "\n" + "THIS IS A SIMULATION RUN\n"
567 print("Beginning 'package' mode check")
569 print("Checking for one emerge\n" + color_stop)
571 LOGFILE = "simulate/fake_emerge.log"
572 PORTDIR = "simulate/"
574 main("package", "first_fake_package")
576 print(red_start + "\nChecking for three emerges\n" + color_stop)
578 main("package", "second_fake_package")
580 print(red_start + "\n'package' mode check complete\n")
584 print("\nBeginning 'current' mode check")
585 print("Current emerge with no emerge process\n" + color_stop)
587 main("current", None)
589 print(red_start + "\nCurrent emerge with emerge processes\n" + color_stop)
591 PACKAGES.append(package("test-group/second_fake_package", "2.9-r2"))
592 PACKAGES[0].emerge_time = 60
593 PACKAGES.append(package("test-group/first_fake_package", "1.10.2-r1"))
594 PACKAGES[1].emerge_time = 120
596 main("current", None)
598 print(red_start + "\nCurrent emerge with incomplete emerge log" +
599 "(causes error in some cases)\n" + color_stop)
602 PACKAGES.append(package("test-group/third_fake_package", "2.9-r2"))
604 main("current", None)
606 print(red_start + "\n" + '*'*20 + "\n" + "SIMULATION FINISHED\n" +
611 main(mode, input_packages)