]> git.ipfire.org Git - people/stevee/pakfire.git/blob - src/pakfire/util.py
Use autotools.
[people/stevee/pakfire.git] / src / pakfire / util.py
1 #!/usr/bin/python
2 ###############################################################################
3 # #
4 # Pakfire - The IPFire package management system #
5 # Copyright (C) 2011 Pakfire development team #
6 # #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
11 # #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
16 # #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
19 # #
20 ###############################################################################
21
22 from __future__ import division
23
24 import fcntl
25 import hashlib
26 import math
27 import os
28 import progressbar
29 import random
30 import shutil
31 import signal
32 import string
33 import struct
34 import sys
35 import termios
36 import time
37
38 import logging
39 log = logging.getLogger("pakfire")
40
41 from constants import *
42 from i18n import _
43
44 # Import binary version of version_compare and capability functions
45 from _pakfire import version_compare, get_capabilities, set_capabilities, personality
46
47 def cli_is_interactive():
48 """
49 Say weather a shell is interactive or not.
50 """
51 if sys.stdin.isatty() and sys.stdout.isatty() and sys.stderr.isatty():
52 return True
53
54 return False
55
56 def ask_user(question):
57 """
58 Ask the user the question, he or she can answer with yes or no.
59
60 This function returns True for "yes" and False for "no".
61
62 If the software is running in a non-inteactive shell, no question
63 is asked at all and the answer is always "yes".
64 """
65 if not cli_is_interactive():
66 return True
67
68 print _("%s [y/N]") % question,
69 ret = raw_input()
70 print # Just an empty line.
71
72 return ret in ("y", "Y", "z", "Z", "j", "J")
73
74 def random_string(length=20):
75 s = ""
76
77 for i in range(length):
78 s += random.choice(string.letters)
79
80 return s
81
82 def make_progress(message, maxval, eta=True, speed=False):
83 # Return nothing if stdout is not a terminal.
84 if not sys.stdout.isatty():
85 return
86
87 widgets = [
88 " ",
89 "%-64s" % message,
90 " ",
91 progressbar.Bar(left="[", right="]"),
92 " ",
93 ]
94
95 if speed:
96 widgets += [
97 progressbar.Percentage(), " ",
98 progressbar.FileTransferSpeed(), " "
99 ]
100
101 if eta:
102 widgets += [progressbar.ETA(), " ",]
103
104 if not maxval:
105 maxval = 1
106
107 pb = progressbar.ProgressBar(widgets=widgets, maxval=maxval)
108 pb.start()
109
110 return pb
111
112 def rm(path, *args, **kargs):
113 """
114 version of shutil.rmtree that ignores no-such-file-or-directory errors,
115 and tries harder if it finds immutable files
116 """
117 tryAgain = 1
118 failedFilename = None
119 while tryAgain:
120 tryAgain = 0
121 try:
122 shutil.rmtree(path, *args, **kargs)
123 except OSError, e:
124 if e.errno == 2: # no such file or directory
125 pass
126 elif e.errno==1 or e.errno==13:
127 tryAgain = 1
128 if failedFilename == e.filename:
129 raise
130 failedFilename = e.filename
131 os.system("chattr -R -i %s" % path)
132 else:
133 raise
134
135 def ioctl_GWINSZ(fd):
136 try:
137 cr = struct.unpack("hh", fcntl.ioctl(fd, termios.TIOCGWINSZ, "1234"))
138 except:
139 return None
140
141 return cr
142
143 def terminal_size():
144 cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
145
146 if not cr:
147 try:
148 fd = os.open(os.ctermid(), os.O_RDONLY)
149 cr = ioctl_GWINSZ(fd)
150 os.close(fd)
151 except:
152 pass
153
154 if not cr:
155 try:
156 cr = (os.environ['LINES'], os.environ['COLUMNS'])
157 except:
158 cr = (25, 80)
159
160 return int(cr[1]), int(cr[0])
161
162 def format_size(s):
163 sign = 1
164
165 # If s is negative, we save the sign and run the calculation with the
166 # absolute value of s.
167 if s < 0:
168 sign = -1
169 s = -1 * s
170
171 units = (" ", "k", "M", "G", "T")
172 unit = 0
173
174 while s >= 1024 and unit < len(units):
175 s /= 1024
176 unit += 1
177
178 return "%d%s" % (round(s) * sign, units[unit])
179
180 def format_time(s):
181 return "%02d:%02d" % (s // 60, s % 60)
182
183 def format_speed(s):
184 return "%sB/s" % format_size(s)
185
186 def calc_hash1(filename=None, data=None):
187 h = hashlib.new("sha1")
188
189 if filename:
190 f = open(filename)
191 buf = f.read(BUFFER_SIZE)
192 while buf:
193 h.update(buf)
194 buf = f.read(BUFFER_SIZE)
195
196 f.close()
197
198 elif data:
199 h.update(data)
200
201 return h.hexdigest()
202
203 def text_wrap(s, length=65):
204 if not s:
205 return ""
206
207 lines = []
208
209 words = []
210 for line in s.splitlines():
211 if not line:
212 words.append("")
213 else:
214 words += line.split()
215
216 line = []
217 while words:
218 word = words.pop(0)
219
220 # An empty words means a line break.
221 if not word:
222 if line:
223 lines.append(" ".join(line))
224 lines.append("")
225 line = []
226
227 else:
228 if len(" ".join(line)) + len(word) >= length:
229 lines.append(" ".join(line))
230 line = []
231 words.insert(0, word)
232 else:
233 line.append(word)
234
235 if line:
236 lines.append(" ".join(line))
237
238 assert not words
239
240 #return "\n".join(lines)
241 return lines
242
243 def orphans_kill(root, killsig=signal.SIGTERM):
244 """
245 kill off anything that is still chrooted.
246 """
247 log.debug(_("Killing orphans..."))
248
249 killed = False
250 for fn in [d for d in os.listdir("/proc") if d.isdigit()]:
251 try:
252 r = os.readlink("/proc/%s/root" % fn)
253 if os.path.realpath(root) == os.path.realpath(r):
254 log.warning(_("Process ID %s is still running in chroot. Killing...") % fn)
255 killed = True
256
257 pid = int(fn, 10)
258 os.kill(pid, killsig)
259 os.waitpid(pid, 0)
260 except OSError, e:
261 pass
262
263 # If something was killed, wait a couple of seconds to make sure all file descriptors
264 # are closed and we can proceed with umounting the filesystems.
265 if killed:
266 log.warning(_("Waiting for processes to terminate..."))
267 time.sleep(3)
268
269 # Calling ourself again to make sure all processes were killed.
270 orphans_kill(root, killsig=killsig)
271
272 def scriptlet_interpreter(scriptlet):
273 """
274 This function returns the interpreter of a scriptlet.
275 """
276 # XXX handle ELF?
277 interpreter = None
278
279 for line in scriptlet.splitlines():
280 if line.startswith("#!/"):
281 interpreter = line[2:]
282 interpreter = interpreter.split()[0]
283 break
284
285 return interpreter