Mercurial > hg > gitweb
changeset 894:62ec665759f2
Merge with TAH.
author | Bryan O'Sullivan <bos@serpentine.com> |
---|---|
date | Sat, 13 Aug 2005 15:23:06 -0800 |
parents | 36c991554ebb (diff) 6d6095823b82 (current diff) |
children | 77b52b864249 |
files | .hgignore CONTRIBUTORS TODO doc/hg.1.txt mercurial/commands.py mercurial/hg.py mercurial/hgweb.py mercurial/revlog.py mercurial/util.py templates/map tests/test-help tests/test-help.out tests/test-merge-revert.out tests/test-merge-revert2 tests/test-merge-revert2.out |
diffstat | 6 files changed, 351 insertions(+), 89 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/commands.py Fri Aug 12 23:54:09 2005 -0800 +++ b/mercurial/commands.py Sat Aug 13 15:23:06 2005 -0800 @@ -14,9 +14,6 @@ class UnknownCommand(Exception): """Exception raised if command is not in the command table.""" -class Abort(Exception): - """Raised if a command needs to print an error and exit.""" - def filterfiles(filters, files): l = [x for x in files if x in filters] @@ -35,30 +32,19 @@ def relpath(repo, args): cwd = repo.getcwd() if cwd: - return [util.pconvert(os.path.normpath(os.path.join(cwd, x))) - for x in args] + return [util.normpath(os.path.join(cwd, x)) for x in args] return args -def matchpats(cwd, pats = [], opts = {}, head = ''): - return util.matcher(cwd, pats or ['.'], opts.get('include'), +def matchpats(repo, cwd, pats = [], opts = {}, head = ''): + return util.matcher(repo, cwd, pats or ['.'], opts.get('include'), opts.get('exclude'), head) -def pathto(n1, n2): - '''return the relative path from one place to another''' - if not n1: return n2 - a, b = n1.split(os.sep), n2.split(os.sep) - a.reverse(), b.reverse() - while a and b and a[-1] == b[-1]: - a.pop(), b.pop() - b.reverse() - return os.sep.join((['..'] * len(a)) + b) - def makewalk(repo, pats, opts, head = ''): cwd = repo.getcwd() - files, matchfn = matchpats(cwd, pats, opts, head) + files, matchfn = matchpats(repo, cwd, pats, opts, head) def walk(): for src, fn in repo.walk(files = files, match = matchfn): - yield src, fn, pathto(cwd, fn) + yield src, fn, util.pathto(cwd, fn) return files, matchfn, walk() def walk(repo, pats, opts, head = ''): @@ -89,7 +75,7 @@ try: num = revlog.rev(revlog.lookup(val)) except KeyError: - raise Abort('invalid revision identifier %s', val) + raise util.Abort('invalid revision identifier %s', val) return num for spec in revs: if spec.find(revrangesep) >= 0: @@ -144,7 +130,7 @@ i += 1 return ''.join(newname) except KeyError, inst: - raise Abort("invalid format spec '%%%s' in output file name", + raise util.Abort("invalid format spec '%%%s' in output file name", inst.args[0]) def make_file(repo, r, pat, node=None, @@ -396,11 +382,10 @@ q = dict(zip(pats, pats)) add, remove = [], [] for src, abs, rel in walk(repo, pats, opts): - if src == 'f': - if repo.dirstate.state(abs) == '?': - add.append(abs) - if rel not in q: ui.status('adding ', rel, '\n') - elif repo.dirstate.state(abs) != 'r' and not os.path.exists(rel): + if src == 'f' and repo.dirstate.state(abs) == '?': + add.append(abs) + if rel not in q: ui.status('adding ', rel, '\n') + if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel): remove.append(abs) if rel not in q: ui.status('removing ', rel, '\n') repo.add(add) @@ -427,7 +412,7 @@ return name if not pats: - raise Abort('at least one file name or pattern required') + raise util.Abort('at least one file name or pattern required') bcache = {} opmap = [['user', getname], ['number', str], ['changeset', getnode]] @@ -478,6 +463,8 @@ ui.warn("abort: destination '%s' already exists\n" % dest) return 1 + dest = os.path.realpath(dest) + class Dircleanup: def __init__(self, dir_): self.rmtree = shutil.rmtree @@ -541,7 +528,7 @@ if not pats and cwd: opts['include'] = [os.path.join(cwd, i) for i in opts['include']] opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']] - fns, match = matchpats((pats and repo.getcwd()) or '', pats, opts) + fns, match = matchpats(repo, (pats and repo.getcwd()) or '', pats, opts) if pats: c, a, d, u = repo.changes(files = fns, match = match) files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r'] @@ -583,7 +570,7 @@ ui.warn("%s in manifest1, but listed as state %s" % (f, state)) errors += 1 if errors: - raise Abort(".hg/dirstate inconsistent with current parent's manifest") + raise util.Abort(".hg/dirstate inconsistent with current parent's manifest") def debugstate(ui, repo): """show the contents of the current dirstate""" @@ -621,6 +608,7 @@ def debugwalk(ui, repo, *pats, **opts): items = list(walk(repo, pats, opts)) + if not items: return fmt = '%%s %%-%ds %%s' % max([len(abs) for (src, abs, rel) in items]) for i in items: print fmt % i @@ -631,12 +619,14 @@ revs = map(lambda x: repo.lookup(x), opts['rev']) if len(revs) > 2: - raise Abort("too many revisions to diff") + raise util.Abort("too many revisions to diff") files = [] - roots, match, results = makewalk(repo, pats, opts) - for src, abs, rel in results: - files.append(abs) + match = util.always + if pats: + roots, match, results = makewalk(repo, pats, opts) + for src, abs, rel in results: + files.append(abs) dodiff(sys.stdout, ui, repo, files, *revs, **{'match': match}) def doexport(ui, repo, changeset, seqno, total, revwidth, opts): @@ -665,7 +655,7 @@ def export(ui, repo, *changesets, **opts): """dump the header and diffs for one or more changesets""" if not changesets: - raise Abort("export requires at least one changeset") + raise util.Abort("export requires at least one changeset") seqno = 0 revs = list(revrange(ui, repo, changesets)) total = len(revs) @@ -762,7 +752,7 @@ files.append(pf) patcherr = f.close() if patcherr: - raise Abort("patch failed") + raise util.Abort("patch failed") if len(files) > 0: addremove(ui, repo, *files) @@ -772,7 +762,7 @@ """create a new repository in the current directory""" if source: - raise Abort("no longer supported: use \"hg clone\" instead") + raise util.Abort("no longer supported: use \"hg clone\" instead") hg.repository(ui, ".", create=1) def locate(ui, repo, *pats, **opts): @@ -1078,8 +1068,8 @@ ''' cwd = repo.getcwd() - files, matchfn = matchpats(cwd, pats, opts) - (c, a, d, u) = [[pathto(cwd, x) for x in n] + files, matchfn = matchpats(repo, cwd, pats, opts) + (c, a, d, u) = [[util.pathto(cwd, x) for x in n] for n in repo.changes(files=files, match=matchfn)] changetypes = [('modified', 'M', c), @@ -1471,8 +1461,6 @@ if options['traceback']: traceback.print_exc() raise - except util.CommandError, inst: - u.warn("abort: %s\n" % inst.args) except hg.RepoError, inst: u.warn("abort: ", inst, "!\n") except SignalInterrupt: @@ -1500,7 +1488,7 @@ u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename)) else: u.warn("abort: %s\n" % inst.strerror) - except Abort, inst: + except util.Abort, inst: u.warn('abort: ', inst.args[0] % inst.args[1:], '\n') sys.exit(1) except TypeError, inst:
--- a/mercurial/hg.py Fri Aug 12 23:54:09 2005 -0800 +++ b/mercurial/hg.py Sat Aug 13 15:23:06 2005 -0800 @@ -10,8 +10,8 @@ from revlog import * from demandload import * demandload(globals(), "re lock urllib urllib2 transaction time socket") -demandload(globals(), "tempfile httprangereader bdiff urlparse stat") -demandload(globals(), "bisect select") +demandload(globals(), "tempfile httprangereader bdiff urlparse") +demandload(globals(), "bisect errno select stat") class filelog(revlog): def __init__(self, opener, path): @@ -300,6 +300,11 @@ def wjoin(self, f): return os.path.join(self.root, f) + def getcwd(self): + cwd = os.getcwd() + if cwd == self.root: return '' + return cwd[len(self.root) + 1:] + def ignore(self, f): if not self.ignorefunc: bigpat = [] @@ -307,14 +312,14 @@ l = file(self.wjoin(".hgignore")) for pat in l: if pat != "\n": - p = util.pconvert(pat[:-1]) + p = pat[:-1] try: - r = re.compile(p) + re.compile(p) except: self.ui.warn("ignoring invalid ignore" + " regular expression '%s'\n" % p) else: - bigpat.append(util.pconvert(pat[:-1])) + bigpat.append(p) except IOError: pass if bigpat: @@ -437,22 +442,69 @@ st.write(e + f) self.dirty = 0 - def walk(self, files = None, match = util.always): + def filterfiles(self, files): + ret = {} + unknown = [] + + for x in files: + if x is '.': + return self.map.copy() + if x not in self.map: + unknown.append(x) + else: + ret[x] = self.map[x] + + if not unknown: + return ret + + b = self.map.keys() + b.sort() + blen = len(b) + + for x in unknown: + bs = bisect.bisect(b, x) + if bs != 0 and b[bs-1] == x: + ret[x] = self.map[x] + continue + while bs < blen: + s = b[bs] + if len(s) > len(x) and s.startswith(x) and s[len(x)] == '/': + ret[s] = self.map[s] + else: + break + bs += 1 + return ret + + def walk(self, files = None, match = util.always, dc=None): self.read() - dc = self.map.copy() + # walk all files by default - if not files: files = [self.root] + if not files: + files = [self.root] + if not dc: + dc = self.map.copy() + elif not dc: + dc = self.filterfiles(files) + known = {'.hg': 1} def seen(fn): if fn in known: return True known[fn] = 1 def traverse(): - for f in util.unique(files): - f = os.path.join(self.root, f) - if os.path.isdir(f): + for ff in util.unique(files): + f = os.path.join(self.root, ff) + try: + st = os.stat(f) + except OSError, inst: + if ff not in dc: self.ui.warn('%s: %s\n' % ( + util.pathto(self.getcwd(), ff), + inst.strerror)) + continue + if stat.S_ISDIR(st.st_mode): for dir, subdirs, fl in os.walk(f): d = dir[len(self.root) + 1:] - nd = os.path.normpath(d) + nd = util.normpath(d) + if nd == '.': nd = '' if seen(nd): subdirs[:] = [] continue @@ -465,8 +517,18 @@ for fn in fl: fn = util.pconvert(os.path.join(d, fn)) yield 'f', fn + elif stat.S_ISREG(st.st_mode): + yield 'f', ff else: - yield 'f', f[len(self.root) + 1:] + kind = 'unknown' + if stat.S_ISCHR(st.st_mode): kind = 'character device' + elif stat.S_ISBLK(st.st_mode): kind = 'block device' + elif stat.S_ISFIFO(st.st_mode): kind = 'fifo' + elif stat.S_ISLNK(st.st_mode): kind = 'symbolic link' + elif stat.S_ISSOCK(st.st_mode): kind = 'socket' + self.ui.warn('%s: unsupported file type (type is %s)\n' % ( + util.pathto(self.getcwd(), ff), + kind)) ks = dc.keys() ks.sort() @@ -477,22 +539,23 @@ # not in .hgignore for src, fn in util.unique(traverse()): - fn = os.path.normpath(fn) + fn = util.normpath(fn) if seen(fn): continue - if fn in dc: - del dc[fn] - elif self.ignore(fn): + if fn not in dc and self.ignore(fn): continue if match(fn): yield src, fn def changes(self, files=None, match=util.always): self.read() - dc = self.map.copy() + if not files: + dc = self.map.copy() + else: + dc = self.filterfiles(files) lookup, modified, added, unknown = [], [], [], [] removed, deleted = [], [] - for src, fn in self.walk(files, match): + for src, fn in self.walk(files, match, dc=dc): try: s = os.stat(os.path.join(self.root, fn)) except OSError: @@ -697,9 +760,7 @@ return filelog(self.opener, f) def getcwd(self): - cwd = os.getcwd() - if cwd == self.root: return '' - return cwd[len(self.root) + 1:] + return self.dirstate.getcwd() def wfile(self, f, mode='r'): return self.wopener(f, mode)
--- a/mercurial/hgweb.py Fri Aug 12 23:54:09 2005 -0800 +++ b/mercurial/hgweb.py Sat Aug 13 15:23:06 2005 -0800 @@ -708,7 +708,12 @@ import BaseHTTPServer class IPv6HTTPServer(BaseHTTPServer.HTTPServer): - address_family = socket.AF_INET6 + address_family = getattr(socket, 'AF_INET6', None) + + def __init__(self, *args, **kwargs): + if self.address_family is None: + raise RepoError('IPv6 not available on this system') + BaseHTTPServer.HTTPServer.__init__(self, *args, **kwargs) class hgwebhandler(BaseHTTPServer.BaseHTTPRequestHandler): def log_error(self, format, *args):
--- a/mercurial/util.py Fri Aug 12 23:54:09 2005 -0800 +++ b/mercurial/util.py Sat Aug 13 15:23:06 2005 -0800 @@ -16,7 +16,8 @@ seen[f] = 1 yield f -class CommandError(Exception): pass +class Abort(Exception): + """Raised if a command needs to print an error and exit.""" def always(fn): return True def never(fn): return False @@ -68,36 +69,52 @@ _globchars = {'[': 1, '{': 1, '*': 1, '?': 1} -def matcher(cwd, names, inc, exc, head = ''): +def pathto(n1, n2): + '''return the relative path from one place to another. + this returns a path in the form used by the local filesystem, not hg.''' + if not n1: return localpath(n2) + a, b = n1.split('/'), n2.split('/') + a.reverse(), b.reverse() + while a and b and a[-1] == b[-1]: + a.pop(), b.pop() + b.reverse() + return os.sep.join((['..'] * len(a)) + b) + +def canonpath(repo, cwd, myname): + rootsep = repo.root + os.sep + name = myname + if not name.startswith(os.sep): + name = os.path.join(repo.root, cwd, name) + name = os.path.normpath(name) + if name.startswith(rootsep): + return pconvert(name[len(rootsep):]) + elif name == repo.root: + return '' + else: + raise Abort('%s not under repository root' % myname) + +def matcher(repo, cwd, names, inc, exc, head = ''): def patkind(name): - for prefix in 're:', 'glob:', 'path:': + for prefix in 're:', 'glob:', 'path:', 'relpath:': if name.startswith(prefix): return name.split(':', 1) for c in name: if c in _globchars: return 'glob', name return 'relpath', name - cwdsep = cwd + os.sep - - def regex(name, tail): + def regex(kind, name, tail): '''convert a pattern into a regular expression''' - kind, name = patkind(name) if kind == 're': return name elif kind == 'path': - return '^' + re.escape(name) + '$' - if cwd: name = os.path.join(cwdsep, name) - name = os.path.normpath(name) - if name == '.': name = '**' + return '^' + re.escape(name) + '(?:/|$)' + elif kind == 'relpath': + return head + re.escape(name) + tail return head + globre(name, '', tail) - def under(fn): - """check if fn is under our cwd""" - return not cwd or fn.startswith(cwdsep) - def matchfn(pats, tail): """build a matching function from a set of patterns""" if pats: - pat = '(?:%s)' % '|'.join([regex(p, tail) for p in pats]) + pat = '(?:%s)' % '|'.join([regex(k, p, tail) for (k, p) in pats]) return re.compile(pat).match def globprefix(pat): @@ -106,18 +123,29 @@ for p in pat.split(os.sep): if patkind(p)[0] == 'glob': break root.append(p) - return os.sep.join(root) + return '/'.join(root) - patkinds = map(patkind, names) - pats = [name for (kind, name) in patkinds if kind != 'relpath'] - files = [name for (kind, name) in patkinds if kind == 'relpath'] - roots = filter(None, map(globprefix, pats)) + files - if cwd: roots = [cwdsep + r for r in roots] + pats = [] + files = [] + roots = [] + for kind, name in map(patkind, names): + if kind in ('glob', 'relpath'): + name = canonpath(repo, cwd, name) + if name == '': + kind, name = 'glob', '**' + if kind in ('glob', 'path', 're'): + pats.append((kind, name)) + if kind == 'glob': + root = globprefix(name) + if root: roots.append(root) + elif kind == 'relpath': + files.append((kind, name)) + roots.append(name) patmatch = matchfn(pats, '$') or always filematch = matchfn(files, '(?:/|$)') or always - incmatch = matchfn(inc, '(?:/|$)') or always - excmatch = matchfn(exc, '(?:/|$)') or (lambda fn: False) + incmatch = matchfn(map(patkind, inc), '(?:/|$)') or always + excmatch = matchfn(map(patkind, exc), '(?:/|$)') or (lambda fn: False) return roots, lambda fn: (incmatch(fn) and not excmatch(fn) and (fn.endswith('/') or @@ -133,7 +161,7 @@ explain_exit(rc)[0]) if errprefix: errmsg = "%s: %s" % (errprefix, errmsg) - raise CommandError(errmsg) + raise Abort(errmsg) def rename(src, dst): try: @@ -178,6 +206,12 @@ def pconvert(path): return path.replace("\\", "/") + def localpath(path): + return path.replace('/', '\\') + + def normpath(path): + return pconvert(os.path.normpath(path)) + makelock = _makelock_file readlock = _readlock_file @@ -206,6 +240,11 @@ def pconvert(path): return path + def localpath(path): + return path + + normpath = os.path.normpath + def makelock(info, pathname): try: os.symlink(info, pathname)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-walk Sat Aug 13 15:23:06 2005 -0800 @@ -0,0 +1,55 @@ +#!/bin/sh + +mkdir t +cd t +hg init +mkdir -p beans +for b in kidney navy turtle borlotti black pinto; do + echo $b > beans/$b +done +mkdir -p mammals/Procyonidae +for m in cacomistle coatimundi raccoon; do + echo $m > mammals/Procyonidae/$m +done +echo skunk > mammals/skunk +echo fennel > fennel +echo fenugreek > fenugreek +echo fiddlehead > fiddlehead +echo glob:glob > glob:glob +hg addremove +hg commit -m "commit #0" -d "0 0" +hg debugwalk +cd mammals +hg debugwalk +hg debugwalk Procyonidae +cd Procyonidae +hg debugwalk +hg debugwalk .. +cd .. +hg debugwalk ../beans +hg debugwalk +cd .. +hg debugwalk -Ibeans +hg debugwalk 'mammals/../beans/b*' +hg debugwalk '-X*/Procyonidae' mammals +hg debugwalk path:mammals +hg debugwalk .. +hg debugwalk beans/../.. +# Don't know how to test absolute paths without always getting a false +# error. +#hg debugwalk `pwd`/beans +#hg debugwalk `pwd`/.. +hg debugwalk glob:\* +hg debugwalk 're:.*[kb]$' +hg debugwalk path:beans/black +hg debugwalk beans 'beans/*' +hg debugwalk 'j*' +hg debugwalk NOEXIST +mkfifo fifo +hg debugwalk fifo +rm fenugreek +hg debugwalk fenugreek +hg rm fenugreek +hg debugwalk fenugreek +touch new +hg debugwalk new
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-walk.out Sat Aug 13 15:23:06 2005 -0800 @@ -0,0 +1,114 @@ ++ hg init ++ hg addremove +adding fennel +adding fenugreek +adding fiddlehead +adding glob:glob +adding beans/black +adding beans/borlotti +adding beans/kidney +adding beans/navy +adding beans/pinto +adding beans/turtle +adding mammals/skunk +adding mammals/Procyonidae/cacomistle +adding mammals/Procyonidae/coatimundi +adding mammals/Procyonidae/raccoon ++ hg commit -m commit #0 -d 0 0 ++ hg debugwalk +f fennel fennel +f fenugreek fenugreek +f fiddlehead fiddlehead +f glob:glob glob:glob +f beans/black beans/black +f beans/borlotti beans/borlotti +f beans/kidney beans/kidney +f beans/navy beans/navy +f beans/pinto beans/pinto +f beans/turtle beans/turtle +f mammals/skunk mammals/skunk +f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle +f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi +f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon ++ hg debugwalk +f mammals/skunk skunk +f mammals/Procyonidae/cacomistle Procyonidae/cacomistle +f mammals/Procyonidae/coatimundi Procyonidae/coatimundi +f mammals/Procyonidae/raccoon Procyonidae/raccoon ++ hg debugwalk Procyonidae +f mammals/Procyonidae/cacomistle Procyonidae/cacomistle +f mammals/Procyonidae/coatimundi Procyonidae/coatimundi +f mammals/Procyonidae/raccoon Procyonidae/raccoon ++ hg debugwalk +f mammals/Procyonidae/cacomistle cacomistle +f mammals/Procyonidae/coatimundi coatimundi +f mammals/Procyonidae/raccoon raccoon ++ hg debugwalk .. +f mammals/skunk ../skunk +f mammals/Procyonidae/cacomistle cacomistle +f mammals/Procyonidae/coatimundi coatimundi +f mammals/Procyonidae/raccoon raccoon ++ hg debugwalk ../beans +f beans/black ../beans/black +f beans/borlotti ../beans/borlotti +f beans/kidney ../beans/kidney +f beans/navy ../beans/navy +f beans/pinto ../beans/pinto +f beans/turtle ../beans/turtle ++ hg debugwalk +f mammals/skunk skunk +f mammals/Procyonidae/cacomistle Procyonidae/cacomistle +f mammals/Procyonidae/coatimundi Procyonidae/coatimundi +f mammals/Procyonidae/raccoon Procyonidae/raccoon ++ hg debugwalk -Ibeans +f beans/black beans/black +f beans/borlotti beans/borlotti +f beans/kidney beans/kidney +f beans/navy beans/navy +f beans/pinto beans/pinto +f beans/turtle beans/turtle ++ hg debugwalk mammals/../beans/b* +f beans/black beans/black +f beans/borlotti beans/borlotti ++ hg debugwalk -X*/Procyonidae mammals +f mammals/skunk mammals/skunk ++ hg debugwalk path:mammals +f mammals/skunk mammals/skunk +f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle +f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi +f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon ++ hg debugwalk .. +abort: .. not under repository root ++ hg debugwalk beans/../.. +abort: beans/../.. not under repository root ++ hg debugwalk glob:* +f fennel fennel +f fenugreek fenugreek +f fiddlehead fiddlehead +f glob:glob glob:glob ++ hg debugwalk re:.*[kb]$ +f fenugreek fenugreek +f glob:glob glob:glob +f beans/black beans/black +f mammals/skunk mammals/skunk ++ hg debugwalk path:beans/black +f beans/black beans/black ++ hg debugwalk beans beans/* +f beans/black beans/black +f beans/borlotti beans/borlotti +f beans/kidney beans/kidney +f beans/navy beans/navy +f beans/pinto beans/pinto +f beans/turtle beans/turtle ++ hg debugwalk j* ++ hg debugwalk NOEXIST +NOEXIST: No such file or directory ++ hg debugwalk fifo +fifo: unsupported file type (type is fifo) ++ hg debugwalk fenugreek +m fenugreek fenugreek ++ hg rm fenugreek ++ hg debugwalk fenugreek +m fenugreek fenugreek ++ hg debugwalk new +f new new