]> git.itanic.dy.fi Git - emerge-timer/blob - emerge-timer.py
Drop time() and date() from the class
[emerge-timer] / emerge-timer.py
1 #!/usr/bin/python
2
3
4 import sys, datetime, os
5
6
7 PORTDIR = "/usr/portage/"
8 LOGFILE = "/var/log/emerge.log"
9
10
11 green_start = "\033[32m"
12 color_stop = "\033[m"
13
14
15 PACKAGES = []
16
17
18
19 class package:
20     def __init__(self, name, version=0):
21         self.name = name
22         self.version = version
23         self.versions = []
24         self.emerge_time = 12*3600
25
26
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))
30
31
32     def average_time(self):
33         """Return average time from class version list"""
34         total_time = 0
35         for i in self.versions:
36             total_time += i[1]
37
38         average_time = total_time/len(self.versions)
39
40         return average_time
41
42
43     def total_time(self):
44         """Return total time from class version list"""
45         total_time = 0
46         for i in self.versions:
47             total_time += i[1]
48
49         return total_time
50
51
52     def max_time(self):
53         """Return maximum time from class version list"""
54         self.versions.sort()
55
56         return self.versions[len(self.versions)-1][1]
57
58
59     def min_time(self):
60         """Return minimum time from class version list"""
61         self.versions.sort()
62
63         return self.versions[0][1]
64
65
66     def print_current_emerge(self):
67         """Function used to print all the current emerge stuff"""
68
69         print("\t" + green_start + self.name + '-' + self.version +
70               color_stop + "\n\t current time: " + time(self.emerge_time) +
71               "\n\t average time: "),
72
73         if len(self.versions) > 1:
74             print(time(self.average_time())),
75         else:
76             print("unknown"),
77
78         print("\n\t " + '-'*45),
79
80         finish_time = self.average_time() - self.emerge_time
81
82         print("\n\t time to finish: "),
83
84         if finish_time > 0:
85             print(time(finish_time))
86         else:
87             print("any time now")
88
89
90     def print_versions(self):
91         """This prints the emerge times for different versions in the
92         normal operating mode of the script"""
93
94         for p in self.versions:
95
96             print('-'*90 + "\n" +
97                   green_start + self.name + p[0] + color_stop + "  >>>  " +
98                   time(p[1]) + "  >>>  " + date(p[2]))
99
100         print('-'*90 + "\n" + "Package " + green_start +
101               self.name + color_stop + " emerged " +
102               str(len(self.versions)) + " times.")
103
104         print
105
106
107     def print_pretended_times(self):
108         """This is used the print all the pretended times"""
109         print("\t" + green_start + self.name + '-' + self.version + color_stop),
110
111         if len(self.versions) > 1:
112             print("\n\taverage time: " + time(self.average_time()))
113         else:
114             print("\n\t no previous emerges")
115
116
117     def print_min_max_ave(self):
118         maxi = self.max_time()
119         mini = self.min_time()
120         average = self.average_time()
121         total = self.total_time()
122
123         print("Max time: \t" + time(maxi) +
124               "\nMin time: \t" + time(mini) +
125               "\nAverage time: \t" + time(average) +
126               "\nIn total spent " + time(total) +
127               " emerging " + green_start + self.name + color_stop)
128
129
130 def time(time):
131     """Converts time in seconds to human readable form"""
132     days = time/(3600*24)
133     hours = (days - int(days))*24
134     minutes = (hours - int(hours))*60
135     seconds = (minutes - int(minutes))*60
136
137     days = int(days)
138     hours = int(hours)
139     minutes = int(minutes)
140     seconds = int(round(seconds))
141
142     pdays = str()
143     phours = str()
144     pminutes = str()
145     pseconds = str()
146
147     if days > 0:
148         pdays = (green_start + str(days) +
149                  color_stop + " day ")
150         if days != 1:
151             pdays = (green_start + str(days) +
152                          color_stop + " days ")
153
154     if hours > 0:
155         phours = (green_start + str(hours) +
156                   color_stop + " hour ")
157         if hours != 1:
158             phours = (green_start + str(hours) +
159                           color_stop + " hours ")
160
161     if minutes > 0:
162         pminutes = (green_start + str(minutes) +
163                     color_stop + " minute ")
164         if minutes != 1:
165             pminutes = (green_start + str(minutes) +
166                         color_stop + " minutes ")
167
168     pseconds = (green_start + str(seconds) +
169                 color_stop + " second ")
170     if seconds != 1:
171         pseconds = (green_start + str(seconds) +
172                     color_stop + " seconds ")
173
174     return (pdays + phours + pminutes + pseconds)
175
176
177 def date(emerge_date):
178     """Returns a date string from a standard POSIX time"""
179     date = datetime.datetime.fromtimestamp(emerge_date)
180
181     date = "{:%d.%m.%Y %H:%M:%S}".format(date)
182
183     return date
184
185
186
187 def open_log():
188     """Attempt to open the LOGFILE."""
189
190     try:
191         f = open(LOGFILE, 'r')
192     except IOError as detail:
193         print detail
194         sys.exit(1)
195
196     return f
197
198
199
200 def search_log_for_package(package_class):
201     """Searchs emerge log for given package and adds all found
202     versions with their emerge times to the class"""
203
204     log = open_log()
205
206     for line in log:
207         if ((">>>" in line) and ("emerge" in line)):
208             if package_class.name in line:
209
210                 version = line.partition(package_class.name)[2].partition(' ')[0]
211                 digit = version.strip('-')[0].isdigit()
212
213                 if digit:
214                     time_string = line.partition(">>>")
215                     start_time = float(time_string[0].strip().strip(':'))
216
217         elif ((":::" in line) and ("completed emerge" in line)):
218
219             if package_class.name in line:
220                 if digit:
221                     time_string = line.partition(":::")
222                     stop_time = float(time_string[0].strip().strip(':'))
223
224                     emerge_time = stop_time - start_time
225
226                     package_class.add_version(version, emerge_time, start_time)
227
228
229
230 def get_package(name):
231     """Take the user-input package name and search for it
232     in PORTDIR. """
233
234     dirlist = os.listdir(PORTDIR)
235     possible_package = []
236
237
238     # If the given name is in the format xxx/zzz
239     # assume that xxx is the package group
240     if '/' in name:
241         group = name.partition('/')[0]
242         pkg = name.partition('/')[2]
243         directory = PORTDIR + group
244
245         if group in dirlist:
246             dirs = os.listdir(directory)
247             if pkg in dirs:
248                 possible_package.append(name)
249
250
251     # Go through the directory listing searching for anything
252     # that matches the given name
253     for i in dirlist:
254         directory = PORTDIR + i
255         if os.path.isdir(directory):
256             dirs = os.listdir(directory)
257             if name in dirs:
258                 possible_package.append(i + '/' + name)
259
260
261     if len(possible_package) > 1:
262         print("Multiple packages found for '" + name + "'.")
263         print("Possible packages: ")
264         for value in possible_package:
265             print("\t" + value)
266
267
268     elif len(possible_package) == 1:
269         package = possible_package[0]
270         return package
271
272
273     else:
274         print("No package '" + name + "' found")
275
276
277     sys.exit(1)
278
279
280
281 def list_pretended():
282     """List all the pretended packages given by emerge -p
283     output. Create a class out of each of those packages and add them
284     to the list."""
285
286     log = open_log()
287
288     for line in sys.stdin:
289         if "[ebuild" in line:
290             full_name = line.partition("] ")[2].partition(' ')[0]
291
292             version = full_name.partition('/')[2].partition('-')[2]
293             while not version[0].isdigit():
294                 version = version.partition('-')[2]
295             package_name = full_name[:-len(version)-1]
296
297             PACKAGES.append(package(package_name, version))
298
299
300
301 def list_emerge_processes():
302     """Look for the ebuild process with ps. If the process is found parse
303     the command for the package. With this package search the LOGFILE for
304     the emerge startup time."""
305
306     f = open_log()
307
308     now = datetime.datetime.today()
309
310     for i in os.popen("ps ax"):
311         if (("ebuild.sh" in i) and ("/bin/bash" not in i)):
312             pack = i.partition('[')[2].partition(']')[0]
313
314             version = pack.partition('/')[2].partition('-')[2]
315
316             while not version[0].isdigit():
317                 version = version.partition('-')[2]
318
319             package_name = pack[:-len(version)-1]
320
321             PACKAGES.append(package(package_name, version))
322
323
324     if len(PACKAGES) == 0:
325         print "No current emerge process found."
326         sys.exit(0)
327
328
329     for line in f:
330         if ((">>>" in line) and ("emerge" in line)):
331             for p in packages:
332                 if (p.name + '-' + p.version in line):
333
334                     time = float(line.partition(' ')[0].strip(":"))
335
336                     timestamp = datetime.datetime.fromtimestamp(time)
337                     difference = (now - timestamp).total_seconds()
338
339                     if difference < p.emerge_time:
340                         p.emerge_time = difference
341
342
343
344 def main(status, user_package=None):
345     """Main function. Hanlde all the different modes of operation."""
346
347     if status == "package":
348         user_package = get_package(user_package)
349
350         pack = package(user_package)
351
352         search_log_for_package(pack)
353         pack.print_versions()
354         pack.print_min_max_ave()
355
356
357     elif status == "current":
358         list_emerge_processes()
359
360         print "Currently emerging:"
361
362         for p in PACKAGES:
363             search_log_for_package(p)
364             p.print_current_emerge()
365
366
367     elif status == "pretended":
368         list_pretended()
369
370         print "This is how long these packages would take to emerge"
371
372         for p in PACKAGES:
373             search_log_for_package(p)
374             p.print_pretended_times()
375             print
376
377
378
379 def usage():
380     usage = """Usage: emerge-timer.py [package] [options]
381
382 Calculate emerge times from emerge log.
383
384 Options:
385 \t-c, --current \t Show time until currently compiling package finishes
386 \t-p, --pretended  Calculate compile time from piped 'emerge -p' output
387 \t-h, --help \t Show this helpscreen
388
389 \t--no-color \t Use colorless output"""
390
391     print usage
392
393     sys.exit(0)
394
395
396 if __name__ == "__main__":
397
398     # Set the default mode as "package"
399     mode = "package"
400     input_package = None
401
402
403     for arg in sys.argv[1:]:
404
405         if arg == "-p" or arg == "--pretended":
406             mode = "pretended"
407
408         if arg == "-c" or arg == "--current":
409             mode = "current"
410
411         if arg == "-h" or arg == "--help":
412             usage()
413
414         if arg == "--no-color":
415             green_start = ""
416             color_stop = ""
417
418
419     if len(sys.argv) > 1:
420         input_package = sys.argv[1]
421     else:
422         usage()
423
424     main(mode, input_package)