# HG changeset patch # User Matt Mackall # Date 1140564987 21600 # Node ID 8a1f2eae2832e07874e594e4689d3b538e5fbb5c # Parent 0762feff304339e849d2540211413408e2e0f228# Parent a1e6e02e9d05e45b45fcaa2e95c9bcc6e944d9d9 Merge with jeffpc diff --git a/contrib/hbisect.py b/contrib/hbisect.py --- a/contrib/hbisect.py +++ b/contrib/hbisect.py @@ -187,7 +187,7 @@ class bisect(object): 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 @@ def test(ui, repo, rev): 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") diff --git a/doc/hg.1.txt b/doc/hg.1.txt --- a/doc/hg.1.txt +++ b/doc/hg.1.txt @@ -376,6 +376,11 @@ log [-r revision ...] [-p] [files]:: options: -I, --include include names matching the given patterns -X, --exclude exclude names matching the given patterns + -b, --branch show branches + -k, --keyword search for keywords + -l, --limit print no more than this many changes + -M, --no-merges do not show merges + -m, --only-merges only show merges -r, --rev show the specified revision or range -p, --patch show patch @@ -543,10 +548,12 @@ serve [options]:: options: -A, --accesslog name of access log file to write to + -d, --daemon run server in background, as a daemon -E, --errorlog name of error log file to write to -a, --address address to use -p, --port port to use (default: 8000) -n, --name name to show in web pages (default: working dir) + --pid-file write server process ID to given file -t, --templatedir web templates to use -6, --ipv6 use IPv6 in addition to IPv4 diff --git a/hgmerge b/hgmerge --- a/hgmerge +++ b/hgmerge @@ -17,31 +17,35 @@ fi # find decent versions of our utilities, insisting on the GNU versions where we # need to -MERGE=merge -DIFF3=gdiff3 -DIFF=gdiff -PATCH=gpatch +MERGE="merge" +DIFF3="gdiff3" +DIFF="gdiff" +PATCH="gpatch" -type $MERGE >/dev/null 2>&1 || MERGE= -type $DIFF3 >/dev/null 2>&1 || DIFF3=diff3 -type $DIFF >/dev/null 2>&1 || DIFF=diff -type $PATCH >/dev/null 2>&1 || PATCH=patch +type "$MERGE" >/dev/null 2>&1 || MERGE= +type "$DIFF3" >/dev/null 2>&1 || DIFF3="diff3" $DIFF3 --version >/dev/null 2>&1 || DIFF3= +type "$DIFF" >/dev/null 2>&1 || DIFF="diff" +type "$DIFF" >/dev/null 2>&1 || DIFF= +type "$PATCH" >/dev/null 2>&1 || PATCH="patch" +type "$PATCH" >/dev/null 2>&1 || PATCH= # find optional visual utilities -FILEMERGE='/Developer/Applications/Utilities/FileMerge.app/Contents/MacOS/FileMerge' -KDIFF3=kdiff3 -TKDIFF=tkdiff +FILEMERGE="/Developer/Applications/Utilities/FileMerge.app/Contents/MacOS/FileMerge" +KDIFF3="kdiff3" +TKDIFF="tkdiff" +MELD="meld" -type $FILEMERGE >/dev/null 2>&1 || FILEMERGE= -type $KDIFF3 >/dev/null 2>&1 || KDIFF3= -type $TKDIFF >/dev/null 2>&1 || TKDIFF= +type "$FILEMERGE" >/dev/null 2>&1 || FILEMERGE= +type "$KDIFF3" >/dev/null 2>&1 || KDIFF3= +type "$TKDIFF" >/dev/null 2>&1 || TKDIFF= +type "$MELD" >/dev/null 2>&1 || MELD= # random part of names -RAND="$RANDOM.$RANDOM.$RANDOM.$$" +RAND="$RANDOM$RANDOM" # temporary directory for diff+patch merge -HGTMP="${TMPDIR-/tmp}/hgmerge.$RAND" +HGTMP="${TMPDIR-'/tmp'}/hgmerge.$RAND" # backup file BACKUP="$LOCAL.orig.$RAND" @@ -68,6 +72,18 @@ failure() { exit 1 } +# Ask if the merge was successful +ask_if_merged() { + while 1; do + echo "$LOCAL seems unchanged. Was the merge successful? [y/n]" + read answer + case answer in + y*|Y*) success;; + n*|N*) failure;; + esac + done +} + # Clean up when interrupted trap "failure" 1 2 3 6 15 # HUP INT QUIT ABRT TERM @@ -76,18 +92,16 @@ mv "$LOCAL" "$BACKUP" cp "$BACKUP" "$LOCAL" # Attempt to do a non-interactive merge -if [ -n "$MERGE" ]; then - $MERGE "$LOCAL" "$BASE" "$OTHER" 2> /dev/null && success - cp "$BACKUP" "$LOCAL" -elif [ -n "$DIFF3" ]; then - echo $DIFF3 -m "$BACKUP" "$BASE" "$OTHER" - $DIFF3 -m "$BACKUP" "$BASE" "$OTHER" > "$LOCAL" && success - if [ $? -eq 2 ]; then - echo "$DIFF3 failed! Exiting." 1>&2 - cp "$BACKUP" "$LOCAL" +if [ -n "$MERGE" -o -n "$DIFF3" ]; then + if [ -n "$MERGE" ]; then + $MERGE "$LOCAL" "$BASE" "$OTHER" 2> /dev/null && success + elif [ -n "$DIFF3" ]; then + $DIFF3 -m "$BACKUP" "$BASE" "$OTHER" > "$LOCAL" && success + fi + if [ $? -gt 1 ]; then + echo "automatic merge failed! Exiting." 1>&2 failure fi - cp "$BACKUP" "$LOCAL" fi # on MacOS X try FileMerge.app, shipped with Apple's developer tools @@ -97,71 +111,66 @@ if [ -n "$FILEMERGE" ]; then # filemerge prefers the right by default $FILEMERGE -left "$OTHER" -right "$LOCAL" -ancestor "$BASE" -merge "$LOCAL" [ $? -ne 0 ] && echo "FileMerge failed to launch" && failure - if test "$LOCAL" -nt "$CHGTEST" - then - success - else - echo "$LOCAL seems unchanged. Was the merge successful?" - select answer in yes no - do - test "$answer" == "yes" && success || failure - done - fi - failure + test "$LOCAL" -nt "$CHGTEST" && success || ask_if_merged fi if [ -n "$DISPLAY" ]; then # try using kdiff3, which is fairly nice if [ -n "$KDIFF3" ]; then - $KDIFF3 --auto "$BASE" "$LOCAL" "$OTHER" -o "$LOCAL" || failure - success + $KDIFF3 --auto "$BASE" "$LOCAL" "$OTHER" -o "$LOCAL" || failure + success fi # try using tkdiff, which is a bit less sophisticated if [ -n "$TKDIFF" ]; then - $TKDIFF "$LOCAL" "$OTHER" -a "$BASE" -o "$LOCAL" || failure - success + $TKDIFF "$LOCAL" "$OTHER" -a "$BASE" -o "$LOCAL" || failure + success + fi + + if [ -n "$MELD" ]; then + cp "$BACKUP" "$CHGTEST" + # protect our feet - meld allows us to save to the left file + cp "$BACKUP" "$LOCAL.tmp.$RAND" + # Meld doesn't have automatic merging, so to reduce intervention + # use the file with conflicts + $MELD "$LOCAL.tmp.$RAND" "$LOCAL" "$OTHER" || failure + # Also it doesn't return good error code + test "$LOCAL" -nt "$CHGTEST" && success || ask_if_merged fi fi # Attempt to do a merge with $EDITOR -if [ -n "$MERGE" ]; then - echo "conflicts detected in $LOCAL" - $MERGE "$LOCAL" "$BASE" "$OTHER" 2>/dev/null || $EDITOR "$LOCAL" - success -fi - -if [ -n "$DIFF3" ]; then +if [ -n "$MERGE" -o -n "$DIFF3" ]; then echo "conflicts detected in $LOCAL" - $DIFF3 -m "$BACKUP" "$BASE" "$OTHER" > "$LOCAL" || { - case $? in - 1) - $EDITOR "$LOCAL" ;; - 2) echo "$DIFF3 failed! Exiting." 1>&2 - cp "$BACKUP" "$LOCAL" - failure ;; - esac - success - } + cp "$BACKUP" "$CHGTEST" + $EDITOR "$LOCAL" || failure + # Some editors do not return meaningful error codes + # Do not take any chances + test "$LOCAL" -nt "$CHGTEST" && success || ask_if_merged fi # attempt to manually merge with diff and patch if [ -n "$DIFF" -a -n "$PATCH" ]; then (umask 077 && mkdir "$HGTMP") || { - echo "Could not create temporary directory $HGTMP" 1>&2 - failure + echo "Could not create temporary directory $HGTMP" 1>&2 + failure } $DIFF -u "$BASE" "$OTHER" > "$HGTMP/diff" || : if $PATCH "$LOCAL" < "$HGTMP/diff"; then - success + success else - # If rejects are empty after using the editor, merge was ok - $EDITOR "$LOCAL" "$LOCAL.rej" && test -s "$LOCAL.rej" || success + # If rejects are empty after using the editor, merge was ok + $EDITOR "$LOCAL" "$LOCAL.rej" || failure + test -s "$LOCAL.rej" || success fi failure fi -echo "hgmerge: unable to find merge, tkdiff, kdiff3, or diff+patch!" +echo +echo "hgmerge: unable to find any merge utility!" +echo "supported programs:" +echo "merge, FileMerge, tkdiff, kdiff3, meld, diff+patch" +echo failure diff --git a/mercurial/bdiff.c b/mercurial/bdiff.c --- a/mercurial/bdiff.c +++ b/mercurial/bdiff.c @@ -17,6 +17,10 @@ #define inline #endif +#ifdef __SUNPRO_C +# define inline +#endif + #ifdef _WIN32 #ifdef _MSC_VER #define inline __inline diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -115,8 +115,8 @@ def walkchangerevs(ui, repo, pats, opts) 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 @@ def walkchangerevs(ui, repo, pats, opts) 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. @@ -447,7 +447,6 @@ def help_(ui, cmd=None, with_version=Fal 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)") @@ -725,8 +724,8 @@ def clone(ui, source, dest=None, **opts) # 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 @@ def docopy(ui, repo, pats, opts): 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 @@ def docopy(ui, repo, pats, opts): 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 @@ def docopy(ui, repo, pats, opts): 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 @@ def docopy(ui, repo, pats, opts): 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 @@ def debugancestor(ui, index, rev1, rev2) 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() @@ -1284,6 +1301,7 @@ def grep(ui, repo, pattern, *pats, **opt 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 @@ def log(ui, repo, *pats, **opts): 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 @@ def log(ui, repo, *pats, **opts): if opts['only_merges'] and len(parents) != 2: continue - br = None if opts['keyword']: changes = getchange(rev) miss = 0 @@ -1620,7 +1649,8 @@ def log(ui, repo, *pats, **opts): 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 @@ def log(ui, repo, *pats, **opts): 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 @@ def outgoing(ui, repo, dest="default-pus dodiff(ui, ui, repo, prev, n) ui.write("\n") -def parents(ui, repo, rev=None, branch=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. @@ -1692,7 +1725,7 @@ def parents(ui, repo, rev=None, branch=N p = repo.dirstate.parents() br = None - if branch is not None: + if branches is not None: br = repo.branchlookup(p) for n in p: if n != nullid: @@ -2022,6 +2055,16 @@ def serve(ui, repo, **opts): 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 +2083,25 @@ def serve(ui, repo, **opts): 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): @@ -2164,7 +2226,10 @@ def tip(ui, repo, **opts): 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) @@ -2324,6 +2389,10 @@ table = { _('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]')), @@ -2375,7 +2444,7 @@ table = { _('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 ]')), "help": (help_, [], _('hg help [COMMAND]')), @@ -2409,8 +2478,9 @@ table = { (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')), @@ -2424,7 +2494,7 @@ table = { _('hg outgoing [-p] [-n] [-M] [DEST]')), "^parents": (parents, - [('b', 'branch', None, _('show branches'))], + [('b', 'branches', None, _('show branches'))], _('hg parents [-b] [REV]')), "paths": (paths, [], _('hg paths [NAME]')), "^pull": @@ -2476,11 +2546,14 @@ table = { "^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')), @@ -2508,7 +2581,11 @@ table = { ('r', 'rev', '', _('revision to tag'))], _('hg tag [-r REV] [OPTION]... NAME')), "tags": (tags, [], _('hg tags')), - "tip": (tip, [('p', 'patch', None, _('show patch'))], _('hg tip')), + "tip": + (tip, + [('b', 'branches', None, _('show branches')), + ('p', 'patch', None, _('show patch'))], + _('hg [-b] [-p] tip')), "unbundle": (unbundle, [('u', 'update', None, diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py --- a/mercurial/dirstate.py +++ b/mercurial/dirstate.py @@ -197,6 +197,19 @@ class dirstate(object): 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 @@ class dirstate(object): 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 @@ class dirstate(object): 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 @@ class dirstate(object): 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 @@ class dirstate(object): 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) diff --git a/mercurial/hgweb.py b/mercurial/hgweb.py --- a/mercurial/hgweb.py +++ b/mercurial/hgweb.py @@ -661,9 +661,10 @@ class hgweb(object): 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]), @@ -673,7 +674,8 @@ class hgweb(object): 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 diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -231,7 +231,7 @@ class localrepository(object): 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")) @@ -245,7 +245,7 @@ class localrepository(object): 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")) @@ -254,25 +254,25 @@ class localrepository(object): 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" @@ -311,7 +311,7 @@ class localrepository(object): if not wlock: wlock = self.wlock() - lock = self.lock() + l = self.lock() tr = self.transaction() mm = m1.copy() mfm = mf1.copy() @@ -388,7 +388,7 @@ class localrepository(object): if not wlock: wlock = self.wlock() - lock = self.lock() + l = self.lock() tr = self.transaction() # check in files @@ -508,7 +508,7 @@ class localrepository(object): 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)) @@ -597,7 +597,6 @@ class localrepository(object): 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) @@ -932,7 +931,7 @@ class localrepository(object): 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: @@ -952,7 +951,7 @@ class localrepository(object): return self.addchangegroup(cg) def push(self, remote, force=False): - lock = remote.lock() + l = remote.lock() base = {} heads = remote.heads() diff --git a/mercurial/lock.py b/mercurial/lock.py --- a/mercurial/lock.py +++ b/mercurial/lock.py @@ -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 @@ class lock(object): 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: diff --git a/mercurial/mpatch.c b/mercurial/mpatch.c --- a/mercurial/mpatch.c +++ b/mercurial/mpatch.c @@ -66,7 +66,7 @@ static struct flist *lalloc(int size) a = NULL; } else a->head = a->tail = a->base; - return a; + return a; } if (!PyErr_Occurred()) PyErr_NoMemory(); diff --git a/mercurial/revlog.py b/mercurial/revlog.py --- a/mercurial/revlog.py +++ b/mercurial/revlog.py @@ -624,12 +624,10 @@ class revlog(object): # 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 @@ class revlog(object): 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 @@ class revlog(object): 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 @@ class revlog(object): 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() diff --git a/templates/map-rss b/templates/map-rss --- a/templates/map-rss +++ b/templates/map-rss @@ -4,3 +4,5 @@ changelog = changelog-rss.tmpl changelogentry = changelogentry-rss.tmpl filelog = filelog-rss.tmpl filelogentry = filelogentry-rss.tmpl +tags = tags-rss.tmpl +tagentry = tagentry-rss.tmpl diff --git a/templates/tagentry-rss.tmpl b/templates/tagentry-rss.tmpl new file mode 100644 --- /dev/null +++ b/templates/tagentry-rss.tmpl @@ -0,0 +1,6 @@ + + #tag|escape# + #url#?cs=#node|short# + + #date|rfc822date# + diff --git a/templates/tags-rss.tmpl b/templates/tags-rss.tmpl new file mode 100644 --- /dev/null +++ b/templates/tags-rss.tmpl @@ -0,0 +1,6 @@ +#header# + #repo|escape#: tags + #repo|escape# tag history + #entriesnotip%tagentry# + + diff --git a/templates/tags.tmpl b/templates/tags.tmpl --- a/templates/tags.tmpl +++ b/templates/tags.tmpl @@ -1,11 +1,14 @@ #header# #repo|escape#: tags +

