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 user_package = get_package(user_package)
434 pack = package(user_package)
436 search_log_for_package(pack)
438 if len(pack.versions) != 0:
439 pack.print_versions()
440 pack.print_min_max_ave()
443 print("Package " + green_start + pack.name +
444 color_stop + " has never been emerged.")
447 elif status == "current":
448 if list_emerge_processes():
451 print "Currently emerging:"
454 search_log_for_package(p)
455 p.print_current_emerge()
458 elif status == "pretended":
461 print "This is how long these packages would take to emerge"
463 total_pretended_time = 0
466 search_log_for_package(p)
468 total_pretended_time += p.print_pretended_times()
472 print("Total emerge time of " + green_start + str(len(PACKAGES)) +
473 color_stop + " package(s): "+ give_time(total_pretended_time))
477 usage = """Usage: emerge-timer.py [package] [options]
479 Calculate emerge times from emerge log.
482 \t-c, --current \t Show time until currently compiling package finishes
483 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
484 \t-h, --help \t Show this helpscreen
485 \t-q, --quiet \t Be less verbose
486 \t--no-color \t Use colorless output
487 \t--simulate \t Do a simulation run"""
494 if __name__ == "__main__":
496 # Set the default mode as "package"
501 for arg in sys.argv[1:]:
503 if arg == "-p" or arg == "--pretended":
506 if arg == "-c" or arg == "--current":
509 if arg == "-h" or arg == "--help":
512 if arg == "-q" or arg == "--quiet":
515 if arg == "--no-color":
519 if arg == "--simulate":
523 if len(sys.argv) > 1:
524 input_package = sys.argv[1]
528 if simulation == True:
530 print(red_start + "\n" + '*'*25 + "\n" + "THIS IS A SIMULATION RUN\n"
533 print("Beginning 'package' mode check")
535 print("Checking for one emerge\n" + color_stop)
537 LOGFILE = "simulate/fake_emerge.log"
538 PORTDIR = "simulate/"
540 main("package", "first_fake_package")
542 print(red_start + "\nChecking for three emerges\n" + color_stop)
544 main("package", "second_fake_package")
546 print(red_start + "\n'package' mode check complete\n")
550 print("\nBeginning 'current' mode check")
551 print("Current emerge with no emerge process\n" + color_stop)
553 main("current", None)
555 print(red_start + "\nCurrent emerge with emerge processes\n" + color_stop)
557 PACKAGES.append(package("test-group/second_fake_package", "2.9-r2"))
558 PACKAGES[0].emerge_time = 60
559 PACKAGES.append(package("test-group/first_fake_package", "1.10.2-r1"))
560 PACKAGES[1].emerge_time = 120
562 main("current", None)
564 print(red_start + "\nCurrent emerge with incomplete emerge log" +
565 "(causes error in some cases)\n" + color_stop)
568 PACKAGES.append(package("test-group/third_fake_package", "2.9-r2"))
570 main("current", None)
572 print(red_start + "\n" + '*'*20 + "\n" + "SIMULATION FINISHED\n" +
577 main(mode, input_package)