4 import sys, datetime, os
7 PORTDIR = "/usr/portage/"
8 LOGFILE = "/var/log/emerge.log"
11 green_start = "\033[32m"
20 def __init__(self, name, version=0):
22 self.version = version
24 self.emerge_time = 12*3600
27 def add_version(self, version, emerge_time, emerge_date):
28 """Add version to the class version list"""
29 self.versions.append((version, emerge_time, emerge_date))
32 def average_time(self):
33 """Return average time from class version list"""
35 for i in self.versions:
38 average_time = total_time/len(self.versions)
44 """Return total time from class version list"""
46 for i in self.versions:
53 """Return maximum time from class version list"""
56 return self.versions[len(self.versions)-1][1]
60 """Return minimum time from class version list"""
63 return self.versions[0][1]
66 def print_current_emerge(self):
67 """Function used to print all the current emerge stuff"""
69 print("\t" + green_start + self.name + '-' + self.version +
70 color_stop + "\n\t current time: " + self.time(self.emerge_time) +
71 "\n\t average time: "),
73 if len(self.versions) > 1:
74 print(self.time(self.average_time())),
78 print("\n\t " + '-'*45),
80 finish_time = self.average_time() - self.emerge_time
82 print("\n\t time to finish: "),
85 print(self.time(finish_time))
90 def print_versions(self):
91 """This prints the emerge times for different versions in the
92 normal operating mode of the script"""
94 for p in self.versions:
97 green_start + self.name + p[0] + color_stop + " >>> " +
98 self.time(p[1]) + " >>> " +
101 print('-'*90 + "\n" + "Package " + green_start +
102 self.name + color_stop + " emerged " +
103 str(len(self.versions)) + " times.")
108 def print_pretended_times(self):
109 """This is used the print all the pretended times"""
110 print("\t" + green_start + self.name + '-' + self.version + color_stop),
112 if len(self.versions) > 1:
113 print("\n\taverage time: " + self.time(self.average_time()))
115 print("\n\t no previous emerges")
118 def print_min_max_ave(self):
119 maxi = self.max_time()
120 mini = self.min_time()
121 average = self.average_time()
122 total = self.total_time()
124 print("Max time: \t" + self.time(maxi) +
125 "\nMin time: \t" + self.time(mini) +
126 "\nAverage time: \t" + self.time(average) +
127 "\nIn total spent " + self.time(total) +
128 " emerging " + green_start + self.name + color_stop)
131 def time(self, time):
132 """Converts time in seconds to human readable form"""
133 days = time/(3600*24)
134 hours = (days - int(days))*24
135 minutes = (hours - int(hours))*60
136 seconds = (minutes - int(minutes))*60
140 minutes = int(minutes)
141 seconds = int(round(seconds))
149 pdays = (green_start + str(days) +
150 color_stop + " day ")
152 pdays = (green_start + str(days) +
153 color_stop + " days ")
156 phours = (green_start + str(hours) +
157 color_stop + " hour ")
159 phours = (green_start + str(hours) +
160 color_stop + " hours ")
163 pminutes = (green_start + str(minutes) +
164 color_stop + " minute ")
166 pminutes = (green_start + str(minutes) +
167 color_stop + " minutes ")
169 pseconds = (green_start + str(seconds) +
170 color_stop + " second ")
172 pseconds = (green_start + str(seconds) +
173 color_stop + " seconds ")
175 return (pdays + phours + pminutes + pseconds)
178 def date(self, emerge_date):
179 """Returns a date string from a standard POSIX time"""
180 date = datetime.datetime.fromtimestamp(emerge_date)
182 date = "{:%d.%m.%Y %H:%M:%S}".format(date)
189 """Attempt to open the LOGFILE."""
192 f = open(LOGFILE, 'r')
193 except IOError as detail:
201 def search_log_for_package(package_class):
202 """Searchs emerge log for given package and adds all found
203 versions with their emerge times to the class"""
208 if ((">>>" in line) and ("emerge" in line)):
209 if package_class.name in line:
211 version = line.partition(package_class.name)[2].partition(' ')[0]
212 digit = version.strip('-')[0].isdigit()
215 time_string = line.partition(">>>")
216 start_time = float(time_string[0].strip().strip(':'))
218 elif ((":::" in line) and ("completed emerge" in line)):
220 if package_class.name in line:
222 time_string = line.partition(":::")
223 stop_time = float(time_string[0].strip().strip(':'))
225 emerge_time = stop_time - start_time
227 package_class.add_version(version, emerge_time, start_time)
231 def get_package(name):
232 """Take the user-input package name and search for it
235 dirlist = os.listdir(PORTDIR)
236 possible_package = []
239 # If the given name is in the format xxx/zzz
240 # assume that xxx is the package group
242 group = name.partition('/')[0]
243 pkg = name.partition('/')[2]
244 directory = PORTDIR + group
247 dirs = os.listdir(directory)
249 possible_package.append(name)
252 # Go through the directory listing searching for anything
253 # that matches the given name
255 directory = PORTDIR + i
256 if os.path.isdir(directory):
257 dirs = os.listdir(directory)
259 possible_package.append(i + '/' + name)
262 if len(possible_package) > 1:
263 print("Multiple packages found for '" + name + "'.")
264 print("Possible packages: ")
265 for value in possible_package:
269 elif len(possible_package) == 1:
270 package = possible_package[0]
275 print("No package '" + name + "' found")
282 def list_pretended():
283 """List all the pretended packages given by emerge -p
284 output. Create a class out of each of those packages and add them
289 for line in sys.stdin:
290 if "[ebuild" in line:
291 full_name = line.partition("] ")[2].partition(' ')[0]
293 version = full_name.partition('/')[2].partition('-')[2]
294 while not version[0].isdigit():
295 version = version.partition('-')[2]
296 package_name = full_name[:-len(version)-1]
298 packages.append(package(package_name, version))
302 def list_emerge_processes():
303 """Look for the ebuild process with ps. If the process is found parse
304 the command for the package. With this package search the LOGFILE for
305 the emerge startup time."""
309 now = datetime.datetime.today()
311 for i in os.popen("ps ax"):
312 if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
313 pack = i.partition('[')[2].partition(']')[0]
315 version = pack.partition('/')[2].partition('-')[2]
317 while not version[0].isdigit():
318 version = version.partition('-')[2]
320 package_name = pack[:-len(version)-1]
322 packages.append(package(package_name, version))
325 if len(packages) == 0:
326 print "No current emerge process found."
331 if ((">>>" in line) and ("emerge" in line)):
333 if (p.name + '-' + p.version in line):
335 time = float(line.partition(' ')[0].strip(":"))
337 timestamp = datetime.datetime.fromtimestamp(time)
338 difference = (now - timestamp).total_seconds()
340 if difference < p.emerge_time:
341 p.emerge_time = difference
345 def main(status, user_package=None):
346 """Main function. Hanlde all the different modes of operation."""
348 if status == "package":
349 user_package = get_package(user_package)
351 pack = package(user_package)
353 search_log_for_package(pack)
354 pack.print_versions()
355 pack.print_min_max_ave()
358 elif status == "current":
359 list_emerge_processes()
361 print "Currently emerging:"
364 search_log_for_package(p)
365 p.print_current_emerge()
368 elif status == "pretended":
371 print "This is how long these packages would take to emerge"
374 search_log_for_package(p)
375 p.print_pretended_times()
381 usage = """Usage: emerge-timer.py [package] [options]
383 Calculate emerge times from emerge log.
386 \t-c, --current \t Show time until currently compiling package finishes
387 \t-p, --pretended Calculate compile time from piped 'emerge -p' output
388 \t-h, --help \t Show this helpscreen
390 \t--no-color \t Use colorless output"""
397 if __name__ == "__main__":
399 # Set the default mode as "package"
404 for arg in sys.argv[1:]:
406 if arg == "-p" or arg == "--pretended":
409 if arg == "-c" or arg == "--current":
412 if arg == "-h" or arg == "--help":
415 if arg == "--no-color":
420 if len(sys.argv) > 1:
421 input_package = sys.argv[1]
425 main(mode, input_package)