tags:

diff --git a/tests/test-archive b/tests/test-archive --- a/tests/test-archive +++ b/tests/test-archive @@ -18,8 +18,8 @@ echo "name = test-archive" >> .hg/hgrc 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" http_proxy= python getarchive.py "$TIP" zip > archive.zip unzip -t archive.zip | sed "s/$QTIP/TIP/" -kill $! +kill `cat $serverpid` +rm $serverpid diff --git a/tests/test-archive.out b/tests/test-archive.out --- a/tests/test-archive.out +++ b/tests/test-archive.out @@ -12,4 +12,3 @@ Archive: archive.zip testing: test-archive-TIP/baz/bletch OK testing: test-archive-TIP/foo OK No errors detected in compressed data of archive.zip. -killed! diff --git a/tests/test-merge3.out b/tests/test-merge3.out --- a/tests/test-merge3.out +++ b/tests/test-merge3.out @@ -1,3 +1,2 @@ removing b -b never committed! nothing changed diff --git a/tests/test-pull b/tests/test-pull --- a/tests/test-pull +++ b/tests/test-pull @@ -7,8 +7,8 @@ hg init 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 @@ cat foo hg manifest hg pull -kill $! +kill `cat $serverpid` +rm $serverpid diff --git a/tests/test-pull-permission b/tests/test-pull-permission --- a/tests/test-pull-permission +++ b/tests/test-pull-permission @@ -12,9 +12,8 @@ chmod -w .hg 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 diff --git a/tests/test-pull.out b/tests/test-pull.out --- a/tests/test-pull.out +++ b/tests/test-pull.out @@ -19,4 +19,3 @@ 2ed2a3912a0b24502043eae84ee4b279c18b90dd pulling from http://localhost:20059/ searching for changes no changes found -killed! diff --git a/tests/test-rename b/tests/test-rename --- a/tests/test-rename +++ b/tests/test-rename @@ -158,3 +158,16 @@ hg remove d1/b 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 diff --git a/tests/test-rename.out b/tests/test-rename.out --- a/tests/test-rename.out +++ b/tests/test-rename.out @@ -246,3 +246,9 @@ R d1/a 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