4 import sys, datetime, os
7 PORTDIR = "/usr/portage/"
8 LOGFILE = "/var/log/emerge.log"
11 green_start = "\033[32m"
21 def __init__(self, name, version=0):
23 self.version = version
25 self.emerge_time = 12*3600
28 def add_version(self, version, emerge_time, emerge_date):
29 """Add version to the class version list"""
30 self.versions.append((version, emerge_time, emerge_date))
33 def average_time(self):
34 """Return average time from class version list"""
36 for i in self.versions:
39 average_time = total_time/len(self.versions)
45 """Return total time from class version list"""
47 for i in self.versions:
54 """Return maximum time from class version list"""
57 return self.versions[len(self.versions)-1][1]
61 """Return minimum time from class version list"""
64 return self.versions[0][1]
67 def print_current_emerge(self):
68 """Function used to print all the current emerge stuff"""
70 print("\t" + green_start + self.name + '-' + self.version +
71 color_stop + "\n\t current time: " + give_time(self.emerge_time) +
72 "\n\t average time: "),
74 if len(self.versions) > 1:
75 print(give_time(self.average_time())),
79 print("\n\t " + '-'*45),
81 finish_time = self.average_time() - self.emerge_time
83 print("\n\t time to finish: "),
86 print(give_time(finish_time))
92 def print_versions(self):
93 """This prints the emerge times for different versions in the
94 normal operating mode of the script"""
101 for p in self.versions:
102 if len(p[0]) > version_length:
103 version_length = len(p[0])
105 if len(give_time(p[1])) > time_length:
106 time_length = len(give_time(p[1]))
108 for p in self.versions:
110 print('-'*90 + "\n" +
111 green_start + self.name + (p[0]).ljust(version_length) +
112 color_stop + " >>> " + (give_time(p[1])).ljust(time_length)
113 + " >>> " + give_date(p[2]))
115 print('-'*90 + "\n" + "Package " + green_start +
116 self.name + color_stop + " emerged " +
117 str(len(self.versions)) + " times.")
122 def print_pretended_times(self):
123 """This is used the print all the pretended times"""
126 print("\t" + green_start + self.name + '-' + self.version + color_stop),
128 if len(self.versions) > 1:
129 aver_time = self.average_time()
132 print("\n\taverage time: " + give_time(aver_time))
138 print("\n\t no previous emerges")
143 def print_min_max_ave(self):
144 maxi = self.max_time()
145 mini = self.min_time()
146 average = self.average_time()
147 total = self.total_time()
149 print("Max time: \t" + give_time(maxi) +
150 "\nMin time: \t" + give_time(mini) +
151 "\nAverage time: \t" + give_time(average) +
152 "\nIn total spent " + give_time(total) +
153 " emerging " + green_start + self.name + color_stop)
158 """Converts time in seconds to human readable form"""
159 days = time/(3600*24)
160 hours = (days - int(days))*24
161 minutes = (hours - int(hours))*60
162 seconds = (minutes - int(minutes))*60
166 minutes = int(minutes)
167 seconds = int(round(seconds))
175 pdays = (green_start + str(days) +
176 color_stop + " day ")
178 pdays = (green_start + str(days) +
179 color_stop + " days ")
182 phours = (green_start + str(hours) +
183 color_stop + " hour ")
185 phours = (green_start + str(hours) +
186 color_stop + " hours ")
189 pminutes = (green_start + str(minutes) +
190 color_stop + " minute ")
192 pminutes = (green_start + str(minutes) +
193 color_stop + " minutes ")
195 pseconds = (green_start + str(seconds) +
196 color_stop + " second ")
198 pseconds = (green_start + str(seconds) +
199 color_stop + " seconds ")
201 return (pdays + phours + pminutes + pseconds)
205 def give_date(emerge_date):
206 """Returns a date string from a standard POSIX time"""
207 date = datetime.datetime.fromtimestamp(emerge_date)
209 date = "{:%d.%m.%Y %H:%M:%S}".format(date)
216 """Attempt to open the LOGFILE."""
219 f = open(LOGFILE, 'r')
220 except IOError as detail:
228 def search_log_for_package(package_class):
229 """Searchs emerge log for given package and adds all found
230 versions with their emerge times to the class"""
235 if ((">>>" in line) and ("emerge" in line)):
236 if package_class.name in line:
238 version = line.partition(package_class.name)[2].partition(' ')[0]
239 digit = version.strip('-')[0].isdigit()
242 time_string = line.partition(">>>")
243 start_time = float(time_string[0].strip().strip(':'))
245 elif ((":::" in line) and ("completed emerge" in line)):
247 if package_class.name in line:
249 time_string = line.partition(":::")
250 stop_time = float(time_string[0].strip().strip(':'))
252 emerge_time = stop_time - start_time
254 package_class.add_version(version, emerge_time, start_time)
258 def get_package(name):
259 """Take the user-input package name and search for it
262 dirlist = os.listdir(PORTDIR)
263 possible_package = []
266 # If the given name is in the format xxx/zzz
267 # assume that xxx is the package group
269 group = name.partition('/')[0]
270 pkg = name.partition('/')[2]
271 directory = PORTDIR + group
274 dirs = os.listdir(directory)
276 possible_package.append(name)
279 # Go through the directory listing searching for anything
280 # that matches the given name
282 directory = PORTDIR + i
283 if os.path.isdir(directory):
284 dirs = os.listdir(directory)
286 possible_package.append(i + '/' + name)
289 if len(possible_package) > 1:
290 print("Multiple packages found for '" + name + "'.")
291 print("Possible packages: ")
292 for value in possible_package:
296 elif len(possible_package) == 1:
297 package = possible_package[0]
302 print("No package '" + name + "' found")
309 def list_pretended():
310 """List all the pretended packages given by emerge -p
311 output. Create a class out of each of those packages and add them
316 for line in sys.stdin:
317 if "[ebuild" in line:
318 full_name = line.partition("] ")[2].partition(' ')[0]
320 version = full_name.partition('/')[2].partition('-')[2]
321 while not version[0].isdigit():
322 version = version.partition('-')[2]
323 package_name = full_name[:-len(version)-1]
325 PACKAGES.append(package(package_name, version))
329 def list_emerge_processes():
330 """Look for the ebuild process with ps. If the process is found parse
331 the command for the package. With this package search the LOGFILE for
332 the emerge startup time."""
336 now = datetime.datetime.today()
338 for i in os.popen("ps ax"):
339 if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
340 pack = i.partition('[')[2].partition(']')[0]
342 version = pack.partition('/')[2].partition('-')[2]
344 while not version[0].isdigit():
345 version = version.partition('-')[2]
347 package_name = pack[:-len(version)-1]
349 PACKAGES.append(package(package_name, version))
352 if len(PACKAGES) == 0:
353 print "No current emerge process found."
358 if ((">>>" in line) and ("emerge" in line)):
360 if (p.name + '-' + p.version in line):
362 time = float(line.partition(' ')[0].strip(":"))
364 timestamp = datetime.datetime.fromtimestamp(time)
365 difference = (now - timestamp).total_seconds()
367 if difference < p.emerge_time:
368 p.emerge_time = difference
372 def main(status, user_package=None):
373 """Main function. Hanlde all the different modes of operation."""
375 if status == "package":
376 user_package = get_package(user_package)
378 pack = package(user_package)
380 search_log_for_package(pack)
381 pack.print_versions()
382 pack.print_min_max_ave()
385 elif status == "current":
386 list_emerge_processes()
388 print "Currently emerging:"
391 search_log_for_package(p)
392 p.print_current_emerge()
395 elif status == "pretended":
398 print "This is how long these packages would take to emerge"
400 total_pretended_time = 0
403 search_log_for_package(p)
405 total_pretended_time += p.print_pretended_times()
409 print("Total emerge time of " + green_start + str(len(PACKAGES)) +
410 color_stop + " package(s): "+ give_time(total_pretended_time))
414 usage = """Usage: emerge-timer.py [package] [options]
416 Calculate emerge times from emerge log.
419 \t-c, --current \t Show time until currently compiling package finishes
420 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
421 \t-h, --help \t Show this helpscreen
422 \t-q, --quiet \t Be less verbose
423 \t--no-color \t Use colorless output"""
430 if __name__ == "__main__":
432 # Set the default mode as "package"
437 for arg in sys.argv[1:]:
439 if arg == "-p" or arg == "--pretended":
442 if arg == "-c" or arg == "--current":
445 if arg == "-h" or arg == "--help":
448 if arg == "-q" or arg == "--quiet":
451 if arg == "--no-color":
456 if len(sys.argv) > 1:
457 input_package = sys.argv[1]
461 main(mode, input_package)