##// END OF EJS Templates
Fix bug with empty inc and exc...
mpm@selenic.com -
r897:fe30f543 default
parent child Browse files
Show More
@@ -1,277 +1,281
1 1 # util.py - utility functions and platform specfic implementations
2 2 #
3 3 # Copyright 2005 K. Thananchayan <thananck@yahoo.com>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 import os, errno
9 9 from demandload import *
10 10 demandload(globals(), "re")
11 11
12 12 def unique(g):
13 13 seen = {}
14 14 for f in g:
15 15 if f not in seen:
16 16 seen[f] = 1
17 17 yield f
18 18
19 19 class Abort(Exception):
20 20 """Raised if a command needs to print an error and exit."""
21 21
22 22 def always(fn): return True
23 23 def never(fn): return False
24 24
25 25 def globre(pat, head = '^', tail = '$'):
26 26 "convert a glob pattern into a regexp"
27 27 i, n = 0, len(pat)
28 28 res = ''
29 29 group = False
30 30 def peek(): return i < n and pat[i]
31 31 while i < n:
32 32 c = pat[i]
33 33 i = i+1
34 34 if c == '*':
35 35 if peek() == '*':
36 36 i += 1
37 37 res += '.*'
38 38 else:
39 39 res += '[^/]*'
40 40 elif c == '?':
41 41 res += '.'
42 42 elif c == '[':
43 43 j = i
44 44 if j < n and pat[j] in '!]':
45 45 j += 1
46 46 while j < n and pat[j] != ']':
47 47 j += 1
48 48 if j >= n:
49 49 res += '\\['
50 50 else:
51 51 stuff = pat[i:j].replace('\\','\\\\')
52 52 i = j + 1
53 53 if stuff[0] == '!':
54 54 stuff = '^' + stuff[1:]
55 55 elif stuff[0] == '^':
56 56 stuff = '\\' + stuff
57 57 res = '%s[%s]' % (res, stuff)
58 58 elif c == '{':
59 59 group = True
60 60 res += '(?:'
61 61 elif c == '}' and group:
62 62 res += ')'
63 63 group = False
64 64 elif c == ',' and group:
65 65 res += '|'
66 66 else:
67 67 res += re.escape(c)
68 68 return head + res + tail
69 69
70 70 _globchars = {'[': 1, '{': 1, '*': 1, '?': 1}
71 71
72 72 def pathto(n1, n2):
73 73 '''return the relative path from one place to another.
74 74 this returns a path in the form used by the local filesystem, not hg.'''
75 75 if not n1: return localpath(n2)
76 76 a, b = n1.split('/'), n2.split('/')
77 77 a.reverse(), b.reverse()
78 78 while a and b and a[-1] == b[-1]:
79 79 a.pop(), b.pop()
80 80 b.reverse()
81 81 return os.sep.join((['..'] * len(a)) + b)
82 82
83 83 def canonpath(repo, cwd, myname):
84 84 rootsep = repo.root + os.sep
85 85 name = myname
86 86 if not name.startswith(os.sep):
87 87 name = os.path.join(repo.root, cwd, name)
88 88 name = os.path.normpath(name)
89 89 if name.startswith(rootsep):
90 90 return pconvert(name[len(rootsep):])
91 91 elif name == repo.root:
92 92 return ''
93 93 else:
94 94 raise Abort('%s not under repository root' % myname)
95 95
96 96 def matcher(repo, cwd, names, inc, exc, head = ''):
97 97 def patkind(name):
98 98 for prefix in 're:', 'glob:', 'path:', 'relpath:':
99 99 if name.startswith(prefix): return name.split(':', 1)
100 100 for c in name:
101 101 if c in _globchars: return 'glob', name
102 102 return 'relpath', name
103 103
104 104 def regex(kind, name, tail):
105 105 '''convert a pattern into a regular expression'''
106 106 if kind == 're':
107 107 return name
108 108 elif kind == 'path':
109 109 return '^' + re.escape(name) + '(?:/|$)'
110 110 elif kind == 'relpath':
111 111 return head + re.escape(name) + tail
112 112 return head + globre(name, '', tail)
113 113
114 114 def matchfn(pats, tail):
115 115 """build a matching function from a set of patterns"""
116 116 if pats:
117 117 pat = '(?:%s)' % '|'.join([regex(k, p, tail) for (k, p) in pats])
118 118 return re.compile(pat).match
119 119
120 120 def globprefix(pat):
121 121 '''return the non-glob prefix of a path, e.g. foo/* -> foo'''
122 122 root = []
123 123 for p in pat.split(os.sep):
124 124 if patkind(p)[0] == 'glob': break
125 125 root.append(p)
126 126 return '/'.join(root)
127 127
128 128 pats = []
129 129 files = []
130 130 roots = []
131 131 for kind, name in map(patkind, names):
132 132 if kind in ('glob', 'relpath'):
133 133 name = canonpath(repo, cwd, name)
134 134 if name == '':
135 135 kind, name = 'glob', '**'
136 136 if kind in ('glob', 'path', 're'):
137 137 pats.append((kind, name))
138 138 if kind == 'glob':
139 139 root = globprefix(name)
140 140 if root: roots.append(root)
141 141 elif kind == 'relpath':
142 142 files.append((kind, name))
143 143 roots.append(name)
144 144
145 145 patmatch = matchfn(pats, '$') or always
146 146 filematch = matchfn(files, '(?:/|$)') or always
147 incmatch = matchfn(map(patkind, inc), '(?:/|$)') or always
148 excmatch = matchfn(map(patkind, exc), '(?:/|$)') or (lambda fn: False)
147 incmatch = always
148 if inc:
149 incmatch = matchfn(map(patkind, inc), '(?:/|$)')
150 excmatch = lambda fn: False
151 if exc:
152 excmatch = matchfn(map(patkind, exc), '(?:/|$)')
149 153
150 154 return roots, lambda fn: (incmatch(fn) and not excmatch(fn) and
151 155 (fn.endswith('/') or
152 156 (not pats and not files) or
153 157 (pats and patmatch(fn)) or
154 158 (files and filematch(fn))))
155 159
156 160 def system(cmd, errprefix=None):
157 161 """execute a shell command that must succeed"""
158 162 rc = os.system(cmd)
159 163 if rc:
160 164 errmsg = "%s %s" % (os.path.basename(cmd.split(None, 1)[0]),
161 165 explain_exit(rc)[0])
162 166 if errprefix:
163 167 errmsg = "%s: %s" % (errprefix, errmsg)
164 168 raise Abort(errmsg)
165 169
166 170 def rename(src, dst):
167 171 try:
168 172 os.rename(src, dst)
169 173 except:
170 174 os.unlink(dst)
171 175 os.rename(src, dst)
172 176
173 177 def copytree(src, dst, copyfile):
174 178 """Copy a directory tree, files are copied using 'copyfile'."""
175 179 names = os.listdir(src)
176 180 os.mkdir(dst)
177 181
178 182 for name in names:
179 183 srcname = os.path.join(src, name)
180 184 dstname = os.path.join(dst, name)
181 185 if os.path.isdir(srcname):
182 186 copytree(srcname, dstname, copyfile)
183 187 elif os.path.isfile(srcname):
184 188 copyfile(srcname, dstname)
185 189 else:
186 190 raise IOError("Not a regular file: %r" % srcname)
187 191
188 192 def _makelock_file(info, pathname):
189 193 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
190 194 os.write(ld, info)
191 195 os.close(ld)
192 196
193 197 def _readlock_file(pathname):
194 198 return file(pathname).read()
195 199
196 200 # Platfor specific varients
197 201 if os.name == 'nt':
198 202 nulldev = 'NUL:'
199 203
200 204 def is_exec(f, last):
201 205 return last
202 206
203 207 def set_exec(f, mode):
204 208 pass
205 209
206 210 def pconvert(path):
207 211 return path.replace("\\", "/")
208 212
209 213 def localpath(path):
210 214 return path.replace('/', '\\')
211 215
212 216 def normpath(path):
213 217 return pconvert(os.path.normpath(path))
214 218
215 219 makelock = _makelock_file
216 220 readlock = _readlock_file
217 221
218 222 def explain_exit(code):
219 223 return "exited with status %d" % code, code
220 224
221 225 else:
222 226 nulldev = '/dev/null'
223 227
224 228 def is_exec(f, last):
225 229 return (os.stat(f).st_mode & 0100 != 0)
226 230
227 231 def set_exec(f, mode):
228 232 s = os.stat(f).st_mode
229 233 if (s & 0100 != 0) == mode:
230 234 return
231 235 if mode:
232 236 # Turn on +x for every +r bit when making a file executable
233 237 # and obey umask.
234 238 umask = os.umask(0)
235 239 os.umask(umask)
236 240 os.chmod(f, s | (s & 0444) >> 2 & ~umask)
237 241 else:
238 242 os.chmod(f, s & 0666)
239 243
240 244 def pconvert(path):
241 245 return path
242 246
243 247 def localpath(path):
244 248 return path
245 249
246 250 normpath = os.path.normpath
247 251
248 252 def makelock(info, pathname):
249 253 try:
250 254 os.symlink(info, pathname)
251 255 except OSError, why:
252 256 if why.errno == errno.EEXIST:
253 257 raise
254 258 else:
255 259 _makelock_file(info, pathname)
256 260
257 261 def readlock(pathname):
258 262 try:
259 263 return os.readlink(pathname)
260 264 except OSError, why:
261 265 if why.errno == errno.EINVAL:
262 266 return _readlock_file(pathname)
263 267 else:
264 268 raise
265 269
266 270 def explain_exit(code):
267 271 """return a 2-tuple (desc, code) describing a process's status"""
268 272 if os.WIFEXITED(code):
269 273 val = os.WEXITSTATUS(code)
270 274 return "exited with status %d" % val, val
271 275 elif os.WIFSIGNALED(code):
272 276 val = os.WTERMSIG(code)
273 277 return "killed by signal %d" % val, val
274 278 elif os.WIFSTOPPED(code):
275 279 val = os.STOPSIG(code)
276 280 return "stopped by signal %d" % val, val
277 281 raise ValueError("invalid exit code")
General Comments 0
You need to be logged in to leave comments. Login now