Mercurial > hg
changeset 9535:75d290db2df6
merge with mpm
author | Benoit Boissinot <benoit.boissinot@ens-lyon.org> |
---|---|
date | Sat, 03 Oct 2009 23:38:10 +0200 |
parents | 8e202431d620 (current diff) d932dc655881 (diff) |
children | f04d17912441 |
files | |
diffstat | 28 files changed, 731 insertions(+), 341 deletions(-) [+] |
line wrap: on
line diff
--- a/contrib/bash_completion Sat Oct 03 23:36:08 2009 +0200 +++ b/contrib/bash_completion Sat Oct 03 23:38:10 2009 +0200 @@ -530,3 +530,20 @@ return } +# shelve +_hg_shelves() +{ + local shelves="$("$hg" unshelve -l . 2>/dev/null)" + local IFS=$'\n' + COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$shelves' -- "$cur")) +} + +_hg_cmd_shelve() +{ + _hg_status "mard" +} + +_hg_cmd_unshelve() +{ + _hg_shelves +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/shrink-revlog.py Sat Oct 03 23:38:10 2009 +0200 @@ -0,0 +1,218 @@ +#!/usr/bin/env python + +"""\ +Reorder a revlog (by default the the manifest file in the current +repository) to save space. Specifically, this topologically sorts the +revisions in the revlog so that revisions on the same branch are adjacent +as much as possible. This is a workaround for the fact that Mercurial +computes deltas relative to the previous revision rather than relative to a +parent revision. This is *not* safe to run on a changelog. +""" + +# Originally written by Benoit Boissinot <benoit.boissinot at ens-lyon.org> +# as a patch to rewrite-log. Cleaned up, refactored, documented, and +# renamed by Greg Ward <greg at gerg.ca>. + +# XXX would be nice to have a way to verify the repository after shrinking, +# e.g. by comparing "before" and "after" states of random changesets +# (maybe: export before, shrink, export after, diff). + +import sys, os, tempfile +import optparse +from mercurial import ui as ui_, hg, revlog, transaction, node, util + +def toposort(rl): + write = sys.stdout.write + + children = {} + root = [] + # build children and roots + write('reading %d revs ' % len(rl)) + try: + for i in rl: + children[i] = [] + parents = [p for p in rl.parentrevs(i) if p != node.nullrev] + # in case of duplicate parents + if len(parents) == 2 and parents[0] == parents[1]: + del parents[1] + for p in parents: + assert p in children + children[p].append(i) + + if len(parents) == 0: + root.append(i) + + if i % 1000 == 0: + write('.') + finally: + write('\n') + + # XXX this is a reimplementation of the 'branchsort' topo sort + # algorithm in hgext.convert.convcmd... would be nice not to duplicate + # the algorithm + write('sorting ...') + visit = root + ret = [] + while visit: + i = visit.pop(0) + ret.append(i) + if i not in children: + # This only happens if some node's p1 == p2, which can + # happen in the manifest in certain circumstances. + continue + next = [] + for c in children.pop(i): + parents_unseen = [p for p in rl.parentrevs(c) + if p != node.nullrev and p in children] + if len(parents_unseen) == 0: + next.append(c) + visit = next + visit + write('\n') + return ret + +def writerevs(r1, r2, order, tr): + write = sys.stdout.write + write('writing %d revs ' % len(order)) + try: + count = 0 + for rev in order: + n = r1.node(rev) + p1, p2 = r1.parents(n) + l = r1.linkrev(rev) + t = r1.revision(n) + n2 = r2.addrevision(t, tr, l, p1, p2) + + if count % 1000 == 0: + write('.') + count += 1 + finally: + write('\n') + +def report(olddatafn, newdatafn): + oldsize = float(os.stat(olddatafn).st_size) + newsize = float(os.stat(newdatafn).st_size) + + # argh: have to pass an int to %d, because a float >= 2^32 + # blows up under Python 2.5 or earlier + sys.stdout.write('old file size: %12d bytes (%6.1f MiB)\n' + % (int(oldsize), oldsize/1024/1024)) + sys.stdout.write('new file size: %12d bytes (%6.1f MiB)\n' + % (int(newsize), newsize/1024/1024)) + + shrink_percent = (oldsize - newsize) / oldsize * 100 + shrink_factor = oldsize / newsize + sys.stdout.write('shrinkage: %.1f%% (%.1fx)\n' + % (shrink_percent, shrink_factor)) + +def main(): + + # Unbuffer stdout for nice progress output. + sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0) + write = sys.stdout.write + + parser = optparse.OptionParser(description=__doc__) + parser.add_option('-R', '--repository', + default=os.path.curdir, + metavar='REPO', + help='repository root directory [default: current dir]') + parser.add_option('--revlog', + metavar='FILE', + help='shrink FILE [default: REPO/hg/store/00manifest.i]') + (options, args) = parser.parse_args() + if args: + parser.error('too many arguments') + + # Open the specified repository. + ui = ui_.ui() + repo = hg.repository(ui, options.repository) + if not repo.local(): + parser.error('not a local repository: %s' % options.repository) + + if options.revlog is None: + indexfn = repo.sjoin('00manifest.i') + else: + if not options.revlog.endswith('.i'): + parser.error('--revlog option must specify the revlog index file ' + '(*.i), not %s' % options.revlog) + + indexfn = os.path.realpath(options.revlog) + store = repo.sjoin('') + if not indexfn.startswith(store): + parser.error('--revlog option must specify a revlog in %s, not %s' + % (store, indexfn)) + + datafn = indexfn[:-2] + '.d' + if not os.path.exists(indexfn): + parser.error('no such file: %s' % indexfn) + if '00changelog' in indexfn: + parser.error('shrinking the changelog will corrupt your repository') + if not os.path.exists(datafn): + # This is just a lazy shortcut because I can't be bothered to + # handle all the special cases that entail from no .d file. + parser.error('%s does not exist: revlog not big enough ' + 'to be worth shrinking' % datafn) + + oldindexfn = indexfn + '.old' + olddatafn = datafn + '.old' + if os.path.exists(oldindexfn) or os.path.exists(olddatafn): + parser.error('one or both of\n' + ' %s\n' + ' %s\n' + 'exists from a previous run; please clean up before ' + 'running again' + % (oldindexfn, olddatafn)) + + write('shrinking %s\n' % indexfn) + prefix = os.path.basename(indexfn)[:-1] + (tmpfd, tmpindexfn) = tempfile.mkstemp(dir=os.path.dirname(indexfn), + prefix=prefix, + suffix='.i') + tmpdatafn = tmpindexfn[:-2] + '.d' + os.close(tmpfd) + + r1 = revlog.revlog(util.opener(os.getcwd(), audit=False), indexfn) + r2 = revlog.revlog(util.opener(os.getcwd(), audit=False), tmpindexfn) + + # Don't use repo.transaction(), because then things get hairy with + # paths: some need to be relative to .hg, and some need to be + # absolute. Doing it this way keeps things simple: everything is an + # absolute path. + lock = repo.lock(wait=False) + tr = transaction.transaction(sys.stderr.write, + open, + repo.sjoin('journal')) + + try: + try: + order = toposort(r1) + writerevs(r1, r2, order, tr) + report(datafn, tmpdatafn) + tr.close() + except: + # Abort transaction first, so we truncate the files before + # deleting them. + tr.abort() + if os.path.exists(tmpindexfn): + os.unlink(tmpindexfn) + if os.path.exists(tmpdatafn): + os.unlink(tmpdatafn) + raise + finally: + lock.release() + + os.link(indexfn, oldindexfn) + os.link(datafn, olddatafn) + os.rename(tmpindexfn, indexfn) + os.rename(tmpdatafn, datafn) + write('note: old revlog saved in:\n' + ' %s\n' + ' %s\n' + '(You can delete those files when you are satisfied that your\n' + 'repository is still sane. ' + 'Running \'hg verify\' is strongly recommended.)\n' + % (oldindexfn, olddatafn)) + +try: + main() +except KeyboardInterrupt: + sys.exit("interrupted")
--- a/doc/hg.1.txt Sat Oct 03 23:36:08 2009 +0200 +++ b/doc/hg.1.txt Sat Oct 03 23:38:10 2009 +0200 @@ -95,6 +95,6 @@ ------- Copyright \(C) 2005-2009 Matt Mackall. Free use of this software is granted under the terms of the GNU General -Public License (GPL). +Public License version 2. .. include:: common.txt
--- a/doc/hgignore.5.txt Sat Oct 03 23:36:08 2009 +0200 +++ b/doc/hgignore.5.txt Sat Oct 03 23:38:10 2009 +0200 @@ -106,6 +106,6 @@ This manual page is copyright 2006 Vadim Gelfer. Mercurial is copyright 2005-2009 Matt Mackall. Free use of this software is granted under the terms of the GNU General -Public License (GPL). +Public License version 2. .. include:: common.txt
--- a/doc/hgrc.5.txt Sat Oct 03 23:36:08 2009 +0200 +++ b/doc/hgrc.5.txt Sat Oct 03 23:38:10 2009 +0200 @@ -946,6 +946,6 @@ This manual page is copyright 2005 Bryan O'Sullivan. Mercurial is copyright 2005-2009 Matt Mackall. Free use of this software is granted under the terms of the GNU General -Public License (GPL). +Public License version 2. .. include:: common.txt
--- a/hgext/color.py Sat Oct 03 23:36:08 2009 +0200 +++ b/hgext/color.py Sat Oct 03 23:38:10 2009 +0200 @@ -160,9 +160,8 @@ return retval _patch_effects = { 'applied': ['blue', 'bold', 'underline'], - 'missing': ['red', 'bold'], - 'unapplied': ['black', 'bold'], } - + 'missing': ['red', 'bold'], + 'unapplied': ['black', 'bold'], } def colorwrap(orig, s): '''wrap ui.write for colored diff output''' lines = s.split('\n')
--- a/hgext/convert/subversion.py Sat Oct 03 23:36:08 2009 +0200 +++ b/hgext/convert/subversion.py Sat Oct 03 23:38:10 2009 +0200 @@ -153,11 +153,13 @@ def issvnurl(url): try: proto, path = url.split('://', 1) - path = urllib.url2pathname(path) + if proto == 'file': + path = urllib.url2pathname(path) except ValueError: proto = 'file' path = os.path.abspath(url) - path = path.replace(os.sep, '/') + if proto == 'file': + path = path.replace(os.sep, '/') check = protomap.get(proto, lambda p, p2: False) while '/' in path: if check(path, proto):
--- a/hgext/extdiff.py Sat Oct 03 23:36:08 2009 +0200 +++ b/hgext/extdiff.py Sat Oct 03 23:38:10 2009 +0200 @@ -42,9 +42,9 @@ ''' from mercurial.i18n import _ -from mercurial.node import short +from mercurial.node import short, nullid from mercurial import cmdutil, util, commands -import os, shlex, shutil, tempfile +import os, shlex, shutil, tempfile, re def snapshot(ui, repo, files, node, tmproot): '''snapshot files as of some revision @@ -69,7 +69,7 @@ for fn in files: wfn = util.pconvert(fn) if not wfn in ctx: - # skipping new file after a merge ? + # File doesn't exist; could be a bogus modify continue ui.note(' %s\n' % wfn) dest = os.path.join(base, wfn) @@ -96,52 +96,95 @@ revs = opts.get('rev') change = opts.get('change') + args = ' '.join(diffopts) + do3way = '$parent2' in args if revs and change: msg = _('cannot specify --rev and --change at the same time') raise util.Abort(msg) elif change: node2 = repo.lookup(change) - node1 = repo[node2].parents()[0].node() + node1a, node1b = repo.changelog.parents(node2) else: - node1, node2 = cmdutil.revpair(repo, revs) + node1a, node2 = cmdutil.revpair(repo, revs) + if not revs: + node1b = repo.dirstate.parents()[1] + else: + node1b = nullid + + # Disable 3-way merge if there is only one parent + if do3way: + if node1b == nullid: + do3way = False matcher = cmdutil.match(repo, pats, opts) - modified, added, removed = repo.status(node1, node2, matcher)[:3] - if not (modified or added or removed): - return 0 + mod_a, add_a, rem_a = map(set, repo.status(node1a, node2, matcher)[:3]) + if do3way: + mod_b, add_b, rem_b = map(set, repo.status(node1b, node2, matcher)[:3]) + else: + mod_b, add_b, rem_b = set(), set(), set() + modadd = mod_a | add_a | mod_b | add_b + common = modadd | rem_a | rem_b + if not common: + return 0 tmproot = tempfile.mkdtemp(prefix='extdiff.') - dir2root = '' try: - # Always make a copy of node1 - dir1 = snapshot(ui, repo, modified + removed, node1, tmproot)[0] - changes = len(modified) + len(removed) + len(added) + # Always make a copy of node1a (and node1b, if applicable) + dir1a_files = mod_a | rem_a | ((mod_b | add_b) - add_a) + dir1a = snapshot(ui, repo, dir1a_files, node1a, tmproot)[0] + if do3way: + dir1b_files = mod_b | rem_b | ((mod_a | add_a) - add_b) + dir1b = snapshot(ui, repo, dir1b_files, node1b, tmproot)[0] + else: + dir1b = None + + fns_and_mtime = [] # If node2 in not the wc or there is >1 change, copy it - if node2 or changes > 1: - dir2, fns_and_mtime = snapshot(ui, repo, modified + added, node2, tmproot) + dir2root = '' + if node2: + dir2 = snapshot(ui, repo, modadd, node2, tmproot)[0] + elif len(common) > 1: + #we only actually need to get the files to copy back to the working + #dir in this case (because the other cases are: diffing 2 revisions + #or single file -- in which case the file is already directly passed + #to the diff tool). + dir2, fns_and_mtime = snapshot(ui, repo, modadd, None, tmproot) else: # This lets the diff tool open the changed file directly dir2 = '' dir2root = repo.root - fns_and_mtime = [] # If only one change, diff the files instead of the directories - if changes == 1 : - if len(modified): - dir1 = os.path.join(dir1, util.localpath(modified[0])) - dir2 = os.path.join(dir2root, dir2, util.localpath(modified[0])) - elif len(removed) : - dir1 = os.path.join(dir1, util.localpath(removed[0])) - dir2 = os.devnull - else: - dir1 = os.devnull - dir2 = os.path.join(dir2root, dir2, util.localpath(added[0])) + # Handle bogus modifies correctly by checking if the files exist + if len(common) == 1: + common_file = util.localpath(common.pop()) + dir1a = os.path.join(dir1a, common_file) + if not os.path.isfile(os.path.join(tmproot, dir1a)): + dir1a = os.devnull + if do3way: + dir1b = os.path.join(dir1b, common_file) + if not os.path.isfile(os.path.join(tmproot, dir1b)): + dir1b = os.devnull + dir2 = os.path.join(dir2root, dir2, common_file) - cmdline = ('%s %s %s %s' % - (util.shellquote(diffcmd), ' '.join(diffopts), - util.shellquote(dir1), util.shellquote(dir2))) + # Function to quote file/dir names in the argument string + # When not operating in 3-way mode, an empty string is returned for parent2 + replace = dict(parent=dir1a, parent1=dir1a, parent2=dir1b, child=dir2) + def quote(match): + key = match.group()[1:] + if not do3way and key == 'parent2': + return '' + return util.shellquote(replace[key]) + + # Match parent2 first, so 'parent1?' will match both parent1 and parent + regex = '\$(parent2|parent1?|child)' + if not do3way and not re.search(regex, args): + args += ' $parent1 $child' + args = re.sub(regex, quote, args) + cmdline = util.shellquote(diffcmd) + ' ' + args + ui.debug('running %r in %s\n' % (cmdline, tmproot)) util.system(cmdline, cwd=tmproot) @@ -173,11 +216,11 @@ that revision is compared to the working directory, and, when no revisions are specified, the working directory files are compared to its parent.''' - program = opts['program'] or 'diff' - if opts['program']: - option = opts['option'] - else: - option = opts['option'] or ['-Npru'] + program = opts.get('program') + option = opts.get('option') + if not program: + program = 'diff' + option = option or ['-Npru'] return dodiff(ui, repo, program, option, pats, opts) cmdtable = {
--- a/hgext/inotify/__init__.py Sat Oct 03 23:36:08 2009 +0200 +++ b/hgext/inotify/__init__.py Sat Oct 03 23:38:10 2009 +0200 @@ -17,28 +17,7 @@ def serve(ui, repo, **opts): '''start an inotify server for this repository''' - timeout = opts.get('timeout') - if timeout: - timeout = float(timeout) * 1e3 - - class service(object): - def init(self): - try: - self.master = server.master(ui, repo.dirstate, - repo.root, timeout) - except server.AlreadyStartedException, inst: - raise util.Abort(str(inst)) - - def run(self): - try: - self.master.run() - finally: - self.master.shutdown() - - service = service() - logfile = ui.config('inotify', 'log') - cmdutil.service(opts, initfn=service.init, runfn=service.run, - logfile=logfile) + server.start(ui, repo.dirstate, repo.root, opts) def debuginotify(ui, repo, **opts): '''debugging information for inotify extension
--- a/hgext/inotify/client.py Sat Oct 03 23:36:08 2009 +0200 +++ b/hgext/inotify/client.py Sat Oct 03 23:38:10 2009 +0200 @@ -34,7 +34,8 @@ self.ui.debug('(starting inotify server)\n') try: try: - server.start(self.ui, self.dirstate, self.root) + server.start(self.ui, self.dirstate, self.root, + dict(daemon=True, daemon_pipefds='')) except server.AlreadyStartedException, inst: # another process may have started its own # inotify server while this one was starting.
--- a/hgext/inotify/server.py Sat Oct 03 23:36:08 2009 +0200 +++ b/hgext/inotify/server.py Sat Oct 03 23:38:10 2009 +0200 @@ -7,7 +7,7 @@ # GNU General Public License version 2, incorporated herein by reference. from mercurial.i18n import _ -from mercurial import osutil, util +from mercurial import cmdutil, osutil, util import common import errno, os, select, socket, stat, struct, sys, tempfile, time @@ -823,52 +823,29 @@ sys.exit(0) pollable.run() -def start(ui, dirstate, root): - def closefds(ignore): - # (from python bug #1177468) - # close all inherited file descriptors - # Python 2.4.1 and later use /dev/urandom to seed the random module's RNG - # a file descriptor is kept internally as os._urandomfd (created on demand - # the first time os.urandom() is called), and should not be closed - try: - os.urandom(4) - urandom_fd = getattr(os, '_urandomfd', None) - except AttributeError: - urandom_fd = None - ignore.append(urandom_fd) - for fd in range(3, 256): - if fd in ignore: - continue +def start(ui, dirstate, root, opts): + timeout = opts.get('timeout') + if timeout: + timeout = float(timeout) * 1e3 + + class service(object): + def init(self): try: - os.close(fd) - except OSError: - pass - - m = master(ui, dirstate, root) - sys.stdout.flush() - sys.stderr.flush() + self.master = master(ui, dirstate, root, timeout) + except AlreadyStartedException, inst: + raise util.Abort(str(inst)) - pid = os.fork() - if pid: - return pid - - closefds(pollable.instances.keys()) - os.setsid() - - fd = os.open('/dev/null', os.O_RDONLY) - os.dup2(fd, 0) - if fd > 0: - os.close(fd) + def run(self): + try: + self.master.run() + finally: + self.master.shutdown() - fd = os.open(ui.config('inotify', 'log', '/dev/null'), - os.O_RDWR | os.O_CREAT | os.O_TRUNC) - os.dup2(fd, 1) - os.dup2(fd, 2) - if fd > 2: - os.close(fd) + runargs = None + if 'inserve' not in sys.argv: + runargs = [sys.argv[0], 'inserve', '-R', root] - try: - m.run() - finally: - m.shutdown() - os._exit(0) + service = service() + logfile = ui.config('inotify', 'log') + cmdutil.service(opts, initfn=service.init, runfn=service.run, + logfile=logfile, runargs=runargs)
--- a/hgext/keyword.py Sat Oct 03 23:36:08 2009 +0200 +++ b/hgext/keyword.py Sat Oct 03 23:38:10 2009 +0200 @@ -244,12 +244,14 @@ return t2 != text return revlog.revlog.cmp(self, node, text) -def _status(ui, repo, kwt, unknown, *pats, **opts): +def _status(ui, repo, kwt, *pats, **opts): '''Bails out if [keyword] configuration is not active. Returns status of working directory.''' if kwt: - match = cmdutil.match(repo, pats, opts) - return repo.status(match=match, unknown=unknown, clean=True) + unknown = (opts.get('unknown') or opts.get('all') + or opts.get('untracked')) + return repo.status(match=cmdutil.match(repo, pats, opts), clean=True, + unknown=unknown) if ui.configitems('keyword'): raise util.Abort(_('[keyword] patterns cannot match')) raise util.Abort(_('no [keyword] patterns configured')) @@ -259,7 +261,7 @@ if repo.dirstate.parents()[1] != nullid: raise util.Abort(_('outstanding uncommitted merge')) kwt = kwtools['templater'] - status = _status(ui, repo, kwt, False, *pats, **opts) + status = _status(ui, repo, kwt, *pats, **opts) modified, added, removed, deleted = status[:4] if modified or added or removed or deleted: raise util.Abort(_('outstanding uncommitted changes')) @@ -380,30 +382,32 @@ See "hg help keyword" on how to construct patterns both for inclusion and exclusion of files. - Use -u/--untracked to list untracked files as well. - - With -a/--all and -v/--verbose the codes used to show the status + With -A/--all and -v/--verbose the codes used to show the status of files are:: K = keyword expansion candidate - k = keyword expansion candidate (untracked) + k = keyword expansion candidate (not tracked) I = ignored - i = ignored (untracked) + i = ignored (not tracked) ''' kwt = kwtools['templater'] - status = _status(ui, repo, kwt, opts.get('untracked'), *pats, **opts) + status = _status(ui, repo, kwt, *pats, **opts) + cwd = pats and repo.getcwd() or '' modified, added, removed, deleted, unknown, ignored, clean = status - files = sorted(modified + added + clean) + files = [] + if not (opts.get('unknown') or opts.get('untracked')) or opts.get('all'): + files = sorted(modified + added + clean) wctx = repo[None] kwfiles = [f for f in files if kwt.iskwfile(f, wctx.flags)] - kwuntracked = [f for f in unknown if kwt.iskwfile(f, wctx.flags)] - cwd = pats and repo.getcwd() or '' - kwfstats = (not opts.get('ignore') and - (('K', kwfiles), ('k', kwuntracked),) or ()) + kwunknown = [f for f in unknown if kwt.iskwfile(f, wctx.flags)] + if not opts.get('ignore') or opts.get('all'): + showfiles = kwfiles, kwunknown + else: + showfiles = [], [] if opts.get('all') or opts.get('ignore'): - kwfstats += (('I', [f for f in files if f not in kwfiles]), - ('i', [f for f in unknown if f not in kwuntracked]),) - for char, filenames in kwfstats: + showfiles += ([f for f in files if f not in kwfiles], + [f for f in unknown if f not in kwunknown]) + for char, filenames in zip('KkIi', showfiles): fmt = (opts.get('all') or ui.verbose) and '%s %%s\n' % char or '%s\n' for f in filenames: ui.write(fmt % repo.pathto(f, cwd)) @@ -545,9 +549,12 @@ _('hg kwexpand [OPTION]... [FILE]...')), 'kwfiles': (files, - [('a', 'all', None, _('show keyword status flags of all files')), + [('A', 'all', None, _('show keyword status flags of all files')), ('i', 'ignore', None, _('show files excluded from expansion')), - ('u', 'untracked', None, _('additionally show untracked files')), + ('u', 'unknown', None, _('only show unknown (not tracked) files')), + ('a', 'all', None, + _('show keyword status flags of all files (DEPRECATED)')), + ('u', 'untracked', None, _('only show untracked files (DEPRECATED)')), ] + commands.walkopts, _('hg kwfiles [OPTION]... [FILE]...')), 'kwshrink': (shrink, commands.walkopts,
--- a/hgext/notify.py Sat Oct 03 23:36:08 2009 +0200 +++ b/hgext/notify.py Sat Oct 03 23:38:10 2009 +0200 @@ -43,6 +43,7 @@ diffstat = True # add a diffstat before the diff content sources = serve # notify if source of incoming changes in this list # (serve == ssh or http, push, pull, bundle) + merge = False # send notification for merges (default True) [email] from = user@host.com # email address to send as if none given [web] @@ -111,6 +112,7 @@ self.test = self.ui.configbool('notify', 'test', True) self.charsets = mail._charsets(self.ui) self.subs = self.subscribers() + self.merge = self.ui.configbool('notify', 'merge', True) mapfile = self.ui.config('notify', 'style') template = (self.ui.config('notify', hooktype) or @@ -166,10 +168,13 @@ return self.ui.config('web', 'baseurl') + (path or self.root) def node(self, ctx, **props): - '''format one changeset.''' + '''format one changeset, unless it is a suppressed merge.''' + if not self.merge and len(ctx.parents()) > 1: + return False self.t.show(ctx, changes=ctx.changeset(), baseurl=self.ui.config('web', 'baseurl'), root=self.repo.root, webroot=self.root, **props) + return True def skipsource(self, source): '''true if incoming changes from this source should be skipped.''' @@ -283,16 +288,29 @@ return ui.pushbuffer() + data = '' + count = 0 if hooktype == 'changegroup': start, end = ctx.rev(), len(repo) - count = end - start for rev in xrange(start, end): - n.node(repo[rev]) - n.diff(ctx, repo['tip']) + if n.node(repo[rev]): + count += 1 + else: + data += ui.popbuffer() + ui.note(_('notify: suppressing notification for merge %d:%s\n') % + (rev, repo[rev].hex()[:12])) + ui.pushbuffer() + if count: + n.diff(ctx, repo['tip']) else: - count = 1 - n.node(ctx) + if not n.node(ctx): + ui.popbuffer() + ui.note(_('notify: suppressing notification for merge %d:%s\n') % + (ctx.rev(), ctx.hex()[:12])) + return + count += 1 n.diff(ctx) - data = ui.popbuffer() - n.send(ctx, count, data) + data += ui.popbuffer() + if count: + n.send(ctx, count, data)
--- a/i18n/da.po Sat Oct 03 23:36:08 2009 +0200 +++ b/i18n/da.po Sat Oct 03 23:38:10 2009 +0200 @@ -17,8 +17,8 @@ msgstr "" "Project-Id-Version: Mercurial\n" "Report-Msgid-Bugs-To: <mercurial-devel@selenic.com>\n" -"POT-Creation-Date: 2009-07-20 23:05+0200\n" -"PO-Revision-Date: 2009-07-21 00:18+0200\n" +"POT-Creation-Date: 2009-09-29 00:26+0200\n" +"PO-Revision-Date: 2009-09-29 00:41+0200\n" "Last-Translator: <mg@lazybytes.net>\n" "Language-Team: Danish\n" "MIME-Version: 1.0\n" @@ -1007,7 +1007,8 @@ #, python-format msgid "" "unexpected response from CVS server (expected \"Valid-requests\", but got %r)" -msgstr "uventet svar fra CVS serveren (forventede \"Valid-requests\", men fik %r)" +msgstr "" +"uventet svar fra CVS serveren (forventede \"Valid-requests\", men fik %r)" #, python-format msgid "%d bytes missing from remote file" @@ -1086,6 +1087,10 @@ msgid "%d changeset entries\n" msgstr "%d ændringer\n" +#, python-format +msgid "darcs version 2.1 or newer needed (found %r)" +msgstr "" + msgid "Python ElementTree module is not available" msgstr "Python ElementTree modulet er ikke tilstede" @@ -1492,10 +1497,6 @@ msgstr "sammenføjer med %d:%s\n" #, python-format -msgid "Automated merge with %s" -msgstr "Automatisk sammenføjning med %s" - -#, python-format msgid "new changeset %d:%s merges remote changes with local\n" msgstr "ny ændring %d:%s fletter fjernændringer sammen med lokale\n" @@ -1576,10 +1577,6 @@ "arbejdskopien af .hgsigs er ændret (deponer venligst .hgsigs manuelt eller " "brug --force)" -#, python-format -msgid "Added signature for changeset %s" -msgstr "Tilføjede underskrift af ændring %s" - msgid "unknown signature version" msgstr "ukendt underskrift-version" @@ -2133,7 +2130,9 @@ msgid "" "\n" "%s keywords written to %s:\n" -msgstr "\n%s nøgleord skrevet til %s:\n" +msgstr "" +"\n" +"%s nøgleord skrevet til %s:\n" msgid "unhooked all commit hooks\n" msgstr "" @@ -3789,22 +3788,22 @@ msgstr "" msgid "cannot use both abort and continue" -msgstr "" +msgstr "abort og continue kan ikke angives samtidig" msgid "cannot use collapse with continue or abort" -msgstr "" +msgstr "continue eller abort kan ikke angives samtidig med collapse" msgid "abort and continue do not allow specifying revisions" -msgstr "" +msgstr "abort og continue tillader ikke at der angives revisioner" msgid "cannot specify both a revision and a base" -msgstr "" +msgstr "man kan ikke angive både en revision og en basis" msgid "nothing to rebase\n" msgstr "" msgid "cannot use both keepbranches and extrafn" -msgstr "" +msgstr "man kan ikke bruge både keepbranches og extrafn" msgid "rebase merging completed\n" msgstr "" @@ -3817,7 +3816,7 @@ #, python-format msgid "%d revisions have been skipped\n" -msgstr "" +msgstr "sprang %d revisioner over\n" msgid " set parents\n" msgstr "" @@ -4275,7 +4274,7 @@ msgstr "" #, python-format -msgid "[win32mbcs] filename conversion fail with %s encoding\n" +msgid "[win32mbcs] filename conversion failed with %s encoding\n" msgstr "" msgid "[win32mbcs] cannot activate on this platform.\n" @@ -4668,12 +4667,27 @@ " be expensive.\n" " " msgstr "" +"tilføj alle nye filer, fjern alle manglende filer\n" +"\n" +" Tilføj alle nye filer og fjern alle manglende filer fra depotet.\n" +"\n" +" Nye filer bliver ignoreret hvis de matcher et af mønstrene i\n" +" .hgignore. Som ved add, så træder disse ændringer først i kræft\n" +" ved næste commit.\n" +"\n" +" Brug -s/--similarity tilvalget for at opdage omdøbte filer. Med en\n" +" parameter større end 0 bliver hver fjernet fil sammenlignet med\n" +" enhver tilføjet fil og filer der er tilstrækkelig ens bliver\n" +" opført som omdøbte. Dette tilvalg tager et procenttal mellem 0\n" +" (slået fra) og 100 (filer skal være identiske) som parameter. At\n" +" opdage omdøbninger på denne måde kan være dyrt.\n" +" " msgid "similarity must be a number" -msgstr "" +msgstr "lighedsgrad skal være et tal" msgid "similarity must be between 0 and 100" -msgstr "" +msgstr "lighedsgrad skal være mellem 0 og 100" msgid "" "show changeset information by line for each file\n" @@ -4705,10 +4719,10 @@ " " msgid "at least one filename or pattern is required" -msgstr "" +msgstr "kræver mindst et filnavn eller mønster" msgid "at least one of -n/-c is required for -l" -msgstr "" +msgstr "brug af -l kræver mindst en af -n/-c" #, python-format msgid "%s: binary file\n" @@ -4744,10 +4758,10 @@ msgstr "intet arbejdskatalog: angive venligst en revision" msgid "repository root cannot be destination" -msgstr "" +msgstr "depotets rod kan ikke bruges som destination" msgid "cannot archive plain files to stdout" -msgstr "" +msgstr "flade filer kan ikke arkiveres til standarduddata" msgid "" "reverse effect of earlier changeset\n" @@ -4806,11 +4820,7 @@ msgstr "%s er ikke forælder til %s" msgid "cannot use --parent on non-merge changeset" -msgstr "" - -#, python-format -msgid "Backed out changeset %s" -msgstr "" +msgstr "kan ikke bruge --parent på en ændringer som ikke er en sammenføjning" #, python-format msgid "changeset %s backs out changeset %s\n" @@ -4824,7 +4834,7 @@ msgstr "" msgid "(use \"backout --merge\" if you want to auto-merge)\n" -msgstr "" +msgstr "(brug \"backout --merge\" hvis du vil sammenføje automatisk)\n" msgid "" "subdivision search of changesets\n" @@ -4872,7 +4882,7 @@ msgstr "" msgid "(use of 'hg bisect <cmd>' is deprecated)\n" -msgstr "" +msgstr "(formen 'hg bisect <kommando>' er forældet)\n" msgid "incompatible arguments" msgstr "inkompatible argumenter" @@ -4883,7 +4893,7 @@ #, python-format msgid "failed to execute %s" -msgstr "" +msgstr "kunne ikke køre %s" #, python-format msgid "%s killed" @@ -4917,10 +4927,27 @@ " 'hg commit --close-branch' to mark this branch as closed.\n" " " msgstr "" +"angiv eller vis navnet på den aktuelle gren\n" +"\n" +" Uden noget argument vises navnet på den nuværende gren. Med et\n" +" argument angives arbejdskatalogets grennavn (grenen eksisterer\n" +" ikke i depotet før næste deponering). Det anbefales at den primære\n" +" udvikling foretages på 'default' grenen.\n" +"\n" +" Med mindre -f/--force bruges, så vil branch ikke lade dig bruge et\n" +" grennavn som allerede eksisterer, selv hvis det er inaktivt.\n" +"\n" +" Brug -C/--clean for at nulstille arbejdskatalogs gren til samme\n" +" gren dets forældre-ændring og derved negere end tidligere ændring.\n" +"\n" +" Brug kommandoen 'hg update' for at skifte til en eksisterende\n" +" gren. Brug 'hg commit --close-branch' for at markere denne gren\n" +" som lukket.\n" +" " #, python-format msgid "reset working directory to branch %s\n" -msgstr "" +msgstr "nulstil arbejdskataloget til gren %s\n" msgid "a branch of the same name already exists (use --force to override)" msgstr "" @@ -5003,6 +5030,22 @@ " %p root-relative path name of file being printed\n" " " msgstr "" +"udskriv den aktuelle eller en given revision af filer\n" +"\n" +" Udskriver de angivne filer som de så ud ved den givne revision.\n" +" Hvis der ikke angves en revision, så bruges forældre-revisionen\n" +" til arbejdskataloget, eller spidsen hvis der ikke er hentet noget\n" +" arbejdskatalog.\n" +"\n" +" Output kan gemmes i en fil hvis navn angives med et formatstreng.\n" +" Reglerne for formatteringen er de samme som for export-kommandoen\n" +" med følgende tilføjelser:\n" +"\n" +" %s grundnavn for filen som udskrives\n" +" %d katalognavn for filen som blvier udskrevet\n" +" eller '.' hvis filen er i katalogets rod\n" +" %p rod-relativ sti for filen som bliver udkrevet\n" +" " msgid "" "make a copy of an existing repository\n" @@ -5525,24 +5568,29 @@ "\n" " With no arguments, show all repository head changesets.\n" "\n" -" Repository \"heads\" are changesets that don't have child\n" -" changesets. They are where development generally takes place and\n" -" are the usual targets for update and merge operations.\n" +" Repository \"heads\" are changesets with no child changesets. They are\n" +" where development generally takes place and are the usual targets\n" +" for update and merge operations.\n" "\n" " If one or more REV is given, the \"branch heads\" will be shown for\n" -" the named branch associated with that revision. The name of the\n" -" branch is called the revision's branch tag.\n" -"\n" -" Branch heads are revisions on a given named branch that do not have\n" -" any descendants on the same branch. A branch head could be a true head\n" -" or it could be the last changeset on a branch before a new branch\n" -" was created. If none of the branch heads are true heads, the branch\n" -" is considered inactive. If -c/--closed is specified, also show branch\n" -" heads marked closed (see hg commit --close-branch).\n" -"\n" -" If STARTREV is specified only those heads (or branch heads) that\n" -" are descendants of STARTREV will be displayed.\n" -" " +" the named branch associated with the specified changeset(s).\n" +"\n" +" Branch heads are changesets on a named branch with no descendants on\n" +" the same branch. A branch head could be a \"true\" (repository) head,\n" +" or it could be the last changeset on that branch before it was\n" +" merged into another branch, or it could be the last changeset on the\n" +" branch before a new branch was created. If none of the branch heads\n" +" are true heads, the branch is considered inactive.\n" +"\n" +" If -c/--closed is specified, also show branch heads marked closed\n" +" (see hg commit --close-branch).\n" +"\n" +" If STARTREV is specified, only those heads that are descendants of\n" +" STARTREV will be displayed.\n" +" " +msgstr "" + +msgid "you must specify a branch to use --closed" msgstr "" #, python-format @@ -6403,17 +6451,9 @@ msgstr "mærkaten '%s' er ikke en lokal mærkat" #, python-format -msgid "Removed tag %s" -msgstr "Mærke %s er fjernet" - -#, python-format msgid "tag '%s' already exists (use -f to force)" msgstr "mærkaten '%s' eksisterer allerede (brug -f for at gennemtvinge)" -#, python-format -msgid "Added tag %s for changeset %s" -msgstr "Tilføjede mærkat %s til ændring %s" - msgid "" "list repository tags\n" "\n" @@ -6511,6 +6551,9 @@ " Se 'hg help dates' for en liste af gyldige formater til -d/--date.\n" " " +msgid "cannot specify both -c/--check and -C/--clean" +msgstr "man kan ikke angive både -c/--check og -C/--clean" + msgid "uncommitted local changes" msgstr "udeponerede lokale ændringer" @@ -6525,6 +6568,14 @@ " integrity of their crosslinks and indices.\n" " " msgstr "" +"verificer depotets integritet\n" +"\n" +" Verificer integreteten af det aktuelle depot.\n" +"\n" +" Dette vil lave en udførlig kontrol af depotets integritet.\n" +" Hashværdier og tjeksummer valideres for hver indgang i\n" +" historikfilen, manifæstet og fulgte filer. Desuden valideres\n" +" integriteten af deres krydslinks og indekser." msgid "output version and copyright information" msgstr "udskriv version- og copyrightinformation" @@ -6539,6 +6590,11 @@ "This is free software; see the source for copying conditions. There is NO\n" "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" msgstr "" +"\n" +"Copyright (C) 2005-2009 Matt Mackall <mpm@selenic.com> og andre\n" +"Dette er frit programmel; se kildekoden for kopieringsbetingelser. Der\n" +"gives INGEN GARANTI; ikke engang for SALGBARHED eller EGNETHED FOR\n" +"NOGET BESTEMT FORMÅL.\n" msgid "repository root directory or symbolic path name" msgstr "depotrodfolder eller symbolsk stinavn" @@ -6721,10 +6777,10 @@ msgstr "[-gbsr] [-c KOMMANDO] [REV]" msgid "set branch name even if it shadows an existing branch" -msgstr "" +msgstr "sæt grennavnet selv hvis det overskygger en eksisterende gren" msgid "reset branch name to parent branch name" -msgstr "" +msgstr "nulstil grennavnet til forældre-grennavnet" msgid "[-fC] [NAME]" msgstr "[-fC] [NAVN]" @@ -6732,8 +6788,8 @@ msgid "show only branches that have unmerged heads" msgstr "vil kun grene som har usammenføjne hoveder" -msgid "show normal and closed heads" -msgstr "vis normale og lukkede hoveder" +msgid "show normal and closed branches" +msgstr "vis normale og lukkede grene" msgid "[-a]" msgstr "[-a]" @@ -6847,7 +6903,7 @@ msgstr "[TILVALG]... [-r REV1 [-r REV2]] [FIL]..." msgid "diff against the second parent" -msgstr "" +msgstr "find forskelle i forhold til den anden forældre" msgid "[OPTION]... [-o OUTFILESPEC] REV..." msgstr "[TILVALG]... [-o UDFILSPECIFIKATION] REV..." @@ -6879,8 +6935,11 @@ msgid "show only heads which are descendants of REV" msgstr "vis kun hoveder som er efterkommere af REV" -msgid "show only the active heads from open branches" -msgstr "vis kun aktive hoveder fra åbne grene" +msgid "show only the active branch heads from open branches" +msgstr "vis kun de aktive grenhoveder fra åbne grene" + +msgid "show normal and closed branch heads" +msgstr "vis normale og lukkede grenhoveder" msgid "[-r STARTREV] [REV]..." msgstr "[-r STARTREV] [REV]..." @@ -7766,22 +7825,21 @@ " Mercurial supports several ways to specify individual revisions.\n" "\n" " A plain integer is treated as a revision number. Negative integers\n" -" are treated as topological offsets from the tip, with -1 denoting\n" -" the tip. As such, negative numbers are only useful if you've\n" -" memorized your local tree numbers and want to save typing a single\n" -" digit. This editor suggests copy and paste.\n" +" are treated as sequential offsets from the tip, with -1 denoting\n" +" the tip, -2 denoting the revision prior to the tip, and so forth.\n" "\n" " A 40-digit hexadecimal string is treated as a unique revision\n" " identifier.\n" "\n" " A hexadecimal string less than 40 characters long is treated as a\n" -" unique revision identifier, and referred to as a short-form\n" +" unique revision identifier and is referred to as a short-form\n" " identifier. A short-form identifier is only valid if it is the\n" " prefix of exactly one full-length identifier.\n" "\n" -" Any other string is treated as a tag name, which is a symbolic\n" -" name associated with a revision identifier. Tag names may not\n" -" contain the \":\" character.\n" +" Any other string is treated as a tag or branch name. A tag name is\n" +" a symbolic name associated with a revision identifier. A branch\n" +" name denotes the tipmost revision of that branch. Tag and branch\n" +" names must not contain the \":\" character.\n" "\n" " The reserved name \"tip\" is a special tag that always identifies\n" " the most recent revision.\n" @@ -7943,13 +8001,19 @@ " - nonempty: Any text. Returns '(none)' if the string is empty.\n" " - hgdate: Date. Returns the date as a pair of numbers:\n" " \"1157407993 25200\" (Unix timestamp, timezone offset).\n" -" - isodate: Date. Returns the date in ISO 8601 format.\n" +" - isodate: Date. Returns the date in ISO 8601 format: \"2009-08-18\n" +" 13:00 +0200\".\n" +" - isodatesec: Date. Returns the date in ISO 8601 format, including\n" +" seconds: \"2009-08-18 13:00:13 +0200\". See also the\n" +" rfc3339date filter.\n" " - localdate: Date. Converts a date to local date.\n" " - obfuscate: Any text. Returns the input text rendered as a\n" " sequence of XML entities.\n" " - person: Any text. Returns the text before an email address.\n" " - rfc822date: Date. Returns a date using the same format used\n" -" in email headers.\n" +" in email headers: \"Tue, 18 Aug 2009 13:00:13 +0200\".\n" +" - rfc3339date: Date. Returns a date using the Internet date format\n" +" specified in RFC 3339: \"2009-08-18T13:00:13+02:00\".\n" " - short: Changeset hash. Returns the short form of a changeset\n" " hash, i.e. a 12-byte hexadecimal string.\n" " - shortdate: Date. Returns a date like \"2006-09-18\".\n"
--- a/i18n/pt_BR.po Sat Oct 03 23:36:08 2009 +0200 +++ b/i18n/pt_BR.po Sat Oct 03 23:38:10 2009 +0200 @@ -9812,22 +9812,21 @@ " Mercurial supports several ways to specify individual revisions.\n" "\n" " A plain integer is treated as a revision number. Negative integers\n" -" are treated as topological offsets from the tip, with -1 denoting\n" -" the tip. As such, negative numbers are only useful if you've\n" -" memorized your local tree numbers and want to save typing a single\n" -" digit. This editor suggests copy and paste.\n" +" are treated as sequential offsets from the tip, with -1 denoting\n" +" the tip, -2 denoting the revision prior to the tip, and so forth.\n" "\n" " A 40-digit hexadecimal string is treated as a unique revision\n" " identifier.\n" "\n" " A hexadecimal string less than 40 characters long is treated as a\n" -" unique revision identifier, and referred to as a short-form\n" +" unique revision identifier and is referred to as a short-form\n" " identifier. A short-form identifier is only valid if it is the\n" " prefix of exactly one full-length identifier.\n" "\n" -" Any other string is treated as a tag name, which is a symbolic\n" -" name associated with a revision identifier. Tag names may not\n" -" contain the \":\" character.\n" +" Any other string is treated as a tag or branch name. A tag name is\n" +" a symbolic name associated with a revision identifier. A branch\n" +" name denotes the tipmost revision of that branch. Tag and branch\n" +" names must not contain the \":\" character.\n" "\n" " The reserved name \"tip\" is a special tag that always identifies\n" " the most recent revision.\n" @@ -9846,23 +9845,22 @@ " individuais.\n" "\n" " Um simples inteiro é tratado como um número de revisão. Inteiros\n" -" negativos são tratados como contados topologicamente a partir da\n" -" tip, com -1 denotando a tip. Assim, números negativos são úteis\n" -" apenas se você memorizou os números de sua árvore local e quiser\n" -" evitar digitar um único caractere. Este editor sugere copiar e\n" -" colar.\n" +" negativos são contados a partir da tip, com -1 denotando a tip,\n" +" -2 denotando a revisão anterior à tip, e assim por diante.\n" "\n" " Uma string hexadecimal de 40 dígitos é tratada como um\n" " identificador único de revisão.\n" "\n" " Uma string hexadecimal de menos de 40 caracteres é tratada como\n" -" um identificador único de revisão, e referida como um\n" -" identificador curto. Um identificador curto é válido apenas se\n" -" for o prefixo de um identificador completo.\n" -"\n" -" Qualquer outra string é tratada como um nome de etiqueta, que é\n" -" um nome simbólico associado a um identificador de revisão. Nomes\n" -" de etiqueta não podem conter o caractere \":\".\n" +" um identificador único de revisão, chamado de identificador\n" +" curto. Um identificador curto é válido apenas se for o prefixo\n" +" de um identificador completo.\n" +"\n" +" Qualquer outra string é tratada como um nome de etiqueta ou\n" +" ramo. Um nome de etiqueta é um nome simbólico associado a um\n" +" identificador de revisão. Um nome de ramo denota a revisão mais\n" +" recente de tal ramo. Nomes de etiqueta ou de ramo não podem\n" +" conter o caractere \":\".\n" "\n" " O nome reservado \"tip\" é uma etiqueta especial que sempre\n" " identifica a revisão mais recente.\n" @@ -10076,13 +10074,19 @@ " - nonempty: Any text. Returns '(none)' if the string is empty.\n" " - hgdate: Date. Returns the date as a pair of numbers:\n" " \"1157407993 25200\" (Unix timestamp, timezone offset).\n" -" - isodate: Date. Returns the date in ISO 8601 format.\n" +" - isodate: Date. Returns the date in ISO 8601 format: \"2009-08-18\n" +" 13:00 +0200\".\n" +" - isodatesec: Date. Returns the date in ISO 8601 format, including\n" +" seconds: \"2009-08-18 13:00:13 +0200\". See also the\n" +" rfc3339date filter.\n" " - localdate: Date. Converts a date to local date.\n" " - obfuscate: Any text. Returns the input text rendered as a\n" " sequence of XML entities.\n" " - person: Any text. Returns the text before an email address.\n" " - rfc822date: Date. Returns a date using the same format used\n" -" in email headers.\n" +" in email headers: \"Tue, 18 Aug 2009 13:00:13 +0200\".\n" +" - rfc3339date: Date. Returns a date using the Internet date format\n" +" specified in RFC 3339: \"2009-08-18T13:00:13+02:00\".\n" " - short: Changeset hash. Returns the short form of a changeset\n" " hash, i.e. a 12-byte hexadecimal string.\n" " - shortdate: Date. Returns a date like \"2006-09-18\".\n" @@ -10186,14 +10190,17 @@ " - nonempty: Qualquer texto. Devolve (none) se o texto for vazio.\n" " - hgdate: Data. Devolve a data como um par de números:\n" " \"1157407993 25200\" (timestamp Unix, defasagem de fuso)\n" -" - isodate: Data. Devolve a data em formato ISO 8601.\n" +" - isodate: Data. Devolve a data em formato ISO 8601: \"2009-08-18\n" +" 13:00 +0200\".\n" " - localdate: Data. Converte para data local.\n" " - obfuscate: Qualquer texto. Devolve o texto de entrada\n" " renderizado como uma seqüência de entidades XML.\n" " - person: Qualquer texto. Devolve o texto antes de um endereço\n" " de e-mail.\n" -" - rfc822date: Data. Devolve uma data usando o mesmo formato\n" -" utilizado em cabeçalhos de e-mail.\n" +" - rfc822date: Data. Devolve uma data usando o mesmo formato utilizado\n" +" em cabeçalhos de e-mail: \"Tue, 18 Aug 2009 13:00:13 +0200\".\n" +" - rfc3339date: Data. Devolve uma data usando o formato de data da\n" +" Internet especificado na RFC 3339: \"2009-08-18T13:00:13+02:00\".\n" " - short: Hash do changeset. Devolve a forma curta do hash de\n" " um changeset, ou seja, uma string hexadecimal de 12 bytes.\n" " - shortdate: Data. Devolve uma data como \"2006-09-18\".\n"
--- a/mercurial/cmdutil.py Sat Oct 03 23:36:08 2009 +0200 +++ b/mercurial/cmdutil.py Sat Oct 03 23:38:10 2009 +0200 @@ -546,24 +546,26 @@ return errors -def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None): +def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None, + runargs=None): '''Run a command as a service.''' if opts['daemon'] and not opts['daemon_pipefds']: rfd, wfd = os.pipe() - args = sys.argv[:] - args.append('--daemon-pipefds=%d,%d' % (rfd, wfd)) + if not runargs: + runargs = sys.argv[:] + runargs.append('--daemon-pipefds=%d,%d' % (rfd, wfd)) # Don't pass --cwd to the child process, because we've already # changed directory. - for i in xrange(1,len(args)): - if args[i].startswith('--cwd='): - del args[i] + for i in xrange(1,len(runargs)): + if runargs[i].startswith('--cwd='): + del runargs[i] break - elif args[i].startswith('--cwd'): - del args[i:i+2] + elif runargs[i].startswith('--cwd'): + del runargs[i:i+2] break pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0), - args[0], args) + runargs[0], runargs) os.close(wfd) os.read(rfd, 1) if parentfn:
--- a/mercurial/commands.py Sat Oct 03 23:36:08 2009 +0200 +++ b/mercurial/commands.py Sat Oct 03 23:38:10 2009 +0200 @@ -1356,23 +1356,25 @@ With no arguments, show all repository head changesets. - Repository "heads" are changesets that don't have child - changesets. They are where development generally takes place and - are the usual targets for update and merge operations. + Repository "heads" are changesets with no child changesets. They are + where development generally takes place and are the usual targets + for update and merge operations. If one or more REV is given, the "branch heads" will be shown for - the named branch associated with that revision. The name of the - branch is called the revision's branch tag. - - Branch heads are revisions on a given named branch that do not have - any descendants on the same branch. A branch head could be a true head - or it could be the last changeset on a branch before a new branch - was created. If none of the branch heads are true heads, the branch - is considered inactive. If -c/--closed is specified, also show branch - heads marked closed (see hg commit --close-branch). - - If STARTREV is specified only those heads (or branch heads) that - are descendants of STARTREV will be displayed. + the named branch associated with the specified changeset(s). + + Branch heads are changesets on a named branch with no descendants on + the same branch. A branch head could be a "true" (repository) head, + or it could be the last changeset on that branch before it was + merged into another branch, or it could be the last changeset on the + branch before a new branch was created. If none of the branch heads + are true heads, the branch is considered inactive. + + If -c/--closed is specified, also show branch heads marked closed + (see hg commit --close-branch). + + If STARTREV is specified, only those heads that are descendants of + STARTREV will be displayed. """ if opts.get('rev'): start = repo.lookup(opts['rev'])
--- a/mercurial/dirstate.py Sat Oct 03 23:36:08 2009 +0200 +++ b/mercurial/dirstate.py Sat Oct 03 23:38:10 2009 +0200 @@ -38,6 +38,9 @@ class dirstate(object): def __init__(self, opener, ui, root): + '''Create a new dirstate object. opener is an open()-like callable + that can be used to open the dirstate file; root is the root of the + directory tracked by the dirstate.''' self._opener = opener self._root = root self._rootdir = os.path.join(root, '') @@ -47,6 +50,8 @@ @propertycache def _map(self): + '''Return the dirstate contents as a map from filename to + (state, mode, size, time).''' self._read() return self._map @@ -169,12 +174,14 @@ return path def __getitem__(self, key): - ''' current states: - n normal - m needs merging - r marked for removal - a marked for addition - ? not tracked''' + '''Return the current state of key (a filename) in the dirstate. + States are: + n normal + m needs merging + r marked for removal + a marked for addition + ? not tracked + ''' return self._map.get(key, ("?",))[0] def __contains__(self, key): @@ -373,13 +380,9 @@ return st = self._opener("dirstate", "w", atomictemp=True) - try: - gran = int(self._ui.config('dirstate', 'granularity', 1)) - except ValueError: - gran = 1 - if gran > 0: - hlimit = util.fstat(st).st_mtime - llimit = hlimit - gran + # use the modification time of the newly created temporary file as the + # filesystem's notion of 'now' + now = int(util.fstat(st).st_mtime) cs = cStringIO.StringIO() copymap = self._copymap @@ -389,9 +392,19 @@ for f, e in self._map.iteritems(): if f in copymap: f = "%s\0%s" % (f, copymap[f]) - if gran > 0 and e[0] == 'n' and llimit < e[3] <= hlimit: - # file was updated too recently, ignore stat data - e = (e[0], 0, -1, -1) + + if e[0] == 'n' and e[3] == now: + # The file was last modified "simultaneously" with the current + # write to dirstate (i.e. within the same second for file- + # systems with a granularity of 1 sec). This commonly happens + # for at least a couple of files on 'update'. + # The user could change the file without changing its size + # within the same second. Invalidate the file's stat data in + # dirstate, forcing future 'status' calls to compare the + # contents of the file. This prevents mistakenly treating such + # files as clean. + e = (e[0], 0, -1, -1) # mark entry as 'unset' + e = pack(_format, e[0], e[1], e[2], e[3], len(f)) write(e) write(f) @@ -411,11 +424,11 @@ def walk(self, match, unknown, ignored): ''' - walk recursively through the directory tree, finding all files - matched by the match function + Walk recursively through the directory tree, finding all files + matched by match. - results are yielded in a tuple (filename, stat), where stat - and st is the stat result if the file was found in the directory. + Return a dict mapping filename to stat-like object (either + mercurial.osutil.stat instance or return value of os.stat()). ''' def fwarn(f, msg): @@ -553,12 +566,38 @@ return results def status(self, match, ignored, clean, unknown): + '''Determine the status of the working copy relative to the + dirstate and return a tuple of lists (unsure, modified, added, + removed, deleted, unknown, ignored, clean), where: + + unsure: + files that might have been modified since the dirstate was + written, but need to be read to be sure (size is the same + but mtime differs) + modified: + files that have definitely been modified since the dirstate + was written (different size or mode) + added: + files that have been explicitly added with hg add + removed: + files that have been explicitly removed with hg remove + deleted: + files that have been deleted through other means ("missing") + unknown: + files not in the dirstate that are not ignored + ignored: + files not in the dirstate that are ignored + (by _dirignore()) + clean: + files that have definitely not been modified since the + dirstate was written + ''' listignored, listclean, listunknown = ignored, clean, unknown lookup, modified, added, unknown, ignored = [], [], [], [], [] removed, deleted, clean = [], [], [] dmap = self._map - ladd = lookup.append + ladd = lookup.append # aka "unsure" madd = modified.append aadd = added.append uadd = unknown.append
--- a/mercurial/posix.py Sat Oct 03 23:36:08 2009 +0200 +++ b/mercurial/posix.py Sat Oct 03 23:38:10 2009 +0200 @@ -165,17 +165,11 @@ return inst.errno != errno.ESRCH def explain_exit(code): - """return a 2-tuple (desc, code) describing a process's status""" - if os.WIFEXITED(code): - val = os.WEXITSTATUS(code) - return _("exited with status %d") % val, val - elif os.WIFSIGNALED(code): - val = os.WTERMSIG(code) - return _("killed by signal %d") % val, val - elif os.WIFSTOPPED(code): - val = os.WSTOPSIG(code) - return _("stopped by signal %d") % val, val - raise ValueError(_("invalid exit code")) + """return a 2-tuple (desc, code) describing a subprocess status + (codes from kill are negative - not os.system/wait encoding)""" + if code >= 0: + return _("exited with status %d") % code, code + return _("killed by signal %d") % -code, -code def isowner(st): """Return True if the stat object st is from the current user."""
--- a/mercurial/streamclone.py Sat Oct 03 23:36:08 2009 +0200 +++ b/mercurial/streamclone.py Sat Oct 03 23:38:10 2009 +0200 @@ -48,8 +48,7 @@ try: repo.ui.debug('scanning\n') for name, ename, size in repo.store.walk(): - # for backwards compat, name was partially encoded - entries.append((store.encodedir(name), size)) + entries.append((name, size)) total_bytes += size finally: lock.release() @@ -62,6 +61,7 @@ yield '%d %d\n' % (len(entries), total_bytes) for name, size in entries: repo.ui.debug('sending %s (%d bytes)\n' % (name, size)) - yield '%s\0%d\n' % (name, size) + # partially encode name over the wire for backwards compat + yield '%s\0%d\n' % (store.encodedir(name), size) for chunk in util.filechunkiter(repo.sopener(name), limit=size): yield chunk
--- a/mercurial/subrepo.py Sat Oct 03 23:36:08 2009 +0200 +++ b/mercurial/subrepo.py Sat Oct 03 23:38:10 2009 +0200 @@ -167,7 +167,7 @@ self._repo.ui.note(_('removing subrepo %s\n') % self._path) hg.clean(self._repo, node.nullid, False) - def get(self, state): + def _get(self, state): source, revision = state try: self._repo.lookup(revision) @@ -178,9 +178,13 @@ other = hg.repository(self._repo.ui, srcurl) self._repo.pull(other) + def get(self, state): + self._get(state) + source, revision = state hg.clean(self._repo, revision, False) def merge(self, state): + self._get(state) hg.merge(self._repo, state[1], remind=False) def push(self, force):
--- a/mercurial/util.py Sat Oct 03 23:36:08 2009 +0200 +++ b/mercurial/util.py Sat Oct 03 23:38:10 2009 +0200 @@ -357,41 +357,26 @@ if val is True: return '1' return str(val) - oldenv = {} - for k in environ: - oldenv[k] = os.environ.get(k) - if cwd is not None: - oldcwd = os.getcwd() origcmd = cmd if os.name == 'nt': cmd = '"%s"' % cmd - try: - for k, v in environ.iteritems(): - os.environ[k] = py2shell(v) - os.environ['HG'] = hgexecutable() - if cwd is not None and oldcwd != cwd: - os.chdir(cwd) - rc = os.system(cmd) - if sys.platform == 'OpenVMS' and rc & 1: - rc = 0 - if rc and onerr: - errmsg = '%s %s' % (os.path.basename(origcmd.split(None, 1)[0]), - explain_exit(rc)[0]) - if errprefix: - errmsg = '%s: %s' % (errprefix, errmsg) - try: - onerr.warn(errmsg + '\n') - except AttributeError: - raise onerr(errmsg) - return rc - finally: - for k, v in oldenv.iteritems(): - if v is None: - del os.environ[k] - else: - os.environ[k] = v - if cwd is not None and oldcwd != cwd: - os.chdir(oldcwd) + env = dict(os.environ) + env.update((k, py2shell(v)) for k, v in environ.iteritems()) + env['HG'] = hgexecutable() + rc = subprocess.call(cmd, shell=True, close_fds=closefds, + env=env, cwd=cwd) + if sys.platform == 'OpenVMS' and rc & 1: + rc = 0 + if rc and onerr: + errmsg = '%s %s' % (os.path.basename(origcmd.split(None, 1)[0]), + explain_exit(rc)[0]) + if errprefix: + errmsg = '%s: %s' % (errprefix, errmsg) + try: + onerr.warn(errmsg + '\n') + except AttributeError: + raise onerr(errmsg) + return rc def checksignature(func): '''wrap a function with code to check for calling errors''' @@ -1280,9 +1265,12 @@ padding = '\n' + ' ' * hangindent # To avoid corrupting multi-byte characters in line, we must wrap # a Unicode string instead of a bytestring. - u = line.decode(encoding.encoding) - w = padding.join(textwrap.wrap(u, width=width - hangindent)) - return w.encode(encoding.encoding) + try: + u = line.decode(encoding.encoding) + w = padding.join(textwrap.wrap(u, width=width - hangindent)) + return w.encode(encoding.encoding) + except UnicodeDecodeError: + return padding.join(textwrap.wrap(line, width=width - hangindent)) def iterlines(iterator): for chunk in iterator:
--- a/tests/test-http Sat Oct 03 23:36:08 2009 +0200 +++ b/tests/test-http Sat Oct 03 23:38:10 2009 +0200 @@ -5,6 +5,11 @@ hg init test cd test echo foo>foo +mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg +echo foo>foo.d/foo +echo bar>foo.d/bAr.hg.d/BaR +echo bar>foo.d/baR.d.hg/bAR + hg commit -A -m 1 hg --config server.uncompressed=True serve -p $HGPORT -d --pid-file=../hg1.pid hg serve -p $HGPORT1 -d --pid-file=../hg2.pid
--- a/tests/test-http.out Sat Oct 03 23:36:08 2009 +0200 +++ b/tests/test-http.out Sat Oct 03 23:38:10 2009 +0200 @@ -1,4 +1,7 @@ adding foo +adding foo.d/bAr.hg.d/BaR +adding foo.d/baR.d.hg/bAR +adding foo.d/foo abort: cannot start server at ':20060': % clone via stream streaming all changes @@ -10,31 +13,31 @@ checking manifests crosschecking files in changesets and manifests checking files -1 files, 1 changesets, 1 total revisions +4 files, 1 changesets, 4 total revisions % try to clone via stream, should use pull instead requesting all changes adding changesets adding manifests adding file changes -added 1 changesets with 1 changes to 1 files +added 1 changesets with 4 changes to 4 files updating working directory -1 files updated, 0 files merged, 0 files removed, 0 files unresolved +4 files updated, 0 files merged, 0 files removed, 0 files unresolved % clone via pull requesting all changes adding changesets adding manifests adding file changes -added 1 changesets with 1 changes to 1 files +added 1 changesets with 4 changes to 4 files updating working directory -1 files updated, 0 files merged, 0 files removed, 0 files unresolved +4 files updated, 0 files merged, 0 files removed, 0 files unresolved checking changesets checking manifests crosschecking files in changesets and manifests checking files -1 files, 1 changesets, 1 total revisions +4 files, 1 changesets, 4 total revisions adding bar % pull -changegroup hook: HG_NODE=cfbd11a1fa315300a080c3de8fe36b0fc5820acf HG_SOURCE=pull HG_URL=http://localhost/ +changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_URL=http://localhost/ pulling from http://localhost/ searching for changes adding changesets
--- a/tests/test-inotify-issue1208.out Sat Oct 03 23:36:08 2009 +0200 +++ b/tests/test-inotify-issue1208.out Sat Oct 03 23:38:10 2009 +0200 @@ -1,5 +1,5 @@ % fail -could not talk to new inotify server: No such file or directory +abort: could not start server: File exists abort: could not start server: File exists % inserve % status
--- a/tests/test-keyword Sat Oct 03 23:36:08 2009 +0200 +++ b/tests/test-keyword Sat Oct 03 23:38:10 2009 +0200 @@ -48,6 +48,11 @@ echo % cat cat a b +echo % no kwfiles +hg kwfiles +echo % untracked candidates +hg -v kwfiles --unknown + echo % addremove hg addremove echo % status @@ -162,6 +167,10 @@ echo % kwfiles hg kwfiles +echo % ignored files +hg -v kwfiles --ignore +echo % all files +hg kwfiles --all echo % diff --rev hg diff --rev 1 | grep -v 'b/c'
--- a/tests/test-keyword.out Sat Oct 03 23:36:08 2009 +0200 +++ b/tests/test-keyword.out Sat Oct 03 23:38:10 2009 +0200 @@ -42,6 +42,9 @@ do not process $Id: xxx $ ignore $Id$ +% no kwfiles +% untracked candidates +k a % addremove adding a adding b @@ -181,6 +184,14 @@ % kwfiles a c +% ignored files +I b +I sym +% all files +K a +K c +I b +I sym % diff --rev diff -r ef63ca68695b c --- /dev/null Thu Jan 01 00:00:00 1970 +0000
--- a/tests/test-notify.out Sat Oct 03 23:36:08 2009 +0200 +++ b/tests/test-notify.out Sat Oct 03 23:38:10 2009 +0200 @@ -35,6 +35,7 @@ diffstat = True # add a diffstat before the diff content sources = serve # notify if source of incoming changes in this list # (serve == ssh or http, push, pull, bundle) + merge = False # send notification for merges (default True) [email] from = user@host.com # email address to send as if none given [web]