##// END OF EJS Templates
Enable path validation for copy, rename, debugwalk and other canonpath users....
Thomas Arendsen Hein -
r1976:df841634 default
parent child Browse files
Show More
@@ -1,800 +1,802 b''
1 1 """
2 2 util.py - Mercurial utility functions and platform specfic implementations
3 3
4 4 Copyright 2005 K. Thananchayan <thananck@yahoo.com>
5 5
6 6 This software may be used and distributed according to the terms
7 7 of the GNU General Public License, incorporated herein by reference.
8 8
9 9 This contains helper routines that are independent of the SCM core and hide
10 10 platform-specific details from the core.
11 11 """
12 12
13 13 import os, errno
14 14 from i18n import gettext as _
15 15 from demandload import *
16 16 demandload(globals(), "cStringIO errno popen2 re shutil sys tempfile")
17 17 demandload(globals(), "threading time")
18 18
19 19 def pipefilter(s, cmd):
20 20 '''filter string S through command CMD, returning its output'''
21 21 (pout, pin) = popen2.popen2(cmd, -1, 'b')
22 22 def writer():
23 23 pin.write(s)
24 24 pin.close()
25 25
26 26 # we should use select instead on UNIX, but this will work on most
27 27 # systems, including Windows
28 28 w = threading.Thread(target=writer)
29 29 w.start()
30 30 f = pout.read()
31 31 pout.close()
32 32 w.join()
33 33 return f
34 34
35 35 def tempfilter(s, cmd):
36 36 '''filter string S through a pair of temporary files with CMD.
37 37 CMD is used as a template to create the real command to be run,
38 38 with the strings INFILE and OUTFILE replaced by the real names of
39 39 the temporary files generated.'''
40 40 inname, outname = None, None
41 41 try:
42 42 infd, inname = tempfile.mkstemp(prefix='hgfin')
43 43 fp = os.fdopen(infd, 'wb')
44 44 fp.write(s)
45 45 fp.close()
46 46 outfd, outname = tempfile.mkstemp(prefix='hgfout')
47 47 os.close(outfd)
48 48 cmd = cmd.replace('INFILE', inname)
49 49 cmd = cmd.replace('OUTFILE', outname)
50 50 code = os.system(cmd)
51 51 if code: raise Abort(_("command '%s' failed: %s") %
52 52 (cmd, explain_exit(code)))
53 53 return open(outname, 'rb').read()
54 54 finally:
55 55 try:
56 56 if inname: os.unlink(inname)
57 57 except: pass
58 58 try:
59 59 if outname: os.unlink(outname)
60 60 except: pass
61 61
62 62 filtertable = {
63 63 'tempfile:': tempfilter,
64 64 'pipe:': pipefilter,
65 65 }
66 66
67 67 def filter(s, cmd):
68 68 "filter a string through a command that transforms its input to its output"
69 69 for name, fn in filtertable.iteritems():
70 70 if cmd.startswith(name):
71 71 return fn(s, cmd[len(name):].lstrip())
72 72 return pipefilter(s, cmd)
73 73
74 74 def patch(strip, patchname, ui):
75 75 """apply the patch <patchname> to the working directory.
76 76 a list of patched files is returned"""
77 77 fp = os.popen('patch -p%d < "%s"' % (strip, patchname))
78 78 files = {}
79 79 for line in fp:
80 80 line = line.rstrip()
81 81 ui.status("%s\n" % line)
82 82 if line.startswith('patching file '):
83 83 pf = parse_patch_output(line)
84 84 files.setdefault(pf, 1)
85 85 code = fp.close()
86 86 if code:
87 87 raise Abort(_("patch command failed: %s") % explain_exit(code)[0])
88 88 return files.keys()
89 89
90 90 def binary(s):
91 91 """return true if a string is binary data using diff's heuristic"""
92 92 if s and '\0' in s[:4096]:
93 93 return True
94 94 return False
95 95
96 96 def unique(g):
97 97 """return the uniq elements of iterable g"""
98 98 seen = {}
99 99 for f in g:
100 100 if f not in seen:
101 101 seen[f] = 1
102 102 yield f
103 103
104 104 class Abort(Exception):
105 105 """Raised if a command needs to print an error and exit."""
106 106
107 107 def always(fn): return True
108 108 def never(fn): return False
109 109
110 110 def patkind(name, dflt_pat='glob'):
111 111 """Split a string into an optional pattern kind prefix and the
112 112 actual pattern."""
113 113 for prefix in 're', 'glob', 'path', 'relglob', 'relpath', 'relre':
114 114 if name.startswith(prefix + ':'): return name.split(':', 1)
115 115 return dflt_pat, name
116 116
117 117 def globre(pat, head='^', tail='$'):
118 118 "convert a glob pattern into a regexp"
119 119 i, n = 0, len(pat)
120 120 res = ''
121 121 group = False
122 122 def peek(): return i < n and pat[i]
123 123 while i < n:
124 124 c = pat[i]
125 125 i = i+1
126 126 if c == '*':
127 127 if peek() == '*':
128 128 i += 1
129 129 res += '.*'
130 130 else:
131 131 res += '[^/]*'
132 132 elif c == '?':
133 133 res += '.'
134 134 elif c == '[':
135 135 j = i
136 136 if j < n and pat[j] in '!]':
137 137 j += 1
138 138 while j < n and pat[j] != ']':
139 139 j += 1
140 140 if j >= n:
141 141 res += '\\['
142 142 else:
143 143 stuff = pat[i:j].replace('\\','\\\\')
144 144 i = j + 1
145 145 if stuff[0] == '!':
146 146 stuff = '^' + stuff[1:]
147 147 elif stuff[0] == '^':
148 148 stuff = '\\' + stuff
149 149 res = '%s[%s]' % (res, stuff)
150 150 elif c == '{':
151 151 group = True
152 152 res += '(?:'
153 153 elif c == '}' and group:
154 154 res += ')'
155 155 group = False
156 156 elif c == ',' and group:
157 157 res += '|'
158 158 else:
159 159 res += re.escape(c)
160 160 return head + res + tail
161 161
162 162 _globchars = {'[': 1, '{': 1, '*': 1, '?': 1}
163 163
164 164 def pathto(n1, n2):
165 165 '''return the relative path from one place to another.
166 166 this returns a path in the form used by the local filesystem, not hg.'''
167 167 if not n1: return localpath(n2)
168 168 a, b = n1.split('/'), n2.split('/')
169 169 a.reverse()
170 170 b.reverse()
171 171 while a and b and a[-1] == b[-1]:
172 172 a.pop()
173 173 b.pop()
174 174 b.reverse()
175 175 return os.sep.join((['..'] * len(a)) + b)
176 176
177 177 def canonpath(root, cwd, myname):
178 178 """return the canonical path of myname, given cwd and root"""
179 179 if root == os.sep:
180 180 rootsep = os.sep
181 181 else:
182 182 rootsep = root + os.sep
183 183 name = myname
184 184 if not name.startswith(os.sep):
185 185 name = os.path.join(root, cwd, name)
186 186 name = os.path.normpath(name)
187 187 if name.startswith(rootsep):
188 return pconvert(name[len(rootsep):])
188 name = name[len(rootsep):]
189 audit_path(name)
190 return pconvert(name)
189 191 elif name == root:
190 192 return ''
191 193 else:
192 194 raise Abort('%s not under root' % myname)
193 195
194 196 def matcher(canonroot, cwd='', names=['.'], inc=[], exc=[], head='', src=None):
195 197 return _matcher(canonroot, cwd, names, inc, exc, head, 'glob', src)
196 198
197 199 def cmdmatcher(canonroot, cwd='', names=['.'], inc=[], exc=[], head='', src=None):
198 200 if os.name == 'nt':
199 201 dflt_pat = 'glob'
200 202 else:
201 203 dflt_pat = 'relpath'
202 204 return _matcher(canonroot, cwd, names, inc, exc, head, dflt_pat, src)
203 205
204 206 def _matcher(canonroot, cwd, names, inc, exc, head, dflt_pat, src):
205 207 """build a function to match a set of file patterns
206 208
207 209 arguments:
208 210 canonroot - the canonical root of the tree you're matching against
209 211 cwd - the current working directory, if relevant
210 212 names - patterns to find
211 213 inc - patterns to include
212 214 exc - patterns to exclude
213 215 head - a regex to prepend to patterns to control whether a match is rooted
214 216
215 217 a pattern is one of:
216 218 'glob:<rooted glob>'
217 219 're:<rooted regexp>'
218 220 'path:<rooted path>'
219 221 'relglob:<relative glob>'
220 222 'relpath:<relative path>'
221 223 'relre:<relative regexp>'
222 224 '<rooted path or regexp>'
223 225
224 226 returns:
225 227 a 3-tuple containing
226 228 - list of explicit non-pattern names passed in
227 229 - a bool match(filename) function
228 230 - a bool indicating if any patterns were passed in
229 231
230 232 todo:
231 233 make head regex a rooted bool
232 234 """
233 235
234 236 def contains_glob(name):
235 237 for c in name:
236 238 if c in _globchars: return True
237 239 return False
238 240
239 241 def regex(kind, name, tail):
240 242 '''convert a pattern into a regular expression'''
241 243 if kind == 're':
242 244 return name
243 245 elif kind == 'path':
244 246 return '^' + re.escape(name) + '(?:/|$)'
245 247 elif kind == 'relglob':
246 248 return head + globre(name, '(?:|.*/)', tail)
247 249 elif kind == 'relpath':
248 250 return head + re.escape(name) + tail
249 251 elif kind == 'relre':
250 252 if name.startswith('^'):
251 253 return name
252 254 return '.*' + name
253 255 return head + globre(name, '', tail)
254 256
255 257 def matchfn(pats, tail):
256 258 """build a matching function from a set of patterns"""
257 259 if not pats:
258 260 return
259 261 matches = []
260 262 for k, p in pats:
261 263 try:
262 264 pat = '(?:%s)' % regex(k, p, tail)
263 265 matches.append(re.compile(pat).match)
264 266 except re.error:
265 267 if src: raise Abort("%s: invalid pattern (%s): %s" % (src, k, p))
266 268 else: raise Abort("invalid pattern (%s): %s" % (k, p))
267 269
268 270 def buildfn(text):
269 271 for m in matches:
270 272 r = m(text)
271 273 if r:
272 274 return r
273 275
274 276 return buildfn
275 277
276 278 def globprefix(pat):
277 279 '''return the non-glob prefix of a path, e.g. foo/* -> foo'''
278 280 root = []
279 281 for p in pat.split(os.sep):
280 282 if contains_glob(p): break
281 283 root.append(p)
282 284 return '/'.join(root)
283 285
284 286 pats = []
285 287 files = []
286 288 roots = []
287 289 for kind, name in [patkind(p, dflt_pat) for p in names]:
288 290 if kind in ('glob', 'relpath'):
289 291 name = canonpath(canonroot, cwd, name)
290 292 if name == '':
291 293 kind, name = 'glob', '**'
292 294 if kind in ('glob', 'path', 're'):
293 295 pats.append((kind, name))
294 296 if kind == 'glob':
295 297 root = globprefix(name)
296 298 if root: roots.append(root)
297 299 elif kind == 'relpath':
298 300 files.append((kind, name))
299 301 roots.append(name)
300 302
301 303 patmatch = matchfn(pats, '$') or always
302 304 filematch = matchfn(files, '(?:/|$)') or always
303 305 incmatch = always
304 306 if inc:
305 307 incmatch = matchfn(map(patkind, inc), '(?:/|$)')
306 308 excmatch = lambda fn: False
307 309 if exc:
308 310 excmatch = matchfn(map(patkind, exc), '(?:/|$)')
309 311
310 312 return (roots,
311 313 lambda fn: (incmatch(fn) and not excmatch(fn) and
312 314 (fn.endswith('/') or
313 315 (not pats and not files) or
314 316 (pats and patmatch(fn)) or
315 317 (files and filematch(fn)))),
316 318 (inc or exc or (pats and pats != [('glob', '**')])) and True)
317 319
318 320 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None):
319 321 '''enhanced shell command execution.
320 322 run with environment maybe modified, maybe in different dir.
321 323
322 324 if command fails and onerr is None, return status. if ui object,
323 325 print error message and return status, else raise onerr object as
324 326 exception.'''
325 327 oldenv = {}
326 328 for k in environ:
327 329 oldenv[k] = os.environ.get(k)
328 330 if cwd is not None:
329 331 oldcwd = os.getcwd()
330 332 try:
331 333 for k, v in environ.iteritems():
332 334 os.environ[k] = str(v)
333 335 if cwd is not None and oldcwd != cwd:
334 336 os.chdir(cwd)
335 337 rc = os.system(cmd)
336 338 if rc and onerr:
337 339 errmsg = '%s %s' % (os.path.basename(cmd.split(None, 1)[0]),
338 340 explain_exit(rc)[0])
339 341 if errprefix:
340 342 errmsg = '%s: %s' % (errprefix, errmsg)
341 343 try:
342 344 onerr.warn(errmsg + '\n')
343 345 except AttributeError:
344 346 raise onerr(errmsg)
345 347 return rc
346 348 finally:
347 349 for k, v in oldenv.iteritems():
348 350 if v is None:
349 351 del os.environ[k]
350 352 else:
351 353 os.environ[k] = v
352 354 if cwd is not None and oldcwd != cwd:
353 355 os.chdir(oldcwd)
354 356
355 357 def rename(src, dst):
356 358 """forcibly rename a file"""
357 359 try:
358 360 os.rename(src, dst)
359 361 except:
360 362 os.unlink(dst)
361 363 os.rename(src, dst)
362 364
363 365 def unlink(f):
364 366 """unlink and remove the directory if it is empty"""
365 367 os.unlink(f)
366 368 # try removing directories that might now be empty
367 369 try: os.removedirs(os.path.dirname(f))
368 370 except: pass
369 371
370 372 def copyfiles(src, dst, hardlink=None):
371 373 """Copy a directory tree using hardlinks if possible"""
372 374
373 375 if hardlink is None:
374 376 hardlink = (os.stat(src).st_dev ==
375 377 os.stat(os.path.dirname(dst)).st_dev)
376 378
377 379 if os.path.isdir(src):
378 380 os.mkdir(dst)
379 381 for name in os.listdir(src):
380 382 srcname = os.path.join(src, name)
381 383 dstname = os.path.join(dst, name)
382 384 copyfiles(srcname, dstname, hardlink)
383 385 else:
384 386 if hardlink:
385 387 try:
386 388 os_link(src, dst)
387 389 except:
388 390 hardlink = False
389 391 shutil.copy(src, dst)
390 392 else:
391 393 shutil.copy(src, dst)
392 394
393 395 def audit_path(path):
394 396 """Abort if path contains dangerous components"""
395 397 parts = os.path.normcase(path).split(os.sep)
396 398 if (os.path.splitdrive(path)[0] or parts[0] in ('.hg', '')
397 399 or os.pardir in parts):
398 400 raise Abort(_("path contains illegal component: %s\n") % path)
399 401
400 402 def opener(base, audit=True):
401 403 """
402 404 return a function that opens files relative to base
403 405
404 406 this function is used to hide the details of COW semantics and
405 407 remote file access from higher level code.
406 408 """
407 409 p = base
408 410 audit_p = audit
409 411
410 412 def mktempcopy(name):
411 413 d, fn = os.path.split(name)
412 414 fd, temp = tempfile.mkstemp(prefix=fn, dir=d)
413 415 fp = os.fdopen(fd, "wb")
414 416 try:
415 417 fp.write(file(name, "rb").read())
416 418 except:
417 419 try: os.unlink(temp)
418 420 except: pass
419 421 raise
420 422 fp.close()
421 423 st = os.lstat(name)
422 424 os.chmod(temp, st.st_mode)
423 425 return temp
424 426
425 427 class atomicfile(file):
426 428 """the file will only be copied on close"""
427 429 def __init__(self, name, mode, atomic=False):
428 430 self.__name = name
429 431 self.temp = mktempcopy(name)
430 432 file.__init__(self, self.temp, mode)
431 433 def close(self):
432 434 if not self.closed:
433 435 file.close(self)
434 436 rename(self.temp, self.__name)
435 437 def __del__(self):
436 438 self.close()
437 439
438 440 def o(path, mode="r", text=False, atomic=False):
439 441 if audit_p:
440 442 audit_path(path)
441 443 f = os.path.join(p, path)
442 444
443 445 if not text:
444 446 mode += "b" # for that other OS
445 447
446 448 if mode[0] != "r":
447 449 try:
448 450 nlink = nlinks(f)
449 451 except OSError:
450 452 d = os.path.dirname(f)
451 453 if not os.path.isdir(d):
452 454 os.makedirs(d)
453 455 else:
454 456 if atomic:
455 457 return atomicfile(f, mode)
456 458 if nlink > 1:
457 459 rename(mktempcopy(f), f)
458 460 return file(f, mode)
459 461
460 462 return o
461 463
462 464 def _makelock_file(info, pathname):
463 465 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
464 466 os.write(ld, info)
465 467 os.close(ld)
466 468
467 469 def _readlock_file(pathname):
468 470 return file(pathname).read()
469 471
470 472 def nlinks(pathname):
471 473 """Return number of hardlinks for the given file."""
472 474 return os.stat(pathname).st_nlink
473 475
474 476 if hasattr(os, 'link'):
475 477 os_link = os.link
476 478 else:
477 479 def os_link(src, dst):
478 480 raise OSError(0, _("Hardlinks not supported"))
479 481
480 482 # Platform specific variants
481 483 if os.name == 'nt':
482 484 demandload(globals(), "msvcrt")
483 485 nulldev = 'NUL:'
484 486
485 487 class winstdout:
486 488 '''stdout on windows misbehaves if sent through a pipe'''
487 489
488 490 def __init__(self, fp):
489 491 self.fp = fp
490 492
491 493 def __getattr__(self, key):
492 494 return getattr(self.fp, key)
493 495
494 496 def close(self):
495 497 try:
496 498 self.fp.close()
497 499 except: pass
498 500
499 501 def write(self, s):
500 502 try:
501 503 return self.fp.write(s)
502 504 except IOError, inst:
503 505 if inst.errno != 0: raise
504 506 self.close()
505 507 raise IOError(errno.EPIPE, 'Broken pipe')
506 508
507 509 sys.stdout = winstdout(sys.stdout)
508 510
509 511 def os_rcpath():
510 512 '''return default os-specific hgrc search path'''
511 513 try:
512 514 import win32api, win32process
513 515 proc = win32api.GetCurrentProcess()
514 516 filename = win32process.GetModuleFileNameEx(proc, 0)
515 517 systemrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
516 518 except ImportError:
517 519 systemrc = r'c:\mercurial\mercurial.ini'
518 520
519 521 return [systemrc,
520 522 os.path.join(os.path.expanduser('~'), 'mercurial.ini')]
521 523
522 524 def parse_patch_output(output_line):
523 525 """parses the output produced by patch and returns the file name"""
524 526 pf = output_line[14:]
525 527 if pf[0] == '`':
526 528 pf = pf[1:-1] # Remove the quotes
527 529 return pf
528 530
529 531 try: # ActivePython can create hard links using win32file module
530 532 import win32api, win32con, win32file
531 533
532 534 def os_link(src, dst): # NB will only succeed on NTFS
533 535 win32file.CreateHardLink(dst, src)
534 536
535 537 def nlinks(pathname):
536 538 """Return number of hardlinks for the given file."""
537 539 try:
538 540 fh = win32file.CreateFile(pathname,
539 541 win32file.GENERIC_READ, win32file.FILE_SHARE_READ,
540 542 None, win32file.OPEN_EXISTING, 0, None)
541 543 res = win32file.GetFileInformationByHandle(fh)
542 544 fh.Close()
543 545 return res[7]
544 546 except:
545 547 return os.stat(pathname).st_nlink
546 548
547 549 def testpid(pid):
548 550 '''return False if pid is dead, True if running or not known'''
549 551 try:
550 552 win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION,
551 553 False, pid)
552 554 except:
553 555 return True
554 556
555 557 except ImportError:
556 558 def testpid(pid):
557 559 '''return False if pid dead, True if running or not known'''
558 560 return True
559 561
560 562 def is_exec(f, last):
561 563 return last
562 564
563 565 def set_exec(f, mode):
564 566 pass
565 567
566 568 def set_binary(fd):
567 569 msvcrt.setmode(fd.fileno(), os.O_BINARY)
568 570
569 571 def pconvert(path):
570 572 return path.replace("\\", "/")
571 573
572 574 def localpath(path):
573 575 return path.replace('/', '\\')
574 576
575 577 def normpath(path):
576 578 return pconvert(os.path.normpath(path))
577 579
578 580 makelock = _makelock_file
579 581 readlock = _readlock_file
580 582
581 583 def explain_exit(code):
582 584 return _("exited with status %d") % code, code
583 585
584 586 else:
585 587 nulldev = '/dev/null'
586 588
587 589 def rcfiles(path):
588 590 rcs = [os.path.join(path, 'hgrc')]
589 591 rcdir = os.path.join(path, 'hgrc.d')
590 592 try:
591 593 rcs.extend([os.path.join(rcdir, f) for f in os.listdir(rcdir)
592 594 if f.endswith(".rc")])
593 595 except OSError, inst: pass
594 596 return rcs
595 597
596 598 def os_rcpath():
597 599 '''return default os-specific hgrc search path'''
598 600 path = []
599 601 if len(sys.argv) > 0:
600 602 path.extend(rcfiles(os.path.dirname(sys.argv[0]) +
601 603 '/../etc/mercurial'))
602 604 path.extend(rcfiles('/etc/mercurial'))
603 605 path.append(os.path.expanduser('~/.hgrc'))
604 606 path = [os.path.normpath(f) for f in path]
605 607 return path
606 608
607 609 def parse_patch_output(output_line):
608 610 """parses the output produced by patch and returns the file name"""
609 611 pf = output_line[14:]
610 612 if pf.startswith("'") and pf.endswith("'") and pf.find(" ") >= 0:
611 613 pf = pf[1:-1] # Remove the quotes
612 614 return pf
613 615
614 616 def is_exec(f, last):
615 617 """check whether a file is executable"""
616 618 return (os.stat(f).st_mode & 0100 != 0)
617 619
618 620 def set_exec(f, mode):
619 621 s = os.stat(f).st_mode
620 622 if (s & 0100 != 0) == mode:
621 623 return
622 624 if mode:
623 625 # Turn on +x for every +r bit when making a file executable
624 626 # and obey umask.
625 627 umask = os.umask(0)
626 628 os.umask(umask)
627 629 os.chmod(f, s | (s & 0444) >> 2 & ~umask)
628 630 else:
629 631 os.chmod(f, s & 0666)
630 632
631 633 def set_binary(fd):
632 634 pass
633 635
634 636 def pconvert(path):
635 637 return path
636 638
637 639 def localpath(path):
638 640 return path
639 641
640 642 normpath = os.path.normpath
641 643
642 644 def makelock(info, pathname):
643 645 try:
644 646 os.symlink(info, pathname)
645 647 except OSError, why:
646 648 if why.errno == errno.EEXIST:
647 649 raise
648 650 else:
649 651 _makelock_file(info, pathname)
650 652
651 653 def readlock(pathname):
652 654 try:
653 655 return os.readlink(pathname)
654 656 except OSError, why:
655 657 if why.errno == errno.EINVAL:
656 658 return _readlock_file(pathname)
657 659 else:
658 660 raise
659 661
660 662 def testpid(pid):
661 663 '''return False if pid dead, True if running or not sure'''
662 664 try:
663 665 os.kill(pid, 0)
664 666 return True
665 667 except OSError, inst:
666 668 return inst.errno != errno.ESRCH
667 669
668 670 def explain_exit(code):
669 671 """return a 2-tuple (desc, code) describing a process's status"""
670 672 if os.WIFEXITED(code):
671 673 val = os.WEXITSTATUS(code)
672 674 return _("exited with status %d") % val, val
673 675 elif os.WIFSIGNALED(code):
674 676 val = os.WTERMSIG(code)
675 677 return _("killed by signal %d") % val, val
676 678 elif os.WIFSTOPPED(code):
677 679 val = os.WSTOPSIG(code)
678 680 return _("stopped by signal %d") % val, val
679 681 raise ValueError(_("invalid exit code"))
680 682
681 683 class chunkbuffer(object):
682 684 """Allow arbitrary sized chunks of data to be efficiently read from an
683 685 iterator over chunks of arbitrary size."""
684 686
685 687 def __init__(self, in_iter, targetsize = 2**16):
686 688 """in_iter is the iterator that's iterating over the input chunks.
687 689 targetsize is how big a buffer to try to maintain."""
688 690 self.in_iter = iter(in_iter)
689 691 self.buf = ''
690 692 self.targetsize = int(targetsize)
691 693 if self.targetsize <= 0:
692 694 raise ValueError(_("targetsize must be greater than 0, was %d") %
693 695 targetsize)
694 696 self.iterempty = False
695 697
696 698 def fillbuf(self):
697 699 """Ignore target size; read every chunk from iterator until empty."""
698 700 if not self.iterempty:
699 701 collector = cStringIO.StringIO()
700 702 collector.write(self.buf)
701 703 for ch in self.in_iter:
702 704 collector.write(ch)
703 705 self.buf = collector.getvalue()
704 706 self.iterempty = True
705 707
706 708 def read(self, l):
707 709 """Read L bytes of data from the iterator of chunks of data.
708 710 Returns less than L bytes if the iterator runs dry."""
709 711 if l > len(self.buf) and not self.iterempty:
710 712 # Clamp to a multiple of self.targetsize
711 713 targetsize = self.targetsize * ((l // self.targetsize) + 1)
712 714 collector = cStringIO.StringIO()
713 715 collector.write(self.buf)
714 716 collected = len(self.buf)
715 717 for chunk in self.in_iter:
716 718 collector.write(chunk)
717 719 collected += len(chunk)
718 720 if collected >= targetsize:
719 721 break
720 722 if collected < targetsize:
721 723 self.iterempty = True
722 724 self.buf = collector.getvalue()
723 725 s, self.buf = self.buf[:l], buffer(self.buf, l)
724 726 return s
725 727
726 728 def filechunkiter(f, size = 65536):
727 729 """Create a generator that produces all the data in the file size
728 730 (default 65536) bytes at a time. Chunks may be less than size
729 731 bytes if the chunk is the last chunk in the file, or the file is a
730 732 socket or some other type of file that sometimes reads less data
731 733 than is requested."""
732 734 s = f.read(size)
733 735 while len(s) > 0:
734 736 yield s
735 737 s = f.read(size)
736 738
737 739 def makedate():
738 740 lt = time.localtime()
739 741 if lt[8] == 1 and time.daylight:
740 742 tz = time.altzone
741 743 else:
742 744 tz = time.timezone
743 745 return time.mktime(lt), tz
744 746
745 747 def datestr(date=None, format='%a %b %d %H:%M:%S %Y'):
746 748 """represent a (unixtime, offset) tuple as a localized time.
747 749 unixtime is seconds since the epoch, and offset is the time zone's
748 750 number of seconds away from UTC."""
749 751 t, tz = date or makedate()
750 752 return ("%s %+03d%02d" %
751 753 (time.strftime(format, time.gmtime(float(t) - tz)),
752 754 -tz / 3600,
753 755 ((-tz % 3600) / 60)))
754 756
755 757 def shortuser(user):
756 758 """Return a short representation of a user name or email address."""
757 759 f = user.find('@')
758 760 if f >= 0:
759 761 user = user[:f]
760 762 f = user.find('<')
761 763 if f >= 0:
762 764 user = user[f+1:]
763 765 return user
764 766
765 767 def walkrepos(path):
766 768 '''yield every hg repository under path, recursively.'''
767 769 def errhandler(err):
768 770 if err.filename == path:
769 771 raise err
770 772
771 773 for root, dirs, files in os.walk(path, onerror=errhandler):
772 774 for d in dirs:
773 775 if d == '.hg':
774 776 yield root
775 777 dirs[:] = []
776 778 break
777 779
778 780 _rcpath = None
779 781
780 782 def rcpath():
781 783 '''return hgrc search path. if env var HGRCPATH is set, use it.
782 784 for each item in path, if directory, use files ending in .rc,
783 785 else use item.
784 786 make HGRCPATH empty to only look in .hg/hgrc of current repo.
785 787 if no HGRCPATH, use default os-specific path.'''
786 788 global _rcpath
787 789 if _rcpath is None:
788 790 if 'HGRCPATH' in os.environ:
789 791 _rcpath = []
790 792 for p in os.environ['HGRCPATH'].split(os.pathsep):
791 793 if not p: continue
792 794 if os.path.isdir(p):
793 795 for f in os.listdir(p):
794 796 if f.endswith('.rc'):
795 797 _rcpath.append(os.path.join(p, f))
796 798 else:
797 799 _rcpath.append(p)
798 800 else:
799 801 _rcpath = os_rcpath()
800 802 return _rcpath
@@ -1,181 +1,211 b''
1 1 #!/bin/sh
2 2
3 3 hg init
4 4 mkdir d1 d1/d11 d2
5 5 echo d1/a > d1/a
6 6 echo d1/ba > d1/ba
7 7 echo d1/a1 > d1/d11/a1
8 8 echo d1/b > d1/b
9 9 echo d2/b > d2/b
10 10 hg add d1/a d1/b d1/ba d1/d11/a1 d2/b
11 11 hg commit -m "1" -d "1000000 0"
12 12
13 13 echo "# rename a single file"
14 14 hg rename d1/d11/a1 d2/c
15 15 hg status
16 16 hg update -C
17 17
18 18 echo "# rename --after a single file"
19 19 mv d1/d11/a1 d2/c
20 20 hg rename --after d1/d11/a1 d2/c
21 21 hg status
22 22 hg update -C
23 23
24 24 echo "# move a single file to an existing directory"
25 25 hg rename d1/d11/a1 d2
26 26 hg status
27 27 hg update -C
28 28
29 29 echo "# move --after a single file to an existing directory"
30 30 mv d1/d11/a1 d2
31 31 hg rename --after d1/d11/a1 d2
32 32 hg status
33 33 hg update -C
34 34
35 35 echo "# rename a file using a relative path"
36 36 (cd d1/d11; hg rename ../../d2/b e)
37 37 hg status
38 38 hg update -C
39 39
40 40 echo "# rename --after a file using a relative path"
41 41 (cd d1/d11; mv ../../d2/b e; hg rename --after ../../d2/b e)
42 42 hg status
43 43 hg update -C
44 44
45 45 echo "# rename directory d1 as d3"
46 46 hg rename d1/ d3
47 47 hg status
48 48 hg update -C
49 49
50 50 echo "# rename --after directory d1 as d3"
51 51 mv d1 d3
52 52 hg rename --after d1 d3
53 53 hg status
54 54 hg update -C
55 55
56 56 echo "# move a directory using a relative path"
57 57 (cd d2; mkdir d3; hg rename ../d1/d11 d3)
58 58 hg status
59 59 hg update -C
60 60
61 61 echo "# move --after a directory using a relative path"
62 62 (cd d2; mkdir d3; mv ../d1/d11 d3; hg rename --after ../d1/d11 d3)
63 63 hg status
64 64 hg update -C
65 65
66 66 echo "# move directory d1/d11 to an existing directory d2 (removes empty d1)"
67 67 hg rename d1/d11/ d2
68 68 hg status
69 69 hg update -C
70 70
71 71 echo "# move directories d1 and d2 to a new directory d3"
72 72 mkdir d3
73 73 hg rename d1 d2 d3
74 74 hg status
75 75 hg update -C
76 76
77 77 echo "# move --after directories d1 and d2 to a new directory d3"
78 78 mkdir d3
79 79 mv d1 d2 d3
80 80 hg rename --after d1 d2 d3
81 81 hg status
82 82 hg update -C
83 83
84 84 echo "# move everything under directory d1 to existing directory d2, do not"
85 85 echo "# overwrite existing files (d2/b)"
86 86 hg rename d1/* d2
87 87 hg status
88 88 diff d1/b d2/b
89 89 hg update -C
90 90
91 91 echo "# attempt to move potentially more than one file into a non-existent"
92 92 echo "# directory"
93 93 hg rename 'glob:d1/**' dx
94 94
95 95 echo "# move every file under d1 to d2/d21 (glob)"
96 96 mkdir d2/d21
97 97 hg rename 'glob:d1/**' d2/d21
98 98 hg status
99 99 hg update -C
100 100
101 101 echo "# move --after some files under d1 to d2/d21 (glob)"
102 102 mkdir d2/d21
103 103 mv d1/a d1/d11/a1 d2/d21
104 104 hg rename --after 'glob:d1/**' d2/d21
105 105 hg status
106 106 hg update -C
107 107
108 108 echo "# move every file under d1 starting with an 'a' to d2/d21 (regexp)"
109 109 mkdir d2/d21
110 110 hg rename 're:d1/([^a][^/]*/)*a.*' d2/d21
111 111 hg status
112 112 hg update -C
113 113
114 114 echo "# attempt to overwrite an existing file"
115 115 echo "ca" > d1/ca
116 116 hg rename d1/ba d1/ca
117 117 hg status
118 118 hg update -C
119 119
120 120 echo "# forced overwrite of an existing file"
121 121 echo "ca" > d1/ca
122 122 hg rename --force d1/ba d1/ca
123 123 hg status
124 124 hg update -C
125 125
126 126 echo "# replace a symlink with a file"
127 127 ln -s ba d1/ca
128 128 hg rename --force d1/ba d1/ca
129 129 hg status
130 130 hg update -C
131 131
132 132 echo "# do not copy more than one source file to the same destination file"
133 133 mkdir d3
134 134 hg rename d1/* d2/* d3
135 135 hg status
136 136 hg update -C
137 137
138 138 echo "# move a whole subtree with \"hg rename .\""
139 139 mkdir d3
140 140 (cd d1; hg rename . ../d3)
141 141 hg status
142 142 hg update -C
143 143
144 144 echo "# move a whole subtree with \"hg rename --after .\""
145 145 mkdir d3
146 146 mv d1/* d3
147 147 (cd d1; hg rename --after . ../d3)
148 148 hg status
149 149 hg update -C
150 150
151 151 echo "# move the parent tree with \"hg rename ..\""
152 152 (cd d1/d11; hg rename .. ../../d3)
153 153 hg status
154 154 hg update -C
155 155
156 156 echo "# skip removed files"
157 157 hg remove d1/b
158 158 hg rename d1 d3
159 159 hg status
160 160 hg update -C
161 161
162 162 echo "# transitive rename"
163 163 hg rename d1/b d1/bb
164 164 hg rename d1/bb d1/bc
165 165 hg status
166 166 hg update -C
167 167
168 168 echo "# transitive rename --after"
169 169 hg rename d1/b d1/bb
170 170 mv d1/bb d1/bc
171 171 hg rename --after d1/bb d1/bc
172 172 hg status
173 173 hg update -C
174 174
175 175 echo "# idempotent renames (d1/b -> d1/bb followed by d1/bb -> d1/b)"
176 176 hg rename d1/b d1/bb
177 177 echo "some stuff added to d1/bb" >> d1/bb
178 178 hg rename d1/bb d1/b
179 179 hg status
180 180 hg debugstate | grep copy
181 181 hg update -C
182
183 echo "# check illegal path components"
184
185 hg rename d1/d11/a1 .hg/foo
186 hg status
187 hg rename d1/d11/a1 ../foo
188 hg status
189
190 mv d1/d11/a1 .hg/foo
191 hg rename --after d1/d11/a1 .hg/foo
192 hg status
193 hg update -C
194 rm .hg/foo
195
196 hg rename d1/d11/a1 .hg
197 hg status
198 hg rename d1/d11/a1 ..
199 hg status
200
201 mv d1/d11/a1 .hg
202 hg rename --after d1/d11/a1 .hg
203 hg status
204 hg update -C
205 rm .hg/a1
206
207 (cd d1/d11; hg rename ../../d2/b ../../.hg/foo)
208 hg status
209 (cd d1/d11; hg rename ../../d2/b ../../../foo)
210 hg status
211
@@ -1,256 +1,272 b''
1 1 # rename a single file
2 2 A d2/c
3 3 R d1/d11/a1
4 4 # rename --after a single file
5 5 A d2/c
6 6 R d1/d11/a1
7 7 # move a single file to an existing directory
8 8 A d2/a1
9 9 R d1/d11/a1
10 10 # move --after a single file to an existing directory
11 11 A d2/a1
12 12 R d1/d11/a1
13 13 # rename a file using a relative path
14 14 A d1/d11/e
15 15 R d2/b
16 16 # rename --after a file using a relative path
17 17 A d1/d11/e
18 18 R d2/b
19 19 # rename directory d1 as d3
20 20 copying d1/a to d3/a
21 21 copying d1/b to d3/b
22 22 copying d1/ba to d3/ba
23 23 copying d1/d11/a1 to d3/d11/a1
24 24 removing d1/a
25 25 removing d1/b
26 26 removing d1/ba
27 27 removing d1/d11/a1
28 28 A d3/a
29 29 A d3/b
30 30 A d3/ba
31 31 A d3/d11/a1
32 32 R d1/a
33 33 R d1/b
34 34 R d1/ba
35 35 R d1/d11/a1
36 36 # rename --after directory d1 as d3
37 37 copying d1/a to d3/a
38 38 copying d1/b to d3/b
39 39 copying d1/ba to d3/ba
40 40 copying d1/d11/a1 to d3/d11/a1
41 41 removing d1/a
42 42 removing d1/b
43 43 removing d1/ba
44 44 removing d1/d11/a1
45 45 A d3/a
46 46 A d3/b
47 47 A d3/ba
48 48 A d3/d11/a1
49 49 R d1/a
50 50 R d1/b
51 51 R d1/ba
52 52 R d1/d11/a1
53 53 # move a directory using a relative path
54 54 copying ../d1/d11/a1 to d3/d11/a1
55 55 removing ../d1/d11/a1
56 56 A d2/d3/d11/a1
57 57 R d1/d11/a1
58 58 # move --after a directory using a relative path
59 59 copying ../d1/d11/a1 to d3/d11/a1
60 60 removing ../d1/d11/a1
61 61 A d2/d3/d11/a1
62 62 R d1/d11/a1
63 63 # move directory d1/d11 to an existing directory d2 (removes empty d1)
64 64 copying d1/d11/a1 to d2/d11/a1
65 65 removing d1/d11/a1
66 66 A d2/d11/a1
67 67 R d1/d11/a1
68 68 # move directories d1 and d2 to a new directory d3
69 69 copying d1/a to d3/d1/a
70 70 copying d1/b to d3/d1/b
71 71 copying d1/ba to d3/d1/ba
72 72 copying d1/d11/a1 to d3/d1/d11/a1
73 73 copying d2/b to d3/d2/b
74 74 removing d1/a
75 75 removing d1/b
76 76 removing d1/ba
77 77 removing d1/d11/a1
78 78 removing d2/b
79 79 A d3/d1/a
80 80 A d3/d1/b
81 81 A d3/d1/ba
82 82 A d3/d1/d11/a1
83 83 A d3/d2/b
84 84 R d1/a
85 85 R d1/b
86 86 R d1/ba
87 87 R d1/d11/a1
88 88 R d2/b
89 89 # move --after directories d1 and d2 to a new directory d3
90 90 copying d1/a to d3/d1/a
91 91 copying d1/b to d3/d1/b
92 92 copying d1/ba to d3/d1/ba
93 93 copying d1/d11/a1 to d3/d1/d11/a1
94 94 copying d2/b to d3/d2/b
95 95 removing d1/a
96 96 removing d1/b
97 97 removing d1/ba
98 98 removing d1/d11/a1
99 99 removing d2/b
100 100 A d3/d1/a
101 101 A d3/d1/b
102 102 A d3/d1/ba
103 103 A d3/d1/d11/a1
104 104 A d3/d2/b
105 105 R d1/a
106 106 R d1/b
107 107 R d1/ba
108 108 R d1/d11/a1
109 109 R d2/b
110 110 # move everything under directory d1 to existing directory d2, do not
111 111 # overwrite existing files (d2/b)
112 112 d2/b: not overwriting - file exists
113 113 copying d1/d11/a1 to d2/d11/a1
114 114 removing d1/d11/a1
115 115 A d2/a
116 116 A d2/ba
117 117 A d2/d11/a1
118 118 R d1/a
119 119 R d1/ba
120 120 R d1/d11/a1
121 121 1c1
122 122 < d1/b
123 123 ---
124 124 > d2/b
125 125 # attempt to move potentially more than one file into a non-existent
126 126 # directory
127 127 abort: with multiple sources, destination must be an existing directory
128 128 # move every file under d1 to d2/d21 (glob)
129 129 copying d1/a to d2/d21/a
130 130 copying d1/b to d2/d21/b
131 131 copying d1/ba to d2/d21/ba
132 132 copying d1/d11/a1 to d2/d21/a1
133 133 removing d1/a
134 134 removing d1/b
135 135 removing d1/ba
136 136 removing d1/d11/a1
137 137 A d2/d21/a
138 138 A d2/d21/a1
139 139 A d2/d21/b
140 140 A d2/d21/ba
141 141 R d1/a
142 142 R d1/b
143 143 R d1/ba
144 144 R d1/d11/a1
145 145 # move --after some files under d1 to d2/d21 (glob)
146 146 copying d1/a to d2/d21/a
147 147 copying d1/d11/a1 to d2/d21/a1
148 148 removing d1/a
149 149 removing d1/d11/a1
150 150 A d2/d21/a
151 151 A d2/d21/a1
152 152 R d1/a
153 153 R d1/d11/a1
154 154 # move every file under d1 starting with an 'a' to d2/d21 (regexp)
155 155 copying d1/a to d2/d21/a
156 156 copying d1/d11/a1 to d2/d21/a1
157 157 removing d1/a
158 158 removing d1/d11/a1
159 159 A d2/d21/a
160 160 A d2/d21/a1
161 161 R d1/a
162 162 R d1/d11/a1
163 163 # attempt to overwrite an existing file
164 164 d1/ca: not overwriting - file exists
165 165 ? d1/ca
166 166 # forced overwrite of an existing file
167 167 A d1/ca
168 168 R d1/ba
169 169 # replace a symlink with a file
170 170 A d1/ca
171 171 R d1/ba
172 172 # do not copy more than one source file to the same destination file
173 173 copying d1/d11/a1 to d3/d11/a1
174 174 d3/b: not overwriting - d2/b collides with d1/b
175 175 removing d1/d11/a1
176 176 A d3/a
177 177 A d3/b
178 178 A d3/ba
179 179 A d3/d11/a1
180 180 R d1/a
181 181 R d1/b
182 182 R d1/ba
183 183 R d1/d11/a1
184 184 # move a whole subtree with "hg rename ."
185 185 copying a to ../d3/d1/a
186 186 copying b to ../d3/d1/b
187 187 copying ba to ../d3/d1/ba
188 188 copying d11/a1 to ../d3/d1/d11/a1
189 189 removing a
190 190 removing b
191 191 removing ba
192 192 removing d11/a1
193 193 A d3/d1/a
194 194 A d3/d1/b
195 195 A d3/d1/ba
196 196 A d3/d1/d11/a1
197 197 R d1/a
198 198 R d1/b
199 199 R d1/ba
200 200 R d1/d11/a1
201 201 # move a whole subtree with "hg rename --after ."
202 202 copying a to ../d3/a
203 203 copying b to ../d3/b
204 204 copying ba to ../d3/ba
205 205 copying d11/a1 to ../d3/d11/a1
206 206 removing a
207 207 removing b
208 208 removing ba
209 209 removing d11/a1
210 210 A d3/a
211 211 A d3/b
212 212 A d3/ba
213 213 A d3/d11/a1
214 214 R d1/a
215 215 R d1/b
216 216 R d1/ba
217 217 R d1/d11/a1
218 218 # move the parent tree with "hg rename .."
219 219 copying ../a to ../../d3/a
220 220 copying ../b to ../../d3/b
221 221 copying ../ba to ../../d3/ba
222 222 copying a1 to ../../d3/d11/a1
223 223 removing ../a
224 224 removing ../b
225 225 removing ../ba
226 226 removing a1
227 227 A d3/a
228 228 A d3/b
229 229 A d3/ba
230 230 A d3/d11/a1
231 231 R d1/a
232 232 R d1/b
233 233 R d1/ba
234 234 R d1/d11/a1
235 235 # skip removed files
236 236 copying d1/a to d3/a
237 237 copying d1/ba to d3/ba
238 238 copying d1/d11/a1 to d3/d11/a1
239 239 removing d1/a
240 240 removing d1/ba
241 241 removing d1/d11/a1
242 242 A d3/a
243 243 A d3/ba
244 244 A d3/d11/a1
245 245 R d1/a
246 246 R d1/b
247 247 R d1/ba
248 248 R d1/d11/a1
249 249 # transitive rename
250 250 A d1/bc
251 251 R d1/b
252 252 # transitive rename --after
253 253 A d1/bc
254 254 R d1/b
255 255 # idempotent renames (d1/b -> d1/bb followed by d1/bb -> d1/b)
256 256 M d1/b
257 # check illegal path components
258 abort: path contains illegal component: .hg/foo
259
260 abort: ../foo not under root
261 abort: path contains illegal component: .hg/foo
262
263 ! d1/d11/a1
264 abort: path contains illegal component: .hg/a1
265
266 abort: ../a1 not under root
267 abort: path contains illegal component: .hg/a1
268
269 ! d1/d11/a1
270 abort: path contains illegal component: .hg/foo
271
272 abort: ../../../foo not under root
@@ -1,55 +1,61 b''
1 1 #!/bin/sh
2 2
3 3 mkdir t
4 4 cd t
5 5 hg init
6 6 mkdir -p beans
7 7 for b in kidney navy turtle borlotti black pinto; do
8 8 echo $b > beans/$b
9 9 done
10 10 mkdir -p mammals/Procyonidae
11 11 for m in cacomistle coatimundi raccoon; do
12 12 echo $m > mammals/Procyonidae/$m
13 13 done
14 14 echo skunk > mammals/skunk
15 15 echo fennel > fennel
16 16 echo fenugreek > fenugreek
17 17 echo fiddlehead > fiddlehead
18 18 echo glob:glob > glob:glob
19 19 hg addremove
20 20 hg commit -m "commit #0" -d "1000000 0"
21 21 hg debugwalk
22 22 cd mammals
23 23 hg debugwalk .
24 24 hg debugwalk Procyonidae
25 25 cd Procyonidae
26 26 hg debugwalk .
27 27 hg debugwalk ..
28 28 cd ..
29 29 hg debugwalk ../beans
30 30 hg debugwalk .
31 hg debugwalk .hg
32 hg debugwalk ../.hg
31 33 cd ..
32 34 hg debugwalk -Ibeans
33 35 hg debugwalk 'glob:mammals/../beans/b*'
34 36 hg debugwalk '-X*/Procyonidae' mammals
35 37 hg debugwalk path:mammals
36 38 hg debugwalk ..
37 39 hg debugwalk beans/../..
40 hg debugwalk .hg
41 hg debugwalk beans/../.hg
42 hg debugwalk beans/../.hg/data
43 hg debugwalk beans/.hg
38 44 # Don't know how to test absolute paths without always getting a false
39 45 # error.
40 46 #hg debugwalk `pwd`/beans
41 47 #hg debugwalk `pwd`/..
42 48 hg debugwalk glob:\*
43 49 hg debugwalk 're:.*[kb]$'
44 50 hg debugwalk path:beans/black
45 51 hg debugwalk beans 'glob:beans/*'
46 52 hg debugwalk 'glob:j*'
47 53 hg debugwalk NOEXIST
48 54 mkfifo fifo
49 55 hg debugwalk fifo
50 56 rm fenugreek
51 57 hg debugwalk fenugreek
52 58 hg rm fenugreek
53 59 hg debugwalk fenugreek
54 60 touch new
55 61 hg debugwalk new
@@ -1,87 +1,97 b''
1 1 adding beans/black
2 2 adding beans/borlotti
3 3 adding beans/kidney
4 4 adding beans/navy
5 5 adding beans/pinto
6 6 adding beans/turtle
7 7 adding fennel
8 8 adding fenugreek
9 9 adding fiddlehead
10 10 adding glob:glob
11 11 adding mammals/Procyonidae/cacomistle
12 12 adding mammals/Procyonidae/coatimundi
13 13 adding mammals/Procyonidae/raccoon
14 14 adding mammals/skunk
15 15 f beans/black beans/black
16 16 f beans/borlotti beans/borlotti
17 17 f beans/kidney beans/kidney
18 18 f beans/navy beans/navy
19 19 f beans/pinto beans/pinto
20 20 f beans/turtle beans/turtle
21 21 f fennel fennel
22 22 f fenugreek fenugreek
23 23 f fiddlehead fiddlehead
24 24 f glob:glob glob:glob
25 25 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
26 26 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
27 27 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
28 28 f mammals/skunk mammals/skunk
29 29 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
30 30 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
31 31 f mammals/Procyonidae/raccoon Procyonidae/raccoon
32 32 f mammals/skunk skunk
33 33 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
34 34 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
35 35 f mammals/Procyonidae/raccoon Procyonidae/raccoon
36 36 f mammals/Procyonidae/cacomistle cacomistle
37 37 f mammals/Procyonidae/coatimundi coatimundi
38 38 f mammals/Procyonidae/raccoon raccoon
39 39 f mammals/Procyonidae/cacomistle cacomistle
40 40 f mammals/Procyonidae/coatimundi coatimundi
41 41 f mammals/Procyonidae/raccoon raccoon
42 42 f mammals/skunk ../skunk
43 43 f beans/black ../beans/black
44 44 f beans/borlotti ../beans/borlotti
45 45 f beans/kidney ../beans/kidney
46 46 f beans/navy ../beans/navy
47 47 f beans/pinto ../beans/pinto
48 48 f beans/turtle ../beans/turtle
49 49 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
50 50 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
51 51 f mammals/Procyonidae/raccoon Procyonidae/raccoon
52 52 f mammals/skunk skunk
53 .hg: No such file or directory
54 abort: path contains illegal component: .hg
55
53 56 f beans/black beans/black
54 57 f beans/borlotti beans/borlotti
55 58 f beans/kidney beans/kidney
56 59 f beans/navy beans/navy
57 60 f beans/pinto beans/pinto
58 61 f beans/turtle beans/turtle
59 62 f beans/black beans/black
60 63 f beans/borlotti beans/borlotti
61 64 f mammals/skunk mammals/skunk
62 65 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
63 66 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
64 67 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
65 68 f mammals/skunk mammals/skunk
66 69 abort: .. not under root
67 70 abort: beans/../.. not under root
71 abort: path contains illegal component: .hg
72
73 abort: path contains illegal component: .hg
74
75 abort: path contains illegal component: .hg/data
76
77 beans/.hg: No such file or directory
68 78 f fennel fennel
69 79 f fenugreek fenugreek
70 80 f fiddlehead fiddlehead
71 81 f glob:glob glob:glob
72 82 f beans/black beans/black
73 83 f fenugreek fenugreek
74 84 f glob:glob glob:glob
75 85 f mammals/skunk mammals/skunk
76 86 f beans/black beans/black
77 87 f beans/black beans/black
78 88 f beans/borlotti beans/borlotti
79 89 f beans/kidney beans/kidney
80 90 f beans/navy beans/navy
81 91 f beans/pinto beans/pinto
82 92 f beans/turtle beans/turtle
83 93 NOEXIST: No such file or directory
84 94 fifo: unsupported file type (type is fifo)
85 95 m fenugreek fenugreek exact
86 96 m fenugreek fenugreek exact
87 97 f new new exact
General Comments 0
You need to be logged in to leave comments. Login now