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 return self.versions[len(self.versions)-1][1]
62 """Return minimum time from class version list"""
65 return self.versions[0][1]
68 def print_current_emerge(self):
69 """Function used to print all the current emerge stuff"""
71 print("\t" + green_start + self.name + '-' + self.version +
72 color_stop + "\n\t current time: " + give_time(self.emerge_time))
75 if len(self.versions) == 1:
76 print("\t last time: "),
77 print(give_time(self.average_time())),
79 elif len(self.versions) > 1:
80 print("\t average time:"),
81 print(give_time(self.average_time())),
84 print("\t average time: " + green_start + "unknown\n" + color_stop),
87 print("\n\t " + '-'*45),
89 print("\n\t time to finish:"),
91 if type(self.emerge_time) != str:
93 finish_time = self.average_time() - self.emerge_time
96 print(give_time(finish_time))
98 print(green_start + "any time now" + color_stop)
100 print(green_start + "unknown" + color_stop)
104 def print_versions(self):
105 """This prints the emerge times for different versions in the
106 'package' operating mode of the script"""
113 for p in self.versions:
114 if len(p[0]) > version_length:
115 version_length = len(p[0])
117 if len(give_time(p[1], True)) > time_length:
118 time_length = len(give_time(p[1], True))
120 for p in self.versions:
122 pad = time_length - len(give_time(p[1], True))
124 print('-'*90 + "\n" +
125 green_start + self.name + (p[0]).ljust(version_length) +
126 color_stop + " >>> " + (give_time(p[1])) + " "*pad +
127 " >>> " + give_date(p[2]))
129 print('-'*90 + "\n" + "Package " + green_start +
130 self.name + color_stop + " emerged " +
131 str(len(self.versions)) + " times.")
136 def print_pretended_times(self):
137 """This is used the print all the pretended times"""
140 print("\t" + green_start + self.name + '-' + self.version + color_stop),
142 if len(self.versions) > 1:
143 aver_time = self.average_time()
146 print("\n\taverage time: " + give_time(aver_time))
152 print("\n\t no previous emerges")
157 def print_min_max_ave(self):
158 maxi = self.max_time()
159 mini = self.min_time()
160 average = self.average_time()
161 total = self.total_time()
163 print("Max time:\t" + give_time(maxi) +
164 "\nMin time:\t" + give_time(mini) +
165 "\nAverage time:\t" + give_time(average) +
166 "\nIn total spent:\t" + give_time(total) +
167 "emerging " + green_start + self.name + color_stop)
171 def give_time(time, nocolor=False):
172 """Converts time in seconds to human readable form"""
173 global green_start, color_stop
175 if green_start == "":
182 if type(time) == str:
183 return(green_start + "unknown" + color_stop)
186 days = time/(3600.0*24.0)
187 hours = (days - int(days))*24.0
188 minutes = (hours - int(hours))*60.0
189 seconds = (minutes - int(minutes))*60.0
193 minutes = int(minutes)
194 seconds = int(round(seconds))
202 pdays = (green_start + str(days) +
203 color_stop + " day ")
205 pdays = (green_start + str(days) +
206 color_stop + " days ")
209 phours = (green_start + str(hours) +
210 color_stop + " hour ")
212 phours = (green_start + str(hours) +
213 color_stop + " hours ")
216 pminutes = (green_start + str(minutes) +
217 color_stop + " minute ")
219 pminutes = (green_start + str(minutes) +
220 color_stop + " minutes ")
223 pseconds = (green_start + str(seconds) +
224 color_stop + " second ")
226 pseconds = (green_start + str(seconds) +
227 color_stop + " seconds ")
230 green_start = "\033[32m"
231 color_stop = "\033[m"
233 return (pdays + phours + pminutes + pseconds)
237 def give_date(emerge_date):
238 """Returns a date string from a standard POSIX time"""
239 date = datetime.datetime.fromtimestamp(emerge_date)
241 date = "{:%d.%m.%Y %H:%M:%S}".format(date)
248 """Attempt to open the LOGFILE."""
251 f = open(LOGFILE, 'r')
252 except IOError as detail:
260 def search_log_for_package(package_class):
261 """Searchs emerge log for given package and adds all found
262 versions with their emerge times to the class"""
267 if ((">>>" in line) and ("emerge" in line)):
268 if package_class.name in line:
270 version = line.partition(package_class.name)[2].partition(' ')[0]
271 digit = version.strip('-')[0].isdigit()
274 time_string = line.partition(">>>")
275 start_time = float(time_string[0].strip().strip(':'))
277 elif ((":::" in line) and ("completed emerge" in line)):
279 if package_class.name in line:
281 time_string = line.partition(":::")
282 stop_time = float(time_string[0].strip().strip(':'))
284 emerge_time = stop_time - start_time
286 package_class.add_version(version, emerge_time, start_time)
290 def get_package(name):
291 """Take the user-input package name and search for it
294 dirlist = os.listdir(PORTDIR)
295 possible_package = []
298 # If the given name is in the format xxx/zzz
299 # assume that xxx is the package group
301 group = name.partition('/')[0]
302 pkg = name.partition('/')[2]
303 directory = PORTDIR + group
306 dirs = os.listdir(directory)
308 possible_package.append(name)
311 # Go through the directory listing searching for anything
312 # that matches the given name
314 directory = PORTDIR + i
315 if os.path.isdir(directory):
316 dirs = os.listdir(directory)
318 possible_package.append(i + '/' + name)
321 if len(possible_package) > 1:
322 print("Multiple packages found for '" + name + "'.")
323 print("Possible packages: ")
324 for value in possible_package:
328 elif len(possible_package) == 1:
329 package = possible_package[0]
334 print("No package '" + name + "' found")
341 def list_pretended():
342 """List all the pretended packages given by emerge -p
343 output. Create a class out of each of those packages and add them
348 for line in sys.stdin:
349 if "[ebuild" in line:
350 full_name = line.partition("] ")[2].partition(' ')[0]
352 version = full_name.partition('/')[2].partition('-')[2]
353 while not version[0].isdigit():
354 version = version.partition('-')[2]
355 package_name = full_name[:-len(version)-1]
357 PACKAGES.append(package(package_name, version))
361 def list_emerge_processes():
362 """Look for the ebuild process with ps. If the process is found parse
363 the command for the package. With this package search the LOGFILE for
364 the emerge startup time."""
368 now = datetime.datetime.today()
370 for i in os.popen("ps ax"):
371 if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
372 pack = i.partition('[')[2].partition(']')[0]
374 version = pack.partition('/')[2].partition('-')[2]
376 while not version[0].isdigit():
377 version = version.partition('-')[2]
379 package_name = pack[:-len(version)-1]
381 PACKAGES.append(package(package_name, version))
384 if len(PACKAGES) == 0:
385 print "No current emerge process found."
391 if ((">>>" in line) and ("emerge" in line)):
395 if (p.name + '-' + p.version in line):
397 time = float(line.partition(' ')[0].strip(":"))
399 timestamp = datetime.datetime.fromtimestamp(time)
400 difference = (now - timestamp).total_seconds()
402 if ((difference < p.emerge_time) or
403 (p.emerge_time == "infinity")):
405 p.emerge_time = difference
411 def main(status, user_package=None):
412 """Main function. Hanlde all the different modes of operation."""
414 if status == "package":
415 user_package = get_package(user_package)
417 pack = package(user_package)
419 search_log_for_package(pack)
421 if len(pack.versions) != 0:
422 pack.print_versions()
423 pack.print_min_max_ave()
426 print("Package " + green_start + pack.name +
427 color_stop + " has never been emerged.")
430 elif status == "current":
431 if list_emerge_processes():
434 print "Currently emerging:"
437 search_log_for_package(p)
438 p.print_current_emerge()
441 elif status == "pretended":
444 print "This is how long these packages would take to emerge"
446 total_pretended_time = 0
449 search_log_for_package(p)
451 total_pretended_time += p.print_pretended_times()
455 print("Total emerge time of " + green_start + str(len(PACKAGES)) +
456 color_stop + " package(s): "+ give_time(total_pretended_time))
460 usage = """Usage: emerge-timer.py [package] [options]
462 Calculate emerge times from emerge log.
465 \t-c, --current \t Show time until currently compiling package finishes
466 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
467 \t-h, --help \t Show this helpscreen
468 \t-q, --quiet \t Be less verbose
469 \t--no-color \t Use colorless output
470 \t--simulate \t Do a simulation run"""
477 if __name__ == "__main__":
479 # Set the default mode as "package"
484 for arg in sys.argv[1:]:
486 if arg == "-p" or arg == "--pretended":
489 if arg == "-c" or arg == "--current":
492 if arg == "-h" or arg == "--help":
495 if arg == "-q" or arg == "--quiet":
498 if arg == "--no-color":
502 if arg == "--simulate":
506 if len(sys.argv) > 1:
507 input_package = sys.argv[1]
511 if simulation == True:
513 print(red_start + "\n" + '*'*25 + "\n" + "THIS IS A SIMULATION RUN\n"
516 print("Beginning 'package' mode check")
518 print("Checking for one emerge\n" + color_stop)
520 LOGFILE = "simulate/fake_emerge.log"
521 PORTDIR = "simulate/"
523 main("package", "first_fake_package")
525 print(red_start + "\nChecking for three emerges\n" + color_stop)
527 main("package", "second_fake_package")
529 print(red_start + "\n'package' mode check complete\n")
533 print("\nBeginning 'current' mode check")
534 print("Current emerge with no emerge process\n" + color_stop)
536 main("current", None)
538 print(red_start + "\nCurrent emerge with emerge processes\n" + color_stop)
540 PACKAGES.append(package("test-group/second_fake_package", "2.9-r2"))
541 PACKAGES[0].emerge_time = 60
542 PACKAGES.append(package("test-group/first_fake_package", "1.10.2-r1"))
543 PACKAGES[1].emerge_time = 120
545 main("current", None)
547 print(red_start + "\nCurrent emerge with incomplete emerge log" +
548 "(causes error in some cases)\n" + color_stop)
551 PACKAGES.append(package("test-group/third_fake_package", "2.9-r2"))
553 main("current", None)
555 print(red_start + "\n" + '*'*20 + "\n" + "SIMULATION FINISHED\n" +
560 main(mode, input_package)