Package logilab-common-0 ::
Package 36 ::
Package 1 ::
Module shellutils
|
|
1 """shell/term utilities, useful to write some python scripts instead of shell
2 scripts.
3
4 :author: Logilab
5 :copyright: 2000-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
6 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
7 :license: General Public License version 2 - http://www.gnu.org/licenses
8 """
9 __docformat__ = "restructuredtext en"
10
11 import os
12 import glob
13 import shutil
14 import sys
15 import tempfile
16 import time
17 import fnmatch
18 from os.path import exists, isdir, islink, basename, join, walk
19
20 from logilab.common import STD_BLACKLIST
21
22
23 -def chown(path, login=None, group=None):
24 """Same as `os.chown` function but accepting user login or group name as
25 argument. If login or group is omitted, it's left unchanged.
26
27 Note: you must own the file to chown it (or be root). Otherwise OSError is raised.
28 """
29 if login is None:
30 uid = -1
31 else:
32 try:
33 uid = int(login)
34 except ValueError:
35 import pwd
36 uid = pwd.getpwnam(login).pw_uid
37 if group is None:
38 gid = -1
39 else:
40 try:
41 gid = int(group)
42 except ValueError:
43 import grp
44 gid = grp.getgrname(group).gr_gid
45 os.chown(path, uid, gid)
46
47
48 -def mv(source, destination, _action=shutil.move):
49 """A shell-like mv, supporting wildcards.
50 """
51 sources = glob.glob(source)
52 if len(sources) > 1:
53 assert isdir(destination)
54 for filename in sources:
55 _action(filename, join(destination, basename(filename)))
56 else:
57 try:
58 source = sources[0]
59 except IndexError:
60 raise OSError('No file matching %s' % source)
61 if isdir(destination) and exists(destination):
62 destination = join(destination, basename(source))
63 try:
64 _action(source, destination)
65 except OSError, ex:
66 raise OSError('Unable to move %r to %r (%s)' % (
67 source, destination, ex))
68
70 """A shell-like rm, supporting wildcards.
71 """
72 for wfile in files:
73 for filename in glob.glob(wfile):
74 if islink(filename):
75 os.remove(filename)
76 elif isdir(filename):
77 shutil.rmtree(filename)
78 else:
79 os.remove(filename)
80
81 -def cp(source, destination):
82 """A shell-like cp, supporting wildcards.
83 """
84 mv(source, destination, _action=shutil.copy)
85
86
88 """Recursivly find files ending with the given extensions from the directory.
89
90 :type directory: str
91 :param directory:
92 directory where the search should start
93
94 :type exts: basestring or list or tuple
95 :param exts:
96 extensions or lists or extensions to search
97
98 :type exclude: boolean
99 :param exts:
100 if this argument is True, returning files NOT ending with the given
101 extensions
102
103 :type blacklist: list or tuple
104 :param blacklist:
105 optional list of files or directory to ignore, default to the value of
106 `logilab.common.STD_BLACKLIST`
107
108 :rtype: list
109 :return:
110 the list of all matching files
111 """
112 if isinstance(exts, basestring):
113 exts = (exts,)
114 if exclude:
115 def match(filename, exts):
116 for ext in exts:
117 if filename.endswith(ext):
118 return False
119 return True
120 else:
121 def match(filename, exts):
122 for ext in exts:
123 if filename.endswith(ext):
124 return True
125 return False
126 def func(files, directory, fnames):
127 """walk handler"""
128
129 for norecurs in blacklist:
130 try:
131 fnames.remove(norecurs)
132 except ValueError:
133 continue
134 for filename in fnames:
135 src = join(directory, filename)
136 if isdir(src):
137 continue
138 if match(filename, exts):
139 files.append(src)
140 files = []
141 walk(directory, func, files)
142 return files
143
144
146 """Recursively finds files matching glob `pattern` under `directory`.
147
148 This is an alternative to `logilab.common.shellutils.find`.
149
150 :type directory: str
151 :param directory:
152 directory where the search should start
153
154 :type pattern: basestring
155 :param pattern:
156 the glob pattern (e.g *.py, foo*.py, etc.)
157
158 :type blacklist: list or tuple
159 :param blacklist:
160 optional list of files or directory to ignore, default to the value of
161 `logilab.common.STD_BLACKLIST`
162
163 :rtype: iterator
164 :return:
165 iterator over the list of all matching files
166 """
167 for curdir, dirnames, filenames in os.walk(directory):
168 for fname in fnmatch.filter(filenames, pattern):
169 yield join(curdir, fname)
170 for skipped in blacklist:
171 if skipped in dirnames:
172 dirnames.remove(skipped)
173
174 -def unzip(archive, destdir):
175 import zipfile
176 if not exists(destdir):
177 os.mkdir(destdir)
178 zfobj = zipfile.ZipFile(archive)
179 for name in zfobj.namelist():
180 if name.endswith('/'):
181 os.mkdir(join(destdir, name))
182 else:
183 outfile = open(join(destdir, name), 'wb')
184 outfile.write(zfobj.read(name))
185 outfile.close()
186
188 """This is a deadlock safe version of popen2 (no stdin), that returns
189 an object with errorlevel, out and err.
190 """
191
193 outfile = tempfile.mktemp()
194 errfile = tempfile.mktemp()
195 self.status = os.system("( %s ) >%s 2>%s" %
196 (command, outfile, errfile)) >> 8
197 self.out = open(outfile,"r").read()
198 self.err = open(errfile,"r").read()
199 os.remove(outfile)
200 os.remove(errfile)
201
202
204 """Acquire a lock represented by a file on the file system."""
205 count = 0
206 while max_try <= 0 or count < max_try:
207 if not exists(lock_file):
208 break
209 count += 1
210 time.sleep(delay)
211 else:
212 raise Exception('Unable to acquire %s' % lock_file)
213 stream = open(lock_file, 'w')
214 stream.write(str(os.getpid()))
215 stream.close()
216
218 """Release a lock represented by a file on the file system."""
219 os.remove(lock_file)
220
221
223 """A simple text progression bar."""
224
225 - def __init__(self, nbops, size=20, stream=sys.stdout):
226 self._fstr = '\r[%%-%ss]' % int(size)
227 self._stream = stream
228 self._total = nbops
229 self._size = size
230 self._current = 0
231 self._progress = 0
232
234 """Update the progression bar."""
235 self._current += 1
236 progress = int((float(self._current)/float(self._total))*self._size)
237 if progress > self._progress:
238 self._progress = progress
239 self.refresh()
240
242 """Refresh the progression bar display."""
243 self._stream.write(self._fstr % ('.' * min(self._progress, self._size)) )
244 self._stream.flush()
245