]> git.ipfire.org Git - pakfire.git/blame - src/pakfire/util.py
libpakfire: Drop Pool
[pakfire.git] / src / pakfire / util.py
CommitLineData
964aa579 1#!/usr/bin/python3
b792d887
MT
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###############################################################################
47a4cb89 21
102c5ee7 22import hashlib
47a4cb89
MT
23import os
24import random
47a4cb89 25import shutil
aa7f15fe 26import signal
47a4cb89 27import string
47a4cb89
MT
28import sys
29import time
30
8b6bc023
MT
31import logging
32log = logging.getLogger("pakfire")
33
964aa579
MT
34from .constants import *
35from .i18n import _
47a4cb89 36
3c0e282f 37# Import binary version of version_compare and capability functions
44b27b6f 38from ._pakfire import get_capabilities, set_capabilities, personality
102c5ee7 39
e9c20259
MT
40def cli_is_interactive():
41 """
42 Say weather a shell is interactive or not.
43 """
44 if sys.stdin.isatty() and sys.stdout.isatty() and sys.stderr.isatty():
45 return True
46
47 return False
48
1b61ba46
MT
49def is_enabled(s):
50 return s in ("true", "yes", "1")
51
c0fd807c
MT
52def ask_user(question):
53 """
54 Ask the user the question, he or she can answer with yes or no.
55
56 This function returns True for "yes" and False for "no".
57
58 If the software is running in a non-inteactive shell, no question
59 is asked at all and the answer is always "yes".
60 """
61 if not cli_is_interactive():
62 return True
63
964aa579
MT
64 print(_("%s [y/N]") % question, end=' ')
65 ret = input()
66 print() # Just an empty line.
c0fd807c
MT
67
68 return ret in ("y", "Y", "z", "Z", "j", "J")
69
7c8f2953
MT
70def random_string(length=20):
71 s = ""
72
73 for i in range(length):
964aa579 74 s += random.choice(string.ascii_letters)
7c8f2953
MT
75
76 return s
77
38ba21f9 78def make_progress(message, maxval, eta=True, speed=False):
964aa579
MT
79 # XXX delay importing the progressbar module
80 # (because of a circular dependency)
10458aa0 81 from .ui import progressbar
964aa579 82
4496b160
MT
83 # Return nothing if stdout is not a terminal.
84 if not sys.stdout.isatty():
85 return
86
dccd65ea
MT
87 if not maxval:
88 maxval = 1
4496b160 89
dccd65ea
MT
90 pb = progressbar.ProgressBar(maxval)
91 pb.add("%-50s" % message)
38ba21f9 92
dccd65ea
MT
93 bar = progressbar.WidgetBar()
94 pb.add(bar)
1e80d5d7 95
dccd65ea
MT
96 if speed:
97 percentage = progressbar.WidgetPercentage()
98 pb.add(percentage)
4496b160 99
dccd65ea
MT
100 filetransfer = progressbar.WidgetFileTransferSpeed()
101 pb.add(filetransfer)
4496b160 102
dccd65ea
MT
103 if eta:
104 eta = progressbar.WidgetETA()
105 pb.add(eta)
106
107 return pb.start()
4496b160 108
47a4cb89
MT
109def rm(path, *args, **kargs):
110 """
111 version of shutil.rmtree that ignores no-such-file-or-directory errors,
112 and tries harder if it finds immutable files
113 """
114 tryAgain = 1
115 failedFilename = None
116 while tryAgain:
117 tryAgain = 0
118 try:
119 shutil.rmtree(path, *args, **kargs)
964aa579 120 except OSError as e:
47a4cb89
MT
121 if e.errno == 2: # no such file or directory
122 pass
123 elif e.errno==1 or e.errno==13:
124 tryAgain = 1
125 if failedFilename == e.filename:
126 raise
127 failedFilename = e.filename
128 os.system("chattr -R -i %s" % path)
129 else:
130 raise
0a9a2371 131
102c5ee7 132def calc_hash1(filename=None, data=None):
e3bcfd23 133 h = hashlib.new("sha1")
102c5ee7
MT
134
135 if filename:
136 f = open(filename)
137 buf = f.read(BUFFER_SIZE)
138 while buf:
139 h.update(buf)
140 buf = f.read(BUFFER_SIZE)
141
142 f.close()
143
144 elif data:
145 h.update(data)
146
147 return h.hexdigest()
148
149def text_wrap(s, length=65):
c07a3ca7
MT
150 if not s:
151 return ""
152
153 lines = []
154
155 words = []
156 for line in s.splitlines():
157 if not line:
158 words.append("")
159 else:
160 words += line.split()
161
162 line = []
163 while words:
164 word = words.pop(0)
165
166 # An empty words means a line break.
167 if not word:
168 if line:
169 lines.append(" ".join(line))
170 lines.append("")
171 line = []
172
173 else:
174 if len(" ".join(line)) + len(word) >= length:
175 lines.append(" ".join(line))
176 line = []
177 words.insert(0, word)
178 else:
179 line.append(word)
102c5ee7 180
c07a3ca7
MT
181 if line:
182 lines.append(" ".join(line))
102c5ee7 183
c07a3ca7 184 assert not words
102c5ee7 185
c07a3ca7
MT
186 #return "\n".join(lines)
187 return lines
aa7f15fe
MT
188
189def orphans_kill(root, killsig=signal.SIGTERM):
190 """
191 kill off anything that is still chrooted.
192 """
8b6bc023 193 log.debug(_("Killing orphans..."))
aa7f15fe 194
536438d9 195 killed = False
aa7f15fe
MT
196 for fn in [d for d in os.listdir("/proc") if d.isdigit()]:
197 try:
198 r = os.readlink("/proc/%s/root" % fn)
199 if os.path.realpath(root) == os.path.realpath(r):
8b6bc023 200 log.warning(_("Process ID %s is still running in chroot. Killing...") % fn)
536438d9 201 killed = True
aa7f15fe
MT
202
203 pid = int(fn, 10)
204 os.kill(pid, killsig)
205 os.waitpid(pid, 0)
964aa579 206 except OSError as e:
aa7f15fe 207 pass
c07a3ca7 208
536438d9
MT
209 # If something was killed, wait a couple of seconds to make sure all file descriptors
210 # are closed and we can proceed with umounting the filesystems.
211 if killed:
8b6bc023 212 log.warning(_("Waiting for processes to terminate..."))
536438d9
MT
213 time.sleep(3)
214
7814c06d
MT
215 # Calling ourself again to make sure all processes were killed.
216 orphans_kill(root, killsig=killsig)
217
c07a3ca7
MT
218def scriptlet_interpreter(scriptlet):
219 """
220 This function returns the interpreter of a scriptlet.
221 """
222 # XXX handle ELF?
223 interpreter = None
224
225 for line in scriptlet.splitlines():
226 if line.startswith("#!/"):
227 interpreter = line[2:]
228 interpreter = interpreter.split()[0]
229 break
230
231 return interpreter