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(green_start + "unknown" + color_stop),
86 print("\n\t " + '-'*45),
88 print("\n\t time to finish:"),
90 if type(self.emerge_time) != str:
92 finish_time = self.average_time() - self.emerge_time
95 print(give_time(finish_time))
97 print(green_start + "any time now" + color_stop)
99 print(green_start + "unknown" + color_stop)
103 def print_versions(self):
104 """This prints the emerge times for different versions in the
105 'package' operating mode of the script"""
112 for p in self.versions:
113 if len(p[0]) > version_length:
114 version_length = len(p[0])
116 if len(give_time(p[1], True)) > time_length:
117 time_length = len(give_time(p[1], True))
119 for p in self.versions:
121 pad = time_length - len(give_time(p[1], True))
123 print('-'*90 + "\n" +
124 green_start + self.name + (p[0]).ljust(version_length) +
125 color_stop + " >>> " + (give_time(p[1])) + " "*pad +
126 " >>> " + give_date(p[2]))
128 print('-'*90 + "\n" + "Package " + green_start +
129 self.name + color_stop + " emerged " +
130 str(len(self.versions)) + " times.")
135 def print_pretended_times(self):
136 """This is used the print all the pretended times"""
139 print("\t" + green_start + self.name + '-' + self.version + color_stop),
141 if len(self.versions) > 1:
142 aver_time = self.average_time()
145 print("\n\taverage time: " + give_time(aver_time))
151 print("\n\t no previous emerges")
156 def print_min_max_ave(self):
157 maxi = self.max_time()
158 mini = self.min_time()
159 average = self.average_time()
160 total = self.total_time()
162 print("Max time: \t" + give_time(maxi) +
163 "\nMin time: \t" + give_time(mini) +
164 "\nAverage time: \t" + give_time(average) +
165 "\nIn total spent " + give_time(total) +
166 " emerging " + green_start + self.name + color_stop)
170 def give_time(time, nocolor=False):
171 """Converts time in seconds to human readable form"""
172 global green_start, color_stop
174 if green_start == "":
181 if type(time) == str:
182 return(green_start + "unknown" + color_stop)
185 days = time/(3600*24)
186 hours = (days - int(days))*24
187 minutes = (hours - int(hours))*60
188 seconds = (minutes - int(minutes))*60
192 minutes = int(minutes)
193 seconds = int(round(seconds))
201 pdays = (green_start + str(days) +
202 color_stop + " day ")
204 pdays = (green_start + str(days) +
205 color_stop + " days ")
208 phours = (green_start + str(hours) +
209 color_stop + " hour ")
211 phours = (green_start + str(hours) +
212 color_stop + " hours ")
215 pminutes = (green_start + str(minutes) +
216 color_stop + " minute ")
218 pminutes = (green_start + str(minutes) +
219 color_stop + " minutes ")
221 pseconds = (green_start + str(seconds) +
222 color_stop + " second ")
224 pseconds = (green_start + str(seconds) +
225 color_stop + " seconds ")
228 green_start = "\033[32m"
229 color_stop = "\033[m"
231 return (pdays + phours + pminutes + pseconds)
235 def give_date(emerge_date):
236 """Returns a date string from a standard POSIX time"""
237 date = datetime.datetime.fromtimestamp(emerge_date)
239 date = "{:%d.%m.%Y %H:%M:%S}".format(date)
246 """Attempt to open the LOGFILE."""
249 f = open(LOGFILE, 'r')
250 except IOError as detail:
258 def search_log_for_package(package_class):
259 """Searchs emerge log for given package and adds all found
260 versions with their emerge times to the class"""
265 if ((">>>" in line) and ("emerge" in line)):
266 if package_class.name in line:
268 version = line.partition(package_class.name)[2].partition(' ')[0]
269 digit = version.strip('-')[0].isdigit()
272 time_string = line.partition(">>>")
273 start_time = float(time_string[0].strip().strip(':'))
275 elif ((":::" in line) and ("completed emerge" in line)):
277 if package_class.name in line:
279 time_string = line.partition(":::")
280 stop_time = float(time_string[0].strip().strip(':'))
282 emerge_time = stop_time - start_time
284 package_class.add_version(version, emerge_time, start_time)
288 def get_package(name):
289 """Take the user-input package name and search for it
292 dirlist = os.listdir(PORTDIR)
293 possible_package = []
296 # If the given name is in the format xxx/zzz
297 # assume that xxx is the package group
299 group = name.partition('/')[0]
300 pkg = name.partition('/')[2]
301 directory = PORTDIR + group
304 dirs = os.listdir(directory)
306 possible_package.append(name)
309 # Go through the directory listing searching for anything
310 # that matches the given name
312 directory = PORTDIR + i
313 if os.path.isdir(directory):
314 dirs = os.listdir(directory)
316 possible_package.append(i + '/' + name)
319 if len(possible_package) > 1:
320 print("Multiple packages found for '" + name + "'.")
321 print("Possible packages: ")
322 for value in possible_package:
326 elif len(possible_package) == 1:
327 package = possible_package[0]
332 print("No package '" + name + "' found")
339 def list_pretended():
340 """List all the pretended packages given by emerge -p
341 output. Create a class out of each of those packages and add them
346 for line in sys.stdin:
347 if "[ebuild" in line:
348 full_name = line.partition("] ")[2].partition(' ')[0]
350 version = full_name.partition('/')[2].partition('-')[2]
351 while not version[0].isdigit():
352 version = version.partition('-')[2]
353 package_name = full_name[:-len(version)-1]
355 PACKAGES.append(package(package_name, version))
359 def list_emerge_processes():
360 """Look for the ebuild process with ps. If the process is found parse
361 the command for the package. With this package search the LOGFILE for
362 the emerge startup time."""
366 now = datetime.datetime.today()
368 for i in os.popen("ps ax"):
369 if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
370 pack = i.partition('[')[2].partition(']')[0]
372 version = pack.partition('/')[2].partition('-')[2]
374 while not version[0].isdigit():
375 version = version.partition('-')[2]
377 package_name = pack[:-len(version)-1]
379 PACKAGES.append(package(package_name, version))
382 if len(PACKAGES) == 0:
383 print "No current emerge process found."
389 if ((">>>" in line) and ("emerge" in line)):
393 if (p.name + '-' + p.version in line):
395 time = float(line.partition(' ')[0].strip(":"))
397 timestamp = datetime.datetime.fromtimestamp(time)
398 difference = (now - timestamp).total_seconds()
400 if ((difference < p.emerge_time) or
401 (p.emerge_time == "infinity")):
403 p.emerge_time = difference
409 def main(status, user_package=None):
410 """Main function. Hanlde all the different modes of operation."""
412 if status == "package":
413 user_package = get_package(user_package)
415 pack = package(user_package)
417 search_log_for_package(pack)
419 if len(pack.versions) != 0:
420 pack.print_versions()
421 pack.print_min_max_ave()
424 print("Package " + green_start + pack.name +
425 color_stop + " has never been emerged.")
428 elif status == "current":
429 if list_emerge_processes():
432 print "Currently emerging:"
435 search_log_for_package(p)
436 p.print_current_emerge()
439 elif status == "pretended":
442 print "This is how long these packages would take to emerge"
444 total_pretended_time = 0
447 search_log_for_package(p)
449 total_pretended_time += p.print_pretended_times()
453 print("Total emerge time of " + green_start + str(len(PACKAGES)) +
454 color_stop + " package(s): "+ give_time(total_pretended_time))
458 usage = """Usage: emerge-timer.py [package] [options]
460 Calculate emerge times from emerge log.
463 \t-c, --current \t Show time until currently compiling package finishes
464 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
465 \t-h, --help \t Show this helpscreen
466 \t-q, --quiet \t Be less verbose
467 \t--no-color \t Use colorless output
468 \t--simulate \t Do a simulation run"""
475 if __name__ == "__main__":
477 # Set the default mode as "package"
482 for arg in sys.argv[1:]:
484 if arg == "-p" or arg == "--pretended":
487 if arg == "-c" or arg == "--current":
490 if arg == "-h" or arg == "--help":
493 if arg == "-q" or arg == "--quiet":
496 if arg == "--no-color":
500 if arg == "--simulate":
504 if len(sys.argv) > 1:
505 input_package = sys.argv[1]
509 if simulation == True:
511 print(red_start + "\n" + '*'*25 + "\n" + "THIS IS A SIMULATION RUN\n"
514 print("Beginning 'package' mode check")
516 print("Checking for one emerge\n" + color_stop)
518 LOGFILE = "simulate/fake_emerge.log"
519 PORTDIR = "simulate/"
521 main("package", "first_fake_package")
523 print(red_start + "\nChecking for three emerges\n" + color_stop)
525 main("package", "second_fake_package")
527 print(red_start + "\n'package' mode check complete\n")
531 print("\nBeginning 'current' mode check")
532 print("Current emerge with no emerge process\n" + color_stop)
534 main("current", None)
536 print(red_start + "\nCurrent emerge with emerge processes\n" + color_stop)
538 PACKAGES.append(package("test-group/second_fake_package", "2.9-r2"))
539 PACKAGES.append(package("test-group/first_fake_package", "1.10.2-r1"))
541 main("current", None)
543 print(red_start + "\n" + '*'*20 + "\n" + "SIMULATION FINISHED\n" +
548 main(mode, input_package)