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 get_package(name):
308 """Take the user-input package name and search for it
311 dirlist = os.listdir(PORTDIR)
312 possible_package = []
315 # If the given name is in the format xxx/zzz
316 # assume that xxx is the package group
318 group = name.partition('/')[0]
319 pkg = name.partition('/')[2]
320 directory = PORTDIR + group
323 dirs = os.listdir(directory)
325 possible_package.append(name)
328 # Go through the directory listing searching for anything
329 # that matches the given name
331 directory = PORTDIR + i
332 if os.path.isdir(directory):
333 dirs = os.listdir(directory)
335 possible_package.append(i + '/' + name)
338 if len(possible_package) > 1:
339 print("Multiple packages found for '" + name + "'.")
340 print("Possible packages: ")
341 for value in possible_package:
345 elif len(possible_package) == 1:
346 package = possible_package[0]
351 print("No package '" + name + "' found")
358 def list_pretended():
359 """List all the pretended packages given by emerge -p
360 output. Create a class out of each of those packages and add them
365 for line in sys.stdin:
366 if "[ebuild" in line:
367 full_name = line.partition("] ")[2].partition(' ')[0]
369 version = full_name.partition('/')[2].partition('-')[2]
370 while not version[0].isdigit():
371 version = version.partition('-')[2]
372 package_name = full_name[:-len(version)-1]
374 PACKAGES.append(package(package_name, version))
378 def list_emerge_processes():
379 """Look for the ebuild process with ps. If the process is found parse
380 the command for the package. With this package search the LOGFILE for
381 the emerge startup time."""
385 now = datetime.datetime.today()
387 for i in os.popen("ps ax"):
388 if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
389 pack = i.partition('[')[2].partition(']')[0]
391 version = pack.partition('/')[2].partition('-')[2]
393 while not version[0].isdigit():
394 version = version.partition('-')[2]
396 package_name = pack[:-len(version)-1]
398 PACKAGES.append(package(package_name, version))
401 if len(PACKAGES) == 0:
402 print "No current emerge process found."
408 if ((">>>" in line) and ("emerge" in line)):
412 if (p.name + '-' + p.version in line):
414 time = float(line.partition(' ')[0].strip(":"))
416 timestamp = datetime.datetime.fromtimestamp(time)
417 difference = (now - timestamp).total_seconds()
419 if ((difference < p.emerge_time) or
420 (p.emerge_time == "infinity")):
422 p.emerge_time = difference
428 def main(status, user_package=None):
429 """Main function. Hanlde all the different modes of operation."""
431 if status == "package":
432 for p in user_package:
433 pack = get_package(p)
437 search_log_for_package(pack)
439 if len(pack.versions) != 0:
440 pack.print_versions()
441 pack.print_min_max_ave()
444 print("Package " + green_start + pack.name +
445 color_stop + " has never been emerged.")
450 elif status == "current":
451 if list_emerge_processes():
454 print "Currently emerging:"
457 search_log_for_package(p)
458 p.print_current_emerge()
461 elif status == "pretended":
464 print "This is how long these packages would take to emerge"
466 total_pretended_time = 0
469 search_log_for_package(p)
471 total_pretended_time += p.print_pretended_times()
475 print("Total emerge time of " + green_start + str(len(PACKAGES)) +
476 color_stop + " package(s): "+ give_time(total_pretended_time))
480 usage = """Usage: emerge-timer.py [package] [options]
482 Calculate emerge times from emerge log.
485 \t-c, --current \t Show time until currently compiling package finishes
486 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
487 \t-h, --help \t Show this helpscreen
488 \t-q, --quiet \t Be less verbose
489 \t--no-color \t Use colorless output
490 \t--simulate \t Do a simulation run"""
497 if __name__ == "__main__":
499 # Set the default mode as "package"
501 input_packages = None
504 for arg in sys.argv[1:]:
506 if arg == "-p" or arg == "--pretended":
509 if arg == "-c" or arg == "--current":
512 if arg == "-h" or arg == "--help":
515 if arg == "-q" or arg == "--quiet":
518 sys.argv.pop(sys.argv.index(arg))
520 if arg == "--no-color":
524 sys.argv.pop(sys.argv.index(arg))
526 if arg == "--simulate":
530 if len(sys.argv) > 1:
531 input_packages = sys.argv[1:]
535 if simulation == True:
537 print(red_start + "\n" + '*'*25 + "\n" + "THIS IS A SIMULATION RUN\n"
540 print("Beginning 'package' mode check")
542 print("Checking for one emerge\n" + color_stop)
544 LOGFILE = "simulate/fake_emerge.log"
545 PORTDIR = "simulate/"
547 main("package", "first_fake_package")
549 print(red_start + "\nChecking for three emerges\n" + color_stop)
551 main("package", "second_fake_package")
553 print(red_start + "\n'package' mode check complete\n")
557 print("\nBeginning 'current' mode check")
558 print("Current emerge with no emerge process\n" + color_stop)
560 main("current", None)
562 print(red_start + "\nCurrent emerge with emerge processes\n" + color_stop)
564 PACKAGES.append(package("test-group/second_fake_package", "2.9-r2"))
565 PACKAGES[0].emerge_time = 60
566 PACKAGES.append(package("test-group/first_fake_package", "1.10.2-r1"))
567 PACKAGES[1].emerge_time = 120
569 main("current", None)
571 print(red_start + "\nCurrent emerge with incomplete emerge log" +
572 "(causes error in some cases)\n" + color_stop)
575 PACKAGES.append(package("test-group/third_fake_package", "2.9-r2"))
577 main("current", None)
579 print(red_start + "\n" + '*'*20 + "\n" + "SIMULATION FINISHED\n" +
584 main(mode, input_packages)