Mercurial > hg-stable
changeset 1782:b9671b41e360
merge with crew
author | Benoit Boissinot <benoit.boissinot@ens-lyon.org> |
---|---|
date | Tue, 21 Feb 2006 16:46:38 +0100 |
parents | 284fc722c342 (current diff) 982fb022a16a (diff) |
children | 35a05f177267 e431344e604c |
files | mercurial/commands.py mercurial/localrepo.py |
diffstat | 33 files changed, 760 insertions(+), 212 deletions(-) [+] |
line wrap: on
line diff
--- a/contrib/hbisect.py Tue Feb 14 21:11:57 2006 +0100 +++ b/contrib/hbisect.py Tue Feb 21 16:46:38 2006 +0100 @@ -187,7 +187,7 @@ check_clean(self.ui, self.repo) rev = self.next() self.ui.write("Now testing %s\n" % hg.hex(rev)) - return self.repo.update(rev, allow=True, force=True) + return self.repo.update(rev, force=True) def good(self, rev): self.goodrevs.append(rev) @@ -232,7 +232,7 @@ b.good(new_rev) ui.write("it is good\n") anc = b.ancestors() - repo.update(new_rev, allow=True, force=True) + repo.update(new_rev, force=True) for v in anc: if v != rev: ui.warn("fail to found cset! :(\n")
--- a/doc/hg.1.txt Tue Feb 14 21:11:57 2006 +0100 +++ b/doc/hg.1.txt Tue Feb 21 16:46:38 2006 +0100 @@ -223,9 +223,11 @@ probably with undesirable results. options: - -a, --text treat all files as text - -I, --include <pat> include names matching the given patterns - -X, --exclude <pat> exclude names matching the given patterns + -a, --text treat all files as text + -I, --include <pat> include names matching the given patterns + -p, --show-function show which function each change is in + -X, --exclude <pat> exclude names matching the given patterns + -w, --ignore-all-space ignore white space when comparing lines export [-o filespec] [revision] ...:: Print the changeset header and diffs for one or more revisions. @@ -374,6 +376,11 @@ options: -I, --include <pat> include names matching the given patterns -X, --exclude <pat> exclude names matching the given patterns + -b, --branch show branches + -k, --keyword <str> search for keywords + -l, --limit <num> print no more than this many changes + -M, --no-merges do not show merges + -m, --only-merges only show merges -r, --rev <A> show the specified revision or range -p, --patch show patch @@ -541,10 +548,12 @@ options: -A, --accesslog <file> name of access log file to write to + -d, --daemon run server in background, as a daemon -E, --errorlog <file> name of error log file to write to -a, --address <addr> address to use -p, --port <n> port to use (default: 8000) -n, --name <name> name to show in web pages (default: working dir) + --pid-file <file> write server process ID to given file -t, --templatedir <path> web templates to use -6, --ipv6 use IPv6 in addition to IPv4 @@ -600,9 +609,12 @@ This lists both regular and local tags. -tip:: +tip [-p]:: Show the tip revision. + options: + -p, --patch show patch + unbundle <file>:: (EXPERIMENTAL)
--- a/doc/hgrc.5.txt Tue Feb 14 21:11:57 2006 +0100 +++ b/doc/hgrc.5.txt Tue Feb 21 16:46:38 2006 +0100 @@ -145,20 +145,71 @@ incoming.email = /my/email/hook incoming.autobuild = /my/build/hook + Most hooks are run with environment variables set that give added + useful information. For each hook below, the environment variables + it is passed are listed with names of the form "$HG_foo". + changegroup;; - Run after a changegroup has been added via push or pull. Passed - the ID of the first new changeset in $NODE. + Run after a changegroup has been added via push, pull or + unbundle. ID of the first new changeset is in $HG_NODE. commit;; Run after a changeset has been created in the local repository. - Passed the ID of the newly created changeset in environment - variable $NODE. + ID of the newly created changeset is in $HG_NODE. Parent + changeset IDs are in $HG_PARENT1 and $HG_PARENT2. incoming;; Run after a changeset has been pulled, pushed, or unbundled into - the local repository. Passed the ID of the newly arrived - changeset in environment variable $NODE. + the local repository. The ID of the newly arrived changeset is in + $HG_NODE. + outgoing;; + Run after sending changes from local repository to another. ID of + first changeset sent is in $HG_NODE. Source of operation is in + $HG_SOURCE; see "preoutgoing" hook for description. + prechangegroup;; + Run before a changegroup is added via push, pull or unbundle. + Exit status 0 allows the changegroup to proceed. Non-zero status + will cause the push, pull or unbundle to fail. precommit;; - Run before starting a commit. Exit status 0 allows the commit to - proceed. Non-zero status will cause the commit to fail. + Run before starting a local commit. Exit status 0 allows the + commit to proceed. Non-zero status will cause the commit to fail. + Parent changeset IDs are in $HG_PARENT1 and $HG_PARENT2. + preoutgoing;; + Run before computing changes to send from the local repository to + another. Non-zero status will cause failure. This lets you + prevent pull over http or ssh. Also prevents against local pull, + push (outbound) or bundle commands, but not effective, since you + can just copy files instead then. Source of operation is in + $HG_SOURCE. If "serve", operation is happening on behalf of + remote ssh or http repository. If "push", "pull" or "bundle", + operation is happening on behalf of repository on same system. + pretag;; + Run before creating a tag. Exit status 0 allows the tag to be + created. Non-zero status will cause the tag to fail. ID of + changeset to tag is in $HG_NODE. Name of tag is in $HG_TAG. Tag + is local if $HG_LOCAL=1, in repo if $HG_LOCAL=0. + pretxnchangegroup;; + Run after a changegroup has been added via push, pull or unbundle, + but before the transaction has been committed. Changegroup is + visible to hook program. This lets you validate incoming changes + before accepting them. Passed the ID of the first new changeset + in $HG_NODE. Exit status 0 allows the transaction to commit. + Non-zero status will cause the transaction to be rolled back and + the push, pull or unbundle will fail. + pretxncommit;; + Run after a changeset has been created but the transaction not yet + committed. Changeset is visible to hook program. This lets you + validate commit message and changes. Exit status 0 allows the + commit to proceed. Non-zero status will cause the transaction to + be rolled back. ID of changeset is in $HG_NODE. Parent changeset + IDs are in $HG_PARENT1 and $HG_PARENT2. + tag;; + Run after a tag is created. ID of tagged changeset is in + $HG_NODE. Name of tag is in $HG_TAG. Tag is local if + $HG_LOCAL=1, in repo if $HG_LOCAL=0. + + In earlier releases, the names of hook environment variables did not + have a "HG_" prefix. These unprefixed names are still provided in + the environment for backwards compatibility, but their use is + deprecated, and they will be removed in a future release. http_proxy:: Used to access web-based Mercurial repositories through a HTTP
--- a/mercurial/commands.py Tue Feb 14 21:11:57 2006 +0100 +++ b/mercurial/commands.py Tue Feb 21 16:46:38 2006 +0100 @@ -115,8 +115,8 @@ yield rev minrev, maxrev = min(revs), max(revs) - for file in files: - filelog = repo.file(file) + for file_ in files: + filelog = repo.file(file_) # A zero count may be a directory or deleted file, so # try to find matching entries on the slow path. if filelog.count() == 0: @@ -127,7 +127,7 @@ if rev < minrev: break fncache.setdefault(rev, []) - fncache[rev].append(file) + fncache[rev].append(file_) wanted[rev] = 1 if slowpath: # The slow path checks files modified in every changeset. @@ -261,7 +261,7 @@ mode) def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always, - changes=None, text=False): + changes=None, text=False, opts={}): if not changes: changes = repo.changes(node1, node2, files, match=match) modified, added, removed, deleted, unknown = changes @@ -296,8 +296,8 @@ date1 = util.datestr(change[2]) diffopts = ui.diffopts() - showfunc = diffopts['showfunc'] - ignorews = diffopts['ignorews'] + showfunc = opts.get('show_function') or diffopts['showfunc'] + ignorews = opts.get('ignore_all_space') or diffopts['ignorews'] for f in modified: to = None if f in mmap: @@ -447,7 +447,6 @@ f = f.lstrip("^") if not ui.debugflag and f.startswith("debug"): continue - d = "" doc = e[0].__doc__ if not doc: doc = _("(No help text available)") @@ -622,7 +621,7 @@ dest = ui.expandpath(dest, repo.root) other = hg.repository(ui, dest) o = repo.findoutgoing(other) - cg = repo.changegroup(o) + cg = repo.changegroup(o, 'bundle') try: f.write("HG10") @@ -725,8 +724,8 @@ # can end up with extra data in the cloned revlogs that's # not pointed to by changesets, thus causing verify to # fail - l1 = lock.lock(os.path.join(source, ".hg", "lock")) - except OSError: + l1 = other.lock() + except lock.LockException: copy = False if copy: @@ -818,14 +817,19 @@ reasons = {'?': _('is not managed'), 'a': _('has been marked for add'), 'r': _('has been marked for remove')} - reason = reasons.get(repo.dirstate.state(abs)) + state = repo.dirstate.state(abs) + reason = reasons.get(state) if reason: + if state == 'a': + origsrc = repo.dirstate.copied(abs) + if origsrc is not None: + return origsrc if exact: ui.warn(_('%s: not copying - file %s\n') % (rel, reason)) else: - return True - - def copy(abssrc, relsrc, target, exact): + return abs + + def copy(origsrc, abssrc, relsrc, target, exact): abstarget = util.canonpath(repo.root, cwd, target) reltarget = util.pathto(cwd, abstarget) prevsrc = targets.get(abstarget) @@ -864,7 +868,7 @@ if ui.verbose or not exact: ui.status(_('copying %s to %s\n') % (relsrc, reltarget)) targets[abstarget] = abssrc - repo.copy(abssrc, abstarget) + repo.copy(origsrc, abstarget) copied.append((abssrc, relsrc, exact)) def targetpathfn(pat, dest, srcs): @@ -938,8 +942,9 @@ for pat in pats: srcs = [] for tag, abssrc, relsrc, exact in walk(repo, [pat], opts): - if okaytocopy(abssrc, relsrc, exact): - srcs.append((abssrc, relsrc, exact)) + origsrc = okaytocopy(abssrc, relsrc, exact) + if origsrc: + srcs.append((origsrc, abssrc, relsrc, exact)) if not srcs: continue copylist.append((tfn(pat, dest, srcs), srcs)) @@ -947,8 +952,8 @@ raise util.Abort(_('no files to copy')) for targetpath, srcs in copylist: - for abssrc, relsrc, exact in srcs: - copy(abssrc, relsrc, targetpath(abssrc), exact) + for origsrc, abssrc, relsrc, exact in srcs: + copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact) if errors: ui.warn(_('(consider using --after)\n')) @@ -980,6 +985,18 @@ a = r.ancestor(r.lookup(rev1), r.lookup(rev2)) ui.write("%d:%s\n" % (r.rev(a), hex(a))) +def debugrebuildstate(ui, repo, rev=None): + """rebuild the dirstate as it would look like for the given revision""" + if not rev: + rev = repo.changelog.tip() + else: + rev = repo.lookup(rev) + change = repo.changelog.read(rev) + n = change[0] + files = repo.manifest.readflags(n) + wlock = repo.wlock() + repo.dirstate.rebuild(rev, files.iteritems()) + def debugcheckstate(ui, repo): """validate the correctness of the current dirstate""" parent1, parent2 = repo.dirstate.parents() @@ -1140,7 +1157,7 @@ fns, matchfn, anypats = matchpats(repo, pats, opts) dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn, - text=opts['text']) + text=opts['text'], opts=opts) def doexport(ui, repo, changeset, seqno, total, revwidth, opts): node = repo.lookup(changeset) @@ -1284,6 +1301,7 @@ s = linestate(line, lnum, cstart, cend) m[s] = s + # FIXME: prev isn't used, why ? prev = {} ucache = {} def display(fn, rev, states, prevstates): @@ -1593,7 +1611,19 @@ self.write(*args) def __getattr__(self, key): return getattr(self.ui, key) + changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts) + + if opts['limit']: + try: + limit = int(opts['limit']) + except ValueError: + raise util.Abort(_('limit must be a positive integer')) + if limit <= 0: raise util.Abort(_('limit must be positive')) + else: + limit = sys.maxint + count = 0 + for st, rev, fns in changeiter: if st == 'window': du = dui(ui) @@ -1607,7 +1637,6 @@ if opts['only_merges'] and len(parents) != 2: continue - br = None if opts['keyword']: changes = getchange(rev) miss = 0 @@ -1620,7 +1649,8 @@ if miss: continue - if opts['branch']: + br = None + if opts['branches']: br = repo.branchlookup([repo.changelog.node(rev)]) show_changeset(du, repo, rev, brinfo=br) @@ -1629,8 +1659,11 @@ dodiff(du, du, repo, prev, changenode, match=matchfn) du.write("\n\n") elif st == 'iter': - for args in du.hunk[rev]: - ui.write(*args) + if count == limit: break + if du.hunk[rev]: + count += 1 + for args in du.hunk[rev]: + ui.write(*args) def manifest(ui, repo, rev=None): """output the latest or given revision of the project manifest @@ -1681,7 +1714,7 @@ dodiff(ui, ui, repo, prev, n) ui.write("\n") -def parents(ui, repo, rev=None): +def parents(ui, repo, rev=None, branches=None): """show the parents of the working dir or revision Print the working directory's parent revisions. @@ -1691,9 +1724,12 @@ else: p = repo.dirstate.parents() + br = None + if branches is not None: + br = repo.branchlookup(p) for n in p: if n != nullid: - show_changeset(ui, repo, changenode=n) + show_changeset(ui, repo, changenode=n, brinfo=br) def paths(ui, search=None): """show definition of symbolic path names @@ -1999,7 +2035,7 @@ arg, roots = getarg() nodes = map(bin, roots.split(" ")) - cg = repo.changegroup(nodes) + cg = repo.changegroup(nodes, 'serve') while 1: d = cg.read(4096) if not d: @@ -2022,6 +2058,16 @@ if opts[o]: ui.setconfig("web", o, opts[o]) + if opts['daemon'] and not opts['daemon_pipefds']: + rfd, wfd = os.pipe() + args = sys.argv[:] + args.append('--daemon-pipefds=%d,%d' % (rfd, wfd)) + pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0), + args[0], args) + os.close(wfd) + os.read(rfd, 1) + os._exit(0) + try: httpd = hgweb.create_server(repo) except socket.error, inst: @@ -2040,6 +2086,25 @@ ui.status(_('listening at http://%s:%d/\n') % (addr, port)) else: ui.status(_('listening at http://%s/\n') % addr) + + if opts['pid_file']: + fp = open(opts['pid_file'], 'w') + fp.write(str(os.getpid())) + fp.close() + + if opts['daemon_pipefds']: + rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')] + os.close(rfd) + os.write(wfd, 'y') + os.close(wfd) + sys.stdout.flush() + sys.stderr.flush() + fd = os.open(util.nulldev, os.O_RDWR) + if fd != 0: os.dup2(fd, 0) + if fd != 1: os.dup2(fd, 1) + if fd != 2: os.dup2(fd, 2) + if fd not in (0, 1, 2): os.close(fd) + httpd.serve_forever() def status(ui, repo, *pats, **opts): @@ -2116,8 +2181,12 @@ if name.find(c) >= 0: raise util.Abort(_("%s cannot be used in a tag name") % repr(c)) + repo.hook('pretag', throw=True, node=r, tag=name, + local=int(not not opts['local'])) + if opts['local']: repo.opener("localtags", "a").write("%s %s\n" % (r, name)) + repo.hook('tag', node=r, tag=name, local=1) return for x in repo.changes(): @@ -2133,6 +2202,7 @@ _("Added tag %s for changeset %s") % (name, r)) try: repo.commit([".hgtags"], message, opts['user'], opts['date']) + repo.hook('tag', node=r, tag=name, local=0) except ValueError, inst: raise util.Abort(str(inst)) @@ -2153,13 +2223,18 @@ r = " ?:?" ui.write("%-30s %s\n" % (t, r)) -def tip(ui, repo): +def tip(ui, repo, **opts): """show the tip revision Show the tip revision. """ n = repo.changelog.tip() - show_changeset(ui, repo, changenode=n) + br = None + if opts['branches']: + br = repo.branchlookup([n]) + show_changeset(ui, repo, changenode=n, brinfo=br) + if opts['patch']: + dodiff(ui, ui, repo, repo.changelog.parents(n)[0], n) def unbundle(ui, repo, fname, **opts): """apply a changegroup file @@ -2317,6 +2392,10 @@ _('forcibly copy over an existing managed file'))], _('hg copy [OPTION]... [SOURCE]... DEST')), "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')), + "debugrebuildstate": + (debugrebuildstate, + [('r', 'rev', "", _("revision to rebuild to"))], + _('debugrebuildstate [-r REV] [REV]')), "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')), "debugconfig": (debugconfig, [], _('debugconfig')), "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')), @@ -2335,7 +2414,12 @@ [('r', 'rev', [], _('revision')), ('a', 'text', None, _('treat all files as text')), ('I', 'include', [], _('include names matching the given patterns')), - ('X', 'exclude', [], _('exclude names matching the given patterns'))], + ('p', 'show-function', None, + _('show which function each change is in')), + ('w', 'ignore-all-space', None, + _('ignore white space when comparing lines')), + ('X', 'exclude', [], + _('exclude names matching the given patterns'))], _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')), "^export": (export, @@ -2363,7 +2447,7 @@ _('hg grep [OPTION]... PATTERN [FILE]...')), "heads": (heads, - [('b', 'branches', None, _('find branch info')), + [('b', 'branches', None, _('show branches')), ('r', 'rev', '', _('show only heads which are descendants of rev'))], _('hg heads [-b] [-r <rev>]')), "help": (help_, [], _('hg help [COMMAND]')), @@ -2397,8 +2481,9 @@ (log, [('I', 'include', [], _('include names matching the given patterns')), ('X', 'exclude', [], _('exclude names matching the given patterns')), - ('b', 'branch', None, _('show branches')), + ('b', 'branches', None, _('show branches')), ('k', 'keyword', [], _('search for a keyword')), + ('l', 'limit', '', _('limit number of changes displayed')), ('r', 'rev', [], _('show the specified revision or range')), ('M', 'no-merges', None, _('do not show merges')), ('m', 'only-merges', None, _('show only merges')), @@ -2410,7 +2495,10 @@ ('p', 'patch', None, _('show patch')), ('n', 'newest-first', None, _('show newest record first'))], _('hg outgoing [-p] [-n] [-M] [DEST]')), - "^parents": (parents, [], _('hg parents [REV]')), + "^parents": + (parents, + [('b', 'branches', None, _('show branches'))], + _('hg parents [-b] [REV]')), "paths": (paths, [], _('hg paths [NAME]')), "^pull": (pull, @@ -2462,11 +2550,14 @@ "^serve": (serve, [('A', 'accesslog', '', _('name of access log file to write to')), + ('d', 'daemon', None, _('run server in background')), + ('', 'daemon-pipefds', '', _('used internally by daemon mode')), ('E', 'errorlog', '', _('name of error log file to write to')), ('p', 'port', 0, _('port to use (default: 8000)')), ('a', 'address', '', _('address to use')), ('n', 'name', '', _('name to show in web pages (default: working dir)')), + ('', 'pid-file', '', _('name of file to write process ID to')), ('', 'stdio', None, _('for remote clients')), ('t', 'templates', '', _('web templates to use')), ('', 'style', '', _('template style to use')), @@ -2494,7 +2585,11 @@ ('r', 'rev', '', _('revision to tag'))], _('hg tag [-r REV] [OPTION]... NAME')), "tags": (tags, [], _('hg tags')), - "tip": (tip, [], _('hg tip')), + "tip": + (tip, + [('b', 'branches', None, _('show branches')), + ('p', 'patch', None, _('show patch'))], + _('hg [-b] [-p] tip')), "unbundle": (unbundle, [('u', 'update', None, @@ -2534,17 +2629,20 @@ def find(cmd): """Return (aliases, command table entry) for command string.""" choice = None + count = 0 for e in table.keys(): aliases = e.lstrip("^").split("|") if cmd in aliases: return aliases, table[e] for a in aliases: if a.startswith(cmd): - if choice: - raise AmbiguousCommand(cmd) - else: - choice = aliases, table[e] - break + count += 1 + choice = aliases, table[e] + break + + if count > 1: + raise AmbiguousCommand(cmd) + if choice: return choice
--- a/mercurial/dirstate.py Tue Feb 14 21:11:57 2006 +0100 +++ b/mercurial/dirstate.py Tue Feb 21 16:46:38 2006 +0100 @@ -197,6 +197,19 @@ def clear(self): self.map = {} + self.copies = {} + self.markdirty() + + def rebuild(self, parent, files): + self.clear() + umask = os.umask(0) + os.umask(umask) + for f, mode in files: + if mode: + self.map[f] = ('n', ~umask, -1, 0) + else: + self.map[f] = ('n', ~umask & 0666, -1, 0) + self.pl = (parent, nullid) self.markdirty() def write(self): @@ -270,11 +283,11 @@ elif not dc: dc = self.filterfiles(files) - def statmatch(file, stat): - file = util.pconvert(file) - if file not in dc and self.ignore(file): + def statmatch(file_, stat): + file_ = util.pconvert(file_) + if file_ not in dc and self.ignore(file_): return False - return match(file) + return match(file_) return self.walkhelper(files=files, statmatch=statmatch, dc=dc) @@ -350,9 +363,9 @@ continue if stat.S_ISDIR(st.st_mode): cmp1 = (lambda x, y: cmp(x[1], y[1])) - sorted = [ x for x in findfiles(f) ] - sorted.sort(cmp1) - for e in sorted: + sorted_ = [ x for x in findfiles(f) ] + sorted_.sort(cmp1) + for e in sorted_: yield e else: ff = util.normpath(ff) @@ -380,7 +393,7 @@ for src, fn, st in self.statwalk(files, match): try: - type, mode, size, time = self[fn] + type_, mode, size, time = self[fn] except KeyError: unknown.append(fn) continue @@ -399,22 +412,23 @@ nonexistent = False # XXX: what to do with file no longer present in the fs # who are not removed in the dirstate ? - if nonexistent and type in "nm": + if nonexistent and type_ in "nm": deleted.append(fn) continue # check the common case first - if type == 'n': + if type_ == 'n': if not st: st = os.stat(fn) - if size != st.st_size or (mode ^ st.st_mode) & 0100: + if size >= 0 and (size != st.st_size + or (mode ^ st.st_mode) & 0100): modified.append(fn) elif time != st.st_mtime: lookup.append(fn) - elif type == 'm': + elif type_ == 'm': modified.append(fn) - elif type == 'a': + elif type_ == 'a': added.append(fn) - elif type == 'r': + elif type_ == 'r': removed.append(fn) return (lookup, modified, added, removed, deleted, unknown)
--- a/mercurial/hgweb.py Tue Feb 14 21:11:57 2006 +0100 +++ b/mercurial/hgweb.py Tue Feb 21 16:46:38 2006 +0100 @@ -660,9 +660,10 @@ i = self.repo.tagslist() i.reverse() - def entries(**map): + def entries(notip=False, **map): parity = 0 for k,n in i: + if notip and k == "tip": continue yield {"parity": parity, "tag": k, "tagmanifest": hex(cl.read(n)[0]), @@ -672,7 +673,8 @@ yield self.t("tags", manifest=hex(mf), - entries=entries) + entries=lambda **x: entries(False, **x), + entriesnotip=lambda **x: entries(True, **x)) def summary(self): cl = self.repo.changelog @@ -962,7 +964,7 @@ nodes = map(bin, req.form['roots'][0].split(" ")) z = zlib.compressobj() - f = self.repo.changegroup(nodes) + f = self.repo.changegroup(nodes, 'serve') while 1: chunk = f.read(4096) if not chunk:
--- a/mercurial/httprepo.py Tue Feb 14 21:11:57 2006 +0100 +++ b/mercurial/httprepo.py Tue Feb 21 16:46:38 2006 +0100 @@ -119,7 +119,7 @@ self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n") raise - def changegroup(self, nodes): + def changegroup(self, nodes, kind): n = " ".join(map(hex, nodes)) f = self.do_cmd("changegroup", roots=n) bytes = 0
--- a/mercurial/localrepo.py Tue Feb 14 21:11:57 2006 +0100 +++ b/mercurial/localrepo.py Tue Feb 21 16:46:38 2006 +0100 @@ -48,30 +48,36 @@ except IOError: pass - def hook(self, name, **args): + def hook(self, name, throw=False, **args): def runhook(name, cmd): self.ui.note(_("running hook %s: %s\n") % (name, cmd)) old = {} for k, v in args.items(): k = k.upper() + old['HG_' + k] = os.environ.get(k, None) old[k] = os.environ.get(k, None) - os.environ[k] = v + os.environ['HG_' + k] = str(v) + os.environ[k] = str(v) - # Hooks run in the repository root - olddir = os.getcwd() - os.chdir(self.root) - r = os.system(cmd) - os.chdir(olddir) + try: + # Hooks run in the repository root + olddir = os.getcwd() + os.chdir(self.root) + r = os.system(cmd) + finally: + for k, v in old.items(): + if v is not None: + os.environ[k] = v + else: + del os.environ[k] - for k, v in old.items(): - if v != None: - os.environ[k] = v - else: - del os.environ[k] + os.chdir(olddir) if r: - self.ui.warn(_("abort: %s hook failed with status %d!\n") % - (name, r)) + desc, r = util.explain_exit(r) + if throw: + raise util.Abort(_('%s hook %s') % (name, desc)) + self.ui.warn(_('error: %s hook %s\n') % (name, desc)) return False return True @@ -225,7 +231,7 @@ self.join("journal"), after) def recover(self): - lock = self.lock() + l = self.lock() if os.path.exists(self.join("journal")): self.ui.status(_("rolling back interrupted transaction\n")) transaction.rollback(self.opener, self.join("journal")) @@ -239,7 +245,7 @@ def undo(self, wlock=None): if not wlock: wlock = self.wlock() - lock = self.lock() + l = self.lock() if os.path.exists(self.join("undo")): self.ui.status(_("rolling back last transaction\n")) transaction.rollback(self.opener, self.join("undo")) @@ -248,25 +254,44 @@ else: self.ui.warn(_("no undo information available\n")) - def lock(self, wait=1): + def do_lock(self, lockname, wait, releasefn=None, acquirefn=None): try: - return lock.lock(self.join("lock"), 0) - except lock.LockHeld, inst: - if wait: - self.ui.warn(_("waiting for lock held by %s\n") % inst.args[0]) - return lock.lock(self.join("lock"), wait) - raise inst - - def wlock(self, wait=1): - try: - wlock = lock.lock(self.join("wlock"), 0, self.dirstate.write) + l = lock.lock(self.join(lockname), 0, releasefn) except lock.LockHeld, inst: if not wait: raise inst self.ui.warn(_("waiting for lock held by %s\n") % inst.args[0]) - wlock = lock.lock(self.join("wlock"), wait, self.dirstate.write) - self.dirstate.read() - return wlock + l = lock.lock(self.join(lockname), wait, releasefn) + if acquirefn: + acquirefn() + return l + + def lock(self, wait=1): + return self.do_lock("lock", wait) + + def wlock(self, wait=1): + return self.do_lock("wlock", wait, + self.dirstate.write, + self.dirstate.read) + + def checkfilemerge(self, filename, text, filelog, manifest1, manifest2): + "determine whether a new filenode is needed" + fp1 = manifest1.get(filename, nullid) + fp2 = manifest2.get(filename, nullid) + + if fp2 != nullid: + # is one parent an ancestor of the other? + fpa = filelog.ancestor(fp1, fp2) + if fpa == fp1: + fp1, fp2 = fp2, nullid + elif fpa == fp2: + fp2 = nullid + + # is the file unmodified from the parent? report existing entry + if fp2 == nullid and text == filelog.read(fp1): + return (fp1, None, None) + + return (None, fp1, fp2) def rawcommit(self, files, text, user, date, p1=None, p2=None, wlock=None): orig_parent = self.dirstate.parents()[0] or nullid @@ -286,7 +311,7 @@ if not wlock: wlock = self.wlock() - lock = self.lock() + l = self.lock() tr = self.transaction() mm = m1.copy() mfm = mf1.copy() @@ -298,27 +323,10 @@ r = self.file(f) mfm[f] = tm - fp1 = m1.get(f, nullid) - fp2 = m2.get(f, nullid) - - # is the same revision on two branches of a merge? - if fp2 == fp1: - fp2 = nullid - - if fp2 != nullid: - # is one parent an ancestor of the other? - fpa = r.ancestor(fp1, fp2) - if fpa == fp1: - fp1, fp2 = fp2, nullid - elif fpa == fp2: - fp2 = nullid - - # is the file unmodified from the parent? - if t == r.read(fp1): - # record the proper existing parent in manifest - # no need to add a revision - mm[f] = fp1 - continue + (entry, fp1, fp2) = self.checkfilemerge(f, t, r, m1, m2) + if entry: + mm[f] = entry + continue mm[f] = r.add(t, {}, tr, linkrev, fp1, fp2) changed.append(f) @@ -372,12 +380,15 @@ self.ui.status(_("nothing changed\n")) return None - if not self.hook("precommit"): - return None + xp1 = hex(p1) + if p2 == nullid: xp2 = '' + else: xp2 = hex(p2) + + self.hook("precommit", throw=True, parent1=xp1, parent2=xp2) if not wlock: wlock = self.wlock() - lock = self.lock() + l = self.lock() tr = self.transaction() # check in files @@ -403,22 +414,9 @@ self.ui.debug(_(" %s: copy %s:%s\n") % (f, cp, meta["copyrev"])) fp1, fp2 = nullid, nullid else: - fp1 = m1.get(f, nullid) - fp2 = m2.get(f, nullid) - - if fp2 != nullid: - # is one parent an ancestor of the other? - fpa = r.ancestor(fp1, fp2) - if fpa == fp1: - fp1, fp2 = fp2, nullid - elif fpa == fp2: - fp2 = nullid - - # is the file unmodified from the parent? - if not meta and t == r.read(fp1) and fp2 == nullid: - # record the proper existing parent in manifest - # no need to add a revision - new[f] = fp1 + entry, fp1, fp2 = self.checkfilemerge(f, t, r, m1, m2) + if entry: + new[f] = entry continue new[f] = r.add(t, meta, tr, linkrev, fp1, fp2) @@ -459,14 +457,15 @@ user = user or self.ui.username() n = self.changelog.add(mn, changed + remove, text, tr, p1, p2, user, date) + self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1, + parent2=xp2) tr.close() self.dirstate.setparents(n) self.dirstate.update(new, "n") self.dirstate.forget(remove) - if not self.hook("commit", node=hex(n)): - return None + self.hook("commit", node=hex(n), parent1=xp1, parent2=xp2) return n def walk(self, node=None, files=[], match=util.always): @@ -509,7 +508,7 @@ if not wlock: try: wlock = self.wlock(wait=0) - except lock.LockHeld: + except lock.LockException: wlock = None lookup, modified, added, removed, deleted, unknown = ( self.dirstate.changes(files, match)) @@ -598,7 +597,6 @@ if os.path.exists(p): self.ui.warn(_("%s still exists!\n") % f) elif self.dirstate.state(f) == 'a': - self.ui.warn(_("%s never committed!\n") % f) self.dirstate.forget([f]) elif f not in self.dirstate: self.ui.warn(_("%s not tracked!\n") % f) @@ -933,7 +931,7 @@ return subset def pull(self, remote, heads=None): - lock = self.lock() + l = self.lock() # if we have an empty repo, fetch everything if self.changelog.tip() == nullid: @@ -947,9 +945,9 @@ return 1 if heads is None: - cg = remote.changegroup(fetch) + cg = remote.changegroup(fetch, 'pull') else: - cg = remote.changegroupsubset(fetch, heads) + cg = remote.changegroupsubset(fetch, heads, 'pull') return self.addchangegroup(cg) def push(self, remote, force=False, revs=None): @@ -980,12 +978,12 @@ return 1 if revs is None: - cg = self.changegroup(update) + cg = self.changegroup(update, 'push') else: - cg = self.changegroupsubset(update, revs) + cg = self.changegroupsubset(update, revs, 'push') return remote.addchangegroup(cg) - def changegroupsubset(self, bases, heads): + def changegroupsubset(self, bases, heads, source): """This function generates a changegroup consisting of all the nodes that are descendents of any of the bases, and ancestors of any of the heads. @@ -997,6 +995,8 @@ Another wrinkle is doing the reverse, figuring out which changeset in the changegroup a particular filenode or manifestnode belongs to.""" + self.hook('preoutgoing', throw=True, source=source) + # Set up some initial variables # Make it easy to refer to self.changelog cl = self.changelog @@ -1249,14 +1249,19 @@ # Signal that no more groups are left. yield struct.pack(">l", 0) + self.hook('outgoing', node=hex(msng_cl_lst[0]), source=source) + return util.chunkbuffer(gengroup()) - def changegroup(self, basenodes): + def changegroup(self, basenodes, source): """Generate a changegroup of all nodes that we have that a recipient doesn't. This is much easier than the previous function as we can assume that the recipient has any changenode we aren't sending them.""" + + self.hook('preoutgoing', throw=True, source=source) + cl = self.changelog nodes = cl.nodesbetween(basenodes, None)[0] revset = dict.fromkeys([cl.rev(n) for n in nodes]) @@ -1308,6 +1313,7 @@ yield chnk yield struct.pack(">l", 0) + self.hook('outgoing', node=hex(nodes[0]), source=source) return util.chunkbuffer(gengroup()) @@ -1343,6 +1349,9 @@ if not source: return + + self.hook('prechangegroup', throw=True) + changesets = files = revisions = 0 tr = self.transaction() @@ -1385,19 +1394,17 @@ " with %d changes to %d files%s\n") % (changesets, revisions, files, heads)) + self.hook('pretxnchangegroup', throw=True, + node=hex(self.changelog.node(cor+1))) + tr.close() if changesets > 0: - if not self.hook("changegroup", - node=hex(self.changelog.node(cor+1))): - self.ui.warn(_("abort: changegroup hook returned failure!\n")) - return 1 + self.hook("changegroup", node=hex(self.changelog.node(cor+1))) for i in range(cor + 1, cnr + 1): self.hook("incoming", node=hex(self.changelog.node(i))) - return - def update(self, node, allow=False, force=False, choose=None, moddirstate=True, forcemerge=False, wlock=None): pl = self.dirstate.parents()
--- a/mercurial/lock.py Tue Feb 14 21:11:57 2006 +0100 +++ b/mercurial/lock.py Tue Feb 21 16:46:38 2006 +0100 @@ -5,10 +5,14 @@ # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. -import os, time +import errno, os, time import util -class LockHeld(Exception): +class LockException(Exception): + pass +class LockHeld(LockException): + pass +class LockUnavailable(LockException): pass class lock(object): @@ -38,8 +42,11 @@ try: util.makelock(str(pid), self.f) self.held = 1 - except (OSError, IOError): - raise LockHeld(util.readlock(self.f)) + except (OSError, IOError), why: + if why.errno == errno.EEXIST: + raise LockHeld(util.readlock(self.f)) + else: + raise LockUnavailable(why) def release(self): if self.held:
--- a/mercurial/mdiff.py Tue Feb 14 21:11:57 2006 +0100 +++ b/mercurial/mdiff.py Tue Feb 21 16:46:38 2006 +0100 @@ -18,16 +18,22 @@ if not text and (util.binary(a) or util.binary(b)): l = ['Binary file %s has changed\n' % fn] - elif a == None: + elif not a: b = b.splitlines(1) - l1 = "--- %s\t%s\n" % ("/dev/null", epoch) + if a is None: + l1 = "--- %s\t%s\n" % ("/dev/null", epoch) + else: + l1 = "--- %s\t%s\n" % ("a/" + fn, ad) l2 = "+++ %s\t%s\n" % ("b/" + fn, bd) l3 = "@@ -0,0 +1,%d @@\n" % len(b) l = [l1, l2, l3] + ["+" + e for e in b] - elif b == None: + elif not b: a = a.splitlines(1) l1 = "--- %s\t%s\n" % ("a/" + fn, ad) - l2 = "+++ %s\t%s\n" % ("/dev/null", epoch) + if b is None: + l2 = "+++ %s\t%s\n" % ("/dev/null", epoch) + else: + l2 = "+++ %s\t%s\n" % ("b/" + fn, bd) l3 = "@@ -1,%d +0,0 @@\n" % len(a) l = [l1, l2, l3] + ["-" + e for e in a] else:
--- a/mercurial/mpatch.c Tue Feb 14 21:11:57 2006 +0100 +++ b/mercurial/mpatch.c Tue Feb 21 16:46:38 2006 +0100 @@ -43,6 +43,7 @@ #endif static char mpatch_doc[] = "Efficient binary patching."; +static PyObject *mpatch_Error; struct frag { int start, end, len; @@ -65,8 +66,11 @@ a = NULL; } else a->head = a->tail = a->base; + return a; } - return a; + if (!PyErr_Occurred()) + PyErr_NoMemory(); + return NULL; } static void lfree(struct flist *a) @@ -215,6 +219,9 @@ /* assume worst case size, we won't have many of these lists */ l = lalloc(len / 12); + if (!l) + return NULL; + lt = l->tail; while (bin < end) { @@ -227,6 +234,13 @@ lt++; } + if (bin != end) { + if (!PyErr_Occurred()) + PyErr_SetString(mpatch_Error, "patch cannot be decoded"); + lfree(l); + return NULL; + } + l->tail = lt; return l; } @@ -238,6 +252,12 @@ struct frag *f = l->head; while (f != l->tail) { + if (f->start < last || f->end > len) { + if (!PyErr_Occurred()) + PyErr_SetString(mpatch_Error, + "invalid patch"); + return -1; + } outlen += f->start - last; last = f->end; outlen += f->len; @@ -248,13 +268,19 @@ return outlen; } -static void apply(char *buf, char *orig, int len, struct flist *l) +static int apply(char *buf, char *orig, int len, struct flist *l) { struct frag *f = l->head; int last = 0; char *p = buf; while (f != l->tail) { + if (f->start < last || f->end > len) { + if (!PyErr_Occurred()) + PyErr_SetString(mpatch_Error, + "invalid patch"); + return 0; + } memcpy(p, orig + last, f->start - last); p += f->start - last; memcpy(p, f->data, f->len); @@ -263,6 +289,7 @@ f++; } memcpy(p, orig + last, len - last); + return 1; } /* recursively generate a patch of all bins between start and end */ @@ -304,16 +331,25 @@ patch = fold(bins, 0, len); if (!patch) - return PyErr_NoMemory(); + return NULL; outlen = calcsize(PyString_Size(text), patch); + if (outlen < 0) { + result = NULL; + goto cleanup; + } result = PyString_FromStringAndSize(NULL, outlen); - if (result) { - in = PyString_AsString(text); - out = PyString_AsString(result); - apply(out, in, PyString_Size(text), patch); + if (!result) { + result = NULL; + goto cleanup; } - + in = PyString_AsString(text); + out = PyString_AsString(result); + if (!apply(out, in, PyString_Size(text), patch)) { + Py_DECREF(result); + result = NULL; + } +cleanup: lfree(patch); return result; } @@ -327,5 +363,6 @@ initmpatch(void) { Py_InitModule3("mpatch", methods, mpatch_doc); + mpatch_Error = PyErr_NewException("mpatch.mpatchError", NULL, NULL); }
--- a/mercurial/revlog.py Tue Feb 14 21:11:57 2006 +0100 +++ b/mercurial/revlog.py Tue Feb 21 16:46:38 2006 +0100 @@ -624,12 +624,10 @@ # we store negative distances because heap returns smallest member h = [(-dist[node], node)] seen = {} - earliest = self.count() while h: d, n = heapq.heappop(h) if n not in seen: seen[n] = 1 - r = self.rev(n) yield (-d, n) for p in self.parents(n): heapq.heappush(h, (-dist[p], p)) @@ -690,11 +688,6 @@ p = self.parents(self.node(revs[0]))[0] revs.insert(0, self.rev(p)) - # helper to reconstruct intermediate versions - def construct(text, base, rev): - bins = [self.chunk(r) for r in xrange(base + 1, rev + 1)] - return mdiff.patches(text, bins) - # build deltas for d in xrange(0, len(revs) - 1): a, b = revs[d], revs[d + 1] @@ -738,10 +731,10 @@ base = prev = -1 start = end = measure = 0 if r: - start = self.start(self.base(t)) + base = self.base(t) + start = self.start(base) end = self.end(t) - measure = self.length(self.base(t)) - base = self.base(t) + measure = self.length(base) prev = self.tip() transaction.add(self.datafile, end) @@ -793,14 +786,15 @@ raise RevlogError(_("consistency error adding group")) measure = len(text) else: - e = (end, len(cdelta), self.base(t), link, p1, p2, node) + e = (end, len(cdelta), base, link, p1, p2, node) self.index.append(e) self.nodemap[node] = r dfh.write(cdelta) ifh.write(struct.pack(indexformat, *e)) t, r, chain, prev = r, r + 1, node, node - start = self.start(self.base(t)) + base = self.base(t) + start = self.start(base) end = self.end(t) dfh.close()
--- a/mercurial/sshrepo.py Tue Feb 14 21:11:57 2006 +0100 +++ b/mercurial/sshrepo.py Tue Feb 21 16:46:38 2006 +0100 @@ -110,7 +110,7 @@ except: raise hg.RepoError(_("unexpected response '%s'") % (d[:400] + "...")) - def changegroup(self, nodes): + def changegroup(self, nodes, kind): n = " ".join(map(hex, nodes)) f = self.do_cmd("changegroup", roots=n) return self.pipei
--- a/templates/map-rss Tue Feb 14 21:11:57 2006 +0100 +++ b/templates/map-rss Tue Feb 21 16:46:38 2006 +0100 @@ -4,3 +4,5 @@ changelogentry = changelogentry-rss.tmpl filelog = filelog-rss.tmpl filelogentry = filelogentry-rss.tmpl +tags = tags-rss.tmpl +tagentry = tagentry-rss.tmpl
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/tagentry-rss.tmpl Tue Feb 21 16:46:38 2006 +0100 @@ -0,0 +1,6 @@ +<item> + <title>#tag|escape#</title> + <link>#url#?cs=#node|short#</link> + <description><![CDATA[#tag|strip|escape|addbreaks#]]></description> + <pubDate>#date|rfc822date#</pubDate> +</item>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/tags-rss.tmpl Tue Feb 21 16:46:38 2006 +0100 @@ -0,0 +1,6 @@ +#header# + <title>#repo|escape#: tags </title> + <description>#repo|escape# tag history</description> + #entriesnotip%tagentry# + </channel> +</rss>
--- a/templates/tags.tmpl Tue Feb 14 21:11:57 2006 +0100 +++ b/templates/tags.tmpl Tue Feb 21 16:46:38 2006 +0100 @@ -1,11 +1,14 @@ #header# <title>#repo|escape#: tags</title> +<link rel="alternate" type="application/rss+xml" + href="?cmd=tags;style=rss" title="RSS feed for #repo|escape#: tags"> </head> <body> <div class="buttons"> <a href="?cl=tip">changelog</a> <a href="?mf=#manifest|short#;path=/">manifest</a> +<a type="application/rss+xml" href="?cmd=tags;style=rss">rss</a> </div> <h2>tags:</h2>
--- a/tests/test-archive Tue Feb 14 21:11:57 2006 +0100 +++ b/tests/test-archive Tue Feb 21 16:46:38 2006 +0100 @@ -18,8 +18,8 @@ echo "allowzip = true" >> .hg/hgrc echo "allowgz = true" >> .hg/hgrc echo "allowbz2 = true" >> .hg/hgrc -hg serve -p 20059 > /dev/null & -sleep 1 # wait for server to be started +serverpid=`mktemp` +hg serve -p 20059 -d --pid-file=$serverpid TIP=`hg id -v | cut -f1 -d' '` QTIP=`hg id -q` @@ -35,4 +35,5 @@ http_proxy= python getarchive.py "$TIP" zip > archive.zip unzip -t archive.zip | sed "s/$QTIP/TIP/" -kill $! +kill `cat $serverpid` +rm $serverpid
--- a/tests/test-archive.out Tue Feb 14 21:11:57 2006 +0100 +++ b/tests/test-archive.out Tue Feb 21 16:46:38 2006 +0100 @@ -12,4 +12,3 @@ testing: test-archive-TIP/baz/bletch OK testing: test-archive-TIP/foo OK No errors detected in compressed data of archive.zip. -killed!
--- a/tests/test-diffdir Tue Feb 14 21:11:57 2006 +0100 +++ b/tests/test-diffdir Tue Feb 21 16:46:38 2006 +0100 @@ -12,3 +12,7 @@ hg diff -r tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" + +echo foo > a +hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ + -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
--- a/tests/test-diffdir.out Tue Feb 14 21:11:57 2006 +0100 +++ b/tests/test-diffdir.out Tue Feb 21 16:46:38 2006 +0100 @@ -8,3 +8,13 @@ +++ b/b @@ -0,0 +1,1 @@ +123 +diff -r 3903775176ed a +--- a/a ++++ b/a +@@ -0,0 +1,1 @@ ++foo +diff -r 3903775176ed b +--- /dev/null ++++ b/b +@@ -0,0 +1,1 @@ ++123
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-excessive-merge Tue Feb 21 16:46:38 2006 +0100 @@ -0,0 +1,46 @@ +#!/bin/sh + +hg init + +echo foo > a +echo foo > b +hg add a b + +hg ci -m "test" -d "0 0" + +echo blah > a + +hg ci -m "branch a" -d "0 0" + +hg co 0 + +echo blah > b + +hg ci -m "branch b" -d "0 0" +HGMERGE=true hg up -m 1 + +hg ci -m "merge b/a -> blah" -d "0 0" + +hg co 1 +HGMERGE=true hg up -m 2 +hg ci -m "merge a/b -> blah" -d "0 0" + +hg log +hg debugindex .hg/00changelog.i + +echo + +echo 1 +hg manifest 1 +echo 2 +hg manifest 2 +echo 3 +hg manifest 3 +echo 4 +hg manifest 4 + +echo + +hg debugindex .hg/data/a.i + +hg verify \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-excessive-merge.out Tue Feb 21 16:46:38 2006 +0100 @@ -0,0 +1,59 @@ +changeset: 4:2ee31f665a86 +tag: tip +parent: 1:96155394af80 +parent: 2:92cc4c306b19 +user: test +date: Thu Jan 1 00:00:00 1970 +0000 +summary: merge a/b -> blah + +changeset: 3:e16a66a37edd +parent: 2:92cc4c306b19 +parent: 1:96155394af80 +user: test +date: Thu Jan 1 00:00:00 1970 +0000 +summary: merge b/a -> blah + +changeset: 2:92cc4c306b19 +parent: 0:5e0375449e74 +user: test +date: Thu Jan 1 00:00:00 1970 +0000 +summary: branch b + +changeset: 1:96155394af80 +user: test +date: Thu Jan 1 00:00:00 1970 +0000 +summary: branch a + +changeset: 0:5e0375449e74 +user: test +date: Thu Jan 1 00:00:00 1970 +0000 +summary: test + + rev offset length base linkrev nodeid p1 p2 + 0 0 60 0 0 5e0375449e74 000000000000 000000000000 + 1 60 62 1 1 96155394af80 5e0375449e74 000000000000 + 2 122 62 2 2 92cc4c306b19 5e0375449e74 000000000000 + 3 184 69 3 3 e16a66a37edd 92cc4c306b19 96155394af80 + 4 253 29 3 4 2ee31f665a86 96155394af80 92cc4c306b19 + +1 +79d7492df40aa0fa093ec4209be78043c181f094 644 a +2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 b +2 +2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 a +79d7492df40aa0fa093ec4209be78043c181f094 644 b +3 +79d7492df40aa0fa093ec4209be78043c181f094 644 a +79d7492df40aa0fa093ec4209be78043c181f094 644 b +4 +79d7492df40aa0fa093ec4209be78043c181f094 644 a +79d7492df40aa0fa093ec4209be78043c181f094 644 b + + rev offset length base linkrev nodeid p1 p2 + 0 0 5 0 0 2ed2a3912a0b 000000000000 000000000000 + 1 5 6 1 1 79d7492df40a 2ed2a3912a0b 000000000000 +checking changesets +checking manifests +crosschecking files in changesets and manifests +checking files +2 files, 5 changesets, 4 total revisions
--- a/tests/test-help.out Tue Feb 14 21:11:57 2006 +0100 +++ b/tests/test-help.out Tue Feb 21 16:46:38 2006 +0100 @@ -171,10 +171,12 @@ options: - -r --rev revision - -a --text treat all files as text - -I --include include names matching the given patterns - -X --exclude exclude names matching the given patterns + -r --rev revision + -a --text treat all files as text + -I --include include names matching the given patterns + -p --show-function show which function each change is in + -w --ignore-all-space ignore white space when comparing lines + -X --exclude exclude names matching the given patterns hg status [OPTION]... [FILE]... show changed files in the working directory
--- a/tests/test-hook Tue Feb 14 21:11:57 2006 +0100 +++ b/tests/test-hook Tue Feb 21 16:46:38 2006 +0100 @@ -1,10 +1,90 @@ #!/bin/sh -hg init +# commit hooks can see env vars +hg init a +cd a echo "[hooks]" > .hg/hgrc -echo 'precommit = echo precommit hook' >> .hg/hgrc -echo 'commit = echo commit hook: $NODE' >> .hg/hgrc +echo 'commit = echo commit hook: n=$HG_NODE p1=$HG_PARENT1 p2=$HG_PARENT2' >> .hg/hgrc echo 'commit.b = echo commit hook b' >> .hg/hgrc +echo 'precommit = echo precommit hook: p1=$HG_PARENT1 p2=$HG_PARENT2' >> .hg/hgrc +echo 'pretxncommit = echo pretxncommit hook: n=$HG_NODE p1=$HG_PARENT1 p2=$HG_PARENT2; hg -q tip' >> .hg/hgrc echo a > a hg add a -hg commit -m "test" -d "0 0" +hg commit -m a -d "0 0" + +hg clone . ../b +cd ../b + +# changegroup hooks can see env vars +echo '[hooks]' > .hg/hgrc +echo 'prechangegroup = echo prechangegroup hook' >> .hg/hgrc +echo 'changegroup = echo changegroup hook: n=$HG_NODE' >> .hg/hgrc +echo 'incoming = echo incoming hook: n=$HG_NODE' >> .hg/hgrc + +# pretxncommit and commit hooks can see both parents of merge +cd ../a +echo b >> a +hg commit -m a1 -d "1 0" +hg update -C 0 +echo b > b +hg add b +hg commit -m b -d '1 0' +hg update -m 1 +hg commit -m merge -d '2 0' + +cd ../b +hg pull ../a + +# tag hooks can see env vars +cd ../a +echo 'pretag = echo pretag hook: t=$HG_TAG n=$HG_NODE l=$HG_LOCAL' >> .hg/hgrc +echo 'tag = echo tag hook: t=$HG_TAG n=$HG_NODE l=$HG_LOCAL' >> .hg/hgrc +hg tag -d '3 0' a +hg tag -l la + +# pretag hook can forbid tagging +echo 'pretag.forbid = echo pretag.forbid hook; exit 1' >> .hg/hgrc +hg tag -d '4 0' fa +hg tag -l fla + +# pretxncommit hook can see changeset, can roll back txn, changeset +# no more there after +echo 'pretxncommit.forbid = echo pretxncommit.forbid hook: tip=`hg -q tip`; exit 1' >> .hg/hgrc +echo z > z +hg add z +hg -q tip +hg commit -m 'fail' -d '4 0' +hg -q tip + +# precommit hook can prevent commit +echo 'precommit.forbid = echo precommit.forbid hook; exit 1' >> .hg/hgrc +hg commit -m 'fail' -d '4 0' +hg -q tip + +# prechangegroup hook can prevent incoming changes +cd ../b +hg -q tip +echo '[hooks]' > .hg/hgrc +echo 'prechangegroup.forbid = echo prechangegroup.forbid hook; exit 1' >> .hg/hgrc +hg pull ../a + +# pretxnchangegroup hook can see incoming changes, can roll back txn, +# incoming changes no longer there after +echo '[hooks]' > .hg/hgrc +echo 'pretxnchangegroup.forbid = echo pretxnchangegroup.forbid hook: tip=`hg -q tip`; exit 1' >> .hg/hgrc +hg pull ../a +hg -q tip + +# outgoing hooks can see env vars +rm .hg/hgrc +echo '[hooks]' > ../a/.hg/hgrc +echo 'preoutgoing = echo preoutgoing hook: s=$HG_SOURCE' >> ../a/.hg/hgrc +echo 'outgoing = echo outgoing hook: n=$HG_NODE s=$HG_SOURCE' >> ../a/.hg/hgrc +hg pull ../a +hg undo + +# preoutgoing hook can prevent outgoing changes +echo 'preoutgoing.forbid = echo preoutgoing.forbid hook; exit 1' >> ../a/.hg/hgrc +hg pull ../a + +exit 0
--- a/tests/test-hook.out Tue Feb 14 21:11:57 2006 +0100 +++ b/tests/test-hook.out Tue Feb 21 16:46:38 2006 +0100 @@ -1,3 +1,88 @@ -precommit hook +precommit hook: p1=0000000000000000000000000000000000000000 p2= +pretxncommit hook: n=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b p1=0000000000000000000000000000000000000000 p2= +0:cb9a9f314b8b +commit hook b +commit hook: n=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b p1=0000000000000000000000000000000000000000 p2= +precommit hook: p1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b p2= +pretxncommit hook: n=ab228980c14deea8b9555d91c9581127383e40fd p1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b p2= +1:ab228980c14d +commit hook b +commit hook: n=ab228980c14deea8b9555d91c9581127383e40fd p1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b p2= +precommit hook: p1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b p2= +pretxncommit hook: n=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 p1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b p2= +2:ee9deb46ab31 +commit hook b +commit hook: n=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 p1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b p2= +precommit hook: p1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 p2=ab228980c14deea8b9555d91c9581127383e40fd +pretxncommit hook: n=07f3376c1e655977439df2a814e3cc14b27abac2 p1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 p2=ab228980c14deea8b9555d91c9581127383e40fd +3:07f3376c1e65 +commit hook b +commit hook: n=07f3376c1e655977439df2a814e3cc14b27abac2 p1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 p2=ab228980c14deea8b9555d91c9581127383e40fd +prechangegroup hook +changegroup hook: n=ab228980c14deea8b9555d91c9581127383e40fd +incoming hook: n=ab228980c14deea8b9555d91c9581127383e40fd +incoming hook: n=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 +incoming hook: n=07f3376c1e655977439df2a814e3cc14b27abac2 +pulling from ../a +searching for changes +adding changesets +adding manifests +adding file changes +added 3 changesets with 2 changes to 2 files +(run 'hg update' to get a working copy) +pretag hook: t=a n=07f3376c1e655977439df2a814e3cc14b27abac2 l=0 +precommit hook: p1=07f3376c1e655977439df2a814e3cc14b27abac2 p2= +pretxncommit hook: n=3cd2c6a5a36c5908aad3bc0d717c29873a05dfc2 p1=07f3376c1e655977439df2a814e3cc14b27abac2 p2= +4:3cd2c6a5a36c commit hook b -commit hook: acb14030fe0a21b60322c440ad2d20cf7685a376 +commit hook: n=3cd2c6a5a36c5908aad3bc0d717c29873a05dfc2 p1=07f3376c1e655977439df2a814e3cc14b27abac2 p2= +tag hook: t=a n=07f3376c1e655977439df2a814e3cc14b27abac2 l=0 +pretag hook: t=la n=3cd2c6a5a36c5908aad3bc0d717c29873a05dfc2 l=1 +tag hook: t=la n=3cd2c6a5a36c5908aad3bc0d717c29873a05dfc2 l=1 +pretag hook: t=fa n=3cd2c6a5a36c5908aad3bc0d717c29873a05dfc2 l=0 +pretag.forbid hook +abort: pretag.forbid hook exited with status 1 +pretag hook: t=fla n=3cd2c6a5a36c5908aad3bc0d717c29873a05dfc2 l=1 +pretag.forbid hook +abort: pretag.forbid hook exited with status 1 +4:3cd2c6a5a36c +precommit hook: p1=3cd2c6a5a36c5908aad3bc0d717c29873a05dfc2 p2= +pretxncommit.forbid hook: tip=5:469a61fe67d6 +abort: pretxncommit.forbid hook exited with status 1 +transaction abort! +rollback completed +4:3cd2c6a5a36c +precommit.forbid hook +abort: precommit.forbid hook exited with status 1 +4:3cd2c6a5a36c +3:07f3376c1e65 +prechangegroup.forbid hook +pulling from ../a +searching for changes +abort: prechangegroup.forbid hook exited with status 1 +pretxnchangegroup.forbid hook: tip=4:3cd2c6a5a36c +pulling from ../a +searching for changes +adding changesets +adding manifests +adding file changes +added 1 changesets with 1 changes to 1 files +abort: pretxnchangegroup.forbid hook exited with status 1 +transaction abort! +rollback completed +3:07f3376c1e65 +preoutgoing hook: s=pull +outgoing hook: n=3cd2c6a5a36c5908aad3bc0d717c29873a05dfc2 s=pull +pulling from ../a +searching for changes +adding changesets +adding manifests +adding file changes +added 1 changesets with 1 changes to 1 files +(run 'hg update' to get a working copy) +rolling back last transaction +preoutgoing hook: s=pull +preoutgoing.forbid hook +pulling from ../a +searching for changes +abort: preoutgoing.forbid hook exited with status 1
--- a/tests/test-merge3.out Tue Feb 14 21:11:57 2006 +0100 +++ b/tests/test-merge3.out Tue Feb 21 16:46:38 2006 +0100 @@ -1,3 +1,2 @@ removing b -b never committed! nothing changed
--- a/tests/test-pull Tue Feb 14 21:11:57 2006 +0100 +++ b/tests/test-pull Tue Feb 21 16:46:38 2006 +0100 @@ -7,8 +7,8 @@ hg addremove hg commit -m 1 hg verify -hg serve -p 20059 > /dev/null & -sleep 1 # wait for server to be started +serverpid=`mktemp` +hg serve -p 20059 -d --pid-file=$serverpid cd .. hg clone http://localhost:20059/ copy @@ -19,4 +19,5 @@ hg manifest hg pull -kill $! +kill `cat $serverpid` +rm $serverpid
--- a/tests/test-pull-permission Tue Feb 14 21:11:57 2006 +0100 +++ b/tests/test-pull-permission Tue Feb 21 16:46:38 2006 +0100 @@ -12,9 +12,8 @@ cd .. hg clone a b + +chmod +w a/.hg # let test clean up + cd b hg verify - -cd .. - -chmod +w a/.hg # let test clean up
--- a/tests/test-pull.out Tue Feb 14 21:11:57 2006 +0100 +++ b/tests/test-pull.out Tue Feb 21 16:46:38 2006 +0100 @@ -19,4 +19,3 @@ pulling from http://localhost:20059/ searching for changes no changes found -killed!
--- a/tests/test-rename Tue Feb 14 21:11:57 2006 +0100 +++ b/tests/test-rename Tue Feb 21 16:46:38 2006 +0100 @@ -158,3 +158,16 @@ hg rename d1 d3 hg status hg update -C + +echo "# transitive rename" +hg rename d1/b d1/bb +hg rename d1/bb d1/bc +hg status +hg update -C + +echo "# transitive rename --after" +hg rename d1/b d1/bb +mv d1/bb d1/bc +hg rename --after d1/bb d1/bc +hg status +hg update -C
--- a/tests/test-rename.out Tue Feb 14 21:11:57 2006 +0100 +++ b/tests/test-rename.out Tue Feb 21 16:46:38 2006 +0100 @@ -246,3 +246,9 @@ R d1/b R d1/ba R d1/d11/a1 +# transitive rename +A d1/bc +R d1/b +# transitive rename --after +A d1/bc +R d1/b
--- a/tests/test-ro-message Tue Feb 14 21:11:57 2006 +0100 +++ b/tests/test-ro-message Tue Feb 21 16:46:38 2006 +0100 @@ -14,4 +14,4 @@ "$HG" commit -m 'Clarifying the vehicle.' "$HG" update -C 1 chmod a-w b/vehicle -"$HG" update -m 2 2>&1 | sed 's|^\(.*[ ]\)/tmp/[^/]*/\(.*\)$|\1\2|g' +"$HG" update -m 2 2>&1 | sed 's|^\(.*[ ]\).*/\([^/]*/[^/]*/[^/]*\)$|\1\2|g'