# HG changeset patch # User Dirkjan Ochtman # Date 1231748025 -3600 # Node ID e9da3de01e0a1641bd495ce82dc149efa63a88d6 # Parent 6c89dd0a7797ae745eae566af2cbe3a5809f9535# Parent f9fcb189c8e22454bb49a8dcb0b1112404d03ca9 merge with crew-stable diff -r f9fcb189c8e2 -r e9da3de01e0a contrib/zsh_completion --- a/contrib/zsh_completion Mon Jan 12 09:12:35 2009 +0100 +++ b/contrib/zsh_completion Mon Jan 12 09:13:45 2009 +0100 @@ -4,14 +4,13 @@ # it into your zsh function path (/usr/share/zsh/site-functions for # instance) # -# Copyright (C) 2005 Steve Borho +# Copyright (C) 2005-6 Steve Borho # Copyright (C) 2006-8 Brendan Cully # # This is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free # Software Foundation; either version 2 of the License, or (at your # option) any later version. -# emulate -LR zsh setopt extendedglob @@ -118,27 +117,17 @@ typeset -ga _hg_cmd_list typeset -gA _hg_alias_list local hline cmd cmdalias - _call_program help hg --verbose help | while read -A hline + + _call_program hg hg debugcomplete -v 2>/dev/null | while read -A hline do - cmd="$hline[1]" - case $cmd in - *:) - cmd=${cmd%:} - _hg_cmd_list+=($cmd) - ;; - *,) - cmd=${cmd%,} - _hg_cmd_list+=($cmd) - integer i=2 - while (( i <= $#hline )) - do - cmdalias=${hline[$i]%(:|,)} - _hg_cmd_list+=($cmdalias) - _hg_alias_list+=($cmdalias $cmd) - (( i++ )) - done - ;; - esac + cmd=$hline[1] + _hg_cmd_list+=($cmd) + + for cmdalias in $hline[2,-1] + do + _hg_cmd_list+=($cmdalias) + _hg_alias_list+=($cmdalias $cmd) + done done } diff -r f9fcb189c8e2 -r e9da3de01e0a hgext/bookmarks.py --- a/hgext/bookmarks.py Mon Jan 12 09:12:35 2009 +0100 +++ b/hgext/bookmarks.py Mon Jan 12 09:13:45 2009 +0100 @@ -14,9 +14,19 @@ It is possible to use bookmark names in every revision lookup (e.g. hg merge, hg update). + +The bookmark extension offers the possiblity to have a more git-like experience +by adding the following configuration option to your .hgrc: + +[bookmarks] +track.current = True + +This will cause bookmarks to track the bookmark that you are currently on, and +just updates it. This is similar to git's approach of branching. ''' from mercurial.commands import templateopts, hex, short +from mercurial import extensions from mercurial.i18n import _ from mercurial import cmdutil, util, commands, changelog from mercurial.node import nullid, nullrev @@ -54,11 +64,54 @@ ''' if os.path.exists(repo.join('bookmarks')): util.copyfile(repo.join('bookmarks'), repo.join('undo.bookmarks')) + if current(repo) not in refs: + setcurrent(repo, None) file = repo.opener('bookmarks', 'w+') for refspec, node in refs.items(): file.write("%s %s\n" % (hex(node), refspec)) file.close() +def current(repo): + '''Get the current bookmark + + If we use gittishsh branches we have a current bookmark that + we are on. This function returns the name of the bookmark. It + is stored in .hg/bookmarks.current + ''' + if repo._bookmarkcurrent: + return repo._bookmarkcurrent + mark = None + if os.path.exists(repo.join('bookmarks.current')): + file = repo.opener('bookmarks.current') + mark = file.readline() + if mark == '': + mark = None + file.close() + repo._bookmarkcurrent = mark + return mark + +def setcurrent(repo, mark): + '''Set the name of the bookmark that we are currently on + + Set the name of the bookmark that we are on (hg update ). + The name is recoreded in .hg/bookmarks.current + ''' + if current(repo) == mark: + return + + refs = parse(repo) + + # do not update if we do update to a rev equal to the current bookmark + if (mark not in refs and + current(repo) and refs[current(repo)] == repo.changectx('.').node()): + return + if mark not in refs: + mark = '' + file = repo.opener('bookmarks.current', 'w+') + file.write(mark) + file.close() + repo._bookmarkcurrent = mark + def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False, rename=None): '''mercurial bookmarks @@ -85,6 +138,8 @@ raise util.Abort(_("new bookmark name required")) marks[mark] = marks[rename] del marks[rename] + if current(repo) == rename: + setcurrent(repo, mark) write(repo, marks) return @@ -121,7 +176,11 @@ ui.status("no bookmarks set\n") else: for bmark, n in marks.iteritems(): - prefix = (n == cur) and '*' or ' ' + if ui.configbool('bookmarks', 'track.current'): + prefix = (bmark == current(repo) and n == cur) and '*' or ' ' + else: + prefix = (n == cur) and '*' or ' ' + ui.write(" %s %-25s %d:%s\n" % ( prefix, bmark, repo.changelog.rev(n), hexfn(n))) return @@ -166,6 +225,7 @@ # init a bookmark cache as otherwise we would get a infinite reading # in lookup() repo._bookmarks = None + repo._bookmarkcurrent = None class bookmark_repo(repo.__class__): def rollback(self): @@ -192,9 +252,14 @@ marks = parse(repo) update = False for mark, n in marks.items(): - if n in parents: - marks[mark] = node - update = True + if ui.configbool('bookmarks', 'track.current'): + if mark == current(repo) and n in parents: + marks[mark] = node + update = True + else: + if n in parents: + marks[mark] = node + update = True if update: write(repo, marks) return node @@ -218,8 +283,35 @@ write(repo, marks) return result + def tags(self): + """Merge bookmarks with normal tags""" + if self.tagscache: + return self.tagscache + + tagscache = super(bookmark_repo, self).tags() + tagscache.update(parse(repo)) + return tagscache + repo.__class__ = bookmark_repo +def updatecurbookmark(orig, ui, repo, *args, **opts): + '''Set the current bookmark + + If the user updates to a bookmark we update the .hg/bookmarks.current + file. + ''' + res = orig(ui, repo, *args, **opts) + rev = opts['rev'] + if not rev and len(args) > 0: + rev = args[0] + setcurrent(repo, rev) + return res + +def uisetup(ui): + 'Replace push with a decorator to provide --non-bookmarked option' + if ui.configbool('bookmarks', 'track.current'): + extensions.wrapcommand(commands.table, 'update', updatecurbookmark) + cmdtable = { "bookmarks": (bookmark, diff -r f9fcb189c8e2 -r e9da3de01e0a hgext/bugzilla.py --- a/hgext/bugzilla.py Mon Jan 12 09:12:35 2009 +0100 +++ b/hgext/bugzilla.py Mon Jan 12 09:13:45 2009 +0100 @@ -4,53 +4,111 @@ # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. -# -# hook extension to update comments of bugzilla bugs when changesets -# that refer to bugs by id are seen. this hook does not change bug -# status, only comments. -# -# to configure, add items to '[bugzilla]' section of hgrc. -# -# to use, configure bugzilla extension and enable like this: -# -# [extensions] -# hgext.bugzilla = -# -# [hooks] -# # run bugzilla hook on every change pulled or pushed in here -# incoming.bugzilla = python:hgext.bugzilla.hook -# -# config items: -# -# section name is 'bugzilla'. -# [bugzilla] -# -# REQUIRED: -# host = bugzilla # mysql server where bugzilla database lives -# password = ** # user's password -# version = 2.16 # version of bugzilla installed -# -# OPTIONAL: -# bzuser = ... # fallback bugzilla user name to record comments with -# db = bugs # database to connect to -# notify = ... # command to run to get bugzilla to send mail -# regexp = ... # regexp to match bug ids (must contain one "()" group) -# strip = 0 # number of slashes to strip for url paths -# style = ... # style file to use when formatting comments -# template = ... # template to use when formatting comments -# timeout = 5 # database connection timeout (seconds) -# user = bugs # user to connect to database as -# [web] -# baseurl = http://hgserver/... # root of hg web site for browsing commits -# -# if hg committer names are not same as bugzilla user names, use -# "usermap" feature to map from committer email to bugzilla user name. -# usermap can be in hgrc or separate config file. -# -# [bugzilla] -# usermap = filename # cfg file with "committer"="bugzilla user" info -# [usermap] -# committer_email = bugzilla_user_name + +'''Bugzilla integration + +This hook extension adds comments on bugs in Bugzilla when changesets +that refer to bugs by Bugzilla ID are seen. The hook does not change bug +status. + +The hook updates the Bugzilla database directly. Only Bugzilla installations +using MySQL are supported. + +The hook relies on a Bugzilla script to send bug change notification emails. +That script changes between Bugzilla versions; the 'processmail' script used +prior to 2.18 is replaced in 2.18 and subsequent versions by +'config/sendbugmail.pl'. Note that these will be run by Mercurial as the user +pushing the change; you will need to ensure the Bugzilla install file +permissions are set appropriately. + +Configuring the extension: + + [bugzilla] + host Hostname of the MySQL server holding the Bugzilla database. + db Name of the Bugzilla database in MySQL. Default 'bugs'. + user Username to use to access MySQL server. Default 'bugs'. + password Password to use to access MySQL server. + timeout Database connection timeout (seconds). Default 5. + version Bugzilla version. Specify '3.0' for Bugzilla versions 3.0 and + later, '2.18' for Bugzilla versions from 2.18 and '2.16' for + versions prior to 2.18. + bzuser Fallback Bugzilla user name to record comments with, if + changeset committer cannot be found as a Bugzilla user. + bzdir Bugzilla install directory. Used by default notify. + Default '/var/www/html/bugzilla'. + notify The command to run to get Bugzilla to send bug change + notification emails. Substitutes from a map with 3 keys, + 'bzdir', 'id' (bug id) and 'user' (committer bugzilla email). + Default depends on version; from 2.18 it is + "cd %(bzdir)s && perl -T contrib/sendbugmail.pl %(id)s %(user)s". + regexp Regular expression to match bug IDs in changeset commit message. + Must contain one "()" group. The default expression matches + 'Bug 1234', 'Bug no. 1234', 'Bug number 1234', + 'Bugs 1234,5678', 'Bug 1234 and 5678' and variations thereof. + Matching is case insensitive. + style The style file to use when formatting comments. + template Template to use when formatting comments. Overrides + style if specified. In addition to the usual Mercurial + keywords, the extension specifies: + {bug} The Bugzilla bug ID. + {root} The full pathname of the Mercurial repository. + {webroot} Stripped pathname of the Mercurial repository. + {hgweb} Base URL for browsing Mercurial repositories. + Default 'changeset {node|short} in repo {root} refers ' + 'to bug {bug}.\\ndetails:\\n\\t{desc|tabindent}' + strip The number of slashes to strip from the front of {root} + to produce {webroot}. Default 0. + usermap Path of file containing Mercurial committer ID to Bugzilla user + ID mappings. If specified, the file should contain one mapping + per line, "committer"="Bugzilla user". See also the + [usermap] section. + + [usermap] + Any entries in this section specify mappings of Mercurial committer ID + to Bugzilla user ID. See also [bugzilla].usermap. + "committer"="Bugzilla user" + + [web] + baseurl Base URL for browsing Mercurial repositories. Reference from + templates as {hgweb}. + +Activating the extension: + + [extensions] + hgext.bugzilla = + + [hooks] + # run bugzilla hook on every change pulled or pushed in here + incoming.bugzilla = python:hgext.bugzilla.hook + +Example configuration: + +This example configuration is for a collection of Mercurial repositories +in /var/local/hg/repos/ used with a local Bugzilla 3.2 installation in +/opt/bugzilla-3.2. + + [bugzilla] + host=localhost + password=XYZZY + version=3.0 + bzuser=unknown@domain.com + bzdir=/opt/bugzilla-3.2 + template=Changeset {node|short} in {root|basename}.\\n{hgweb}/{webroot}/rev/{node|short}\\n\\n{desc}\\n + strip=5 + + [web] + baseurl=http://dev.domain.com/hg + + [usermap] + user@emaildomain.com=user.name@bugzilladomain.com + +Commits add a comment to the Bugzilla bug record of the form: + + Changeset 3b16791d6642 in repository-name. + http://dev.domain.com/hg/repository-name/rev/3b16791d6642 + + Changeset commit comment. Bug 1234. +''' from mercurial.i18n import _ from mercurial.node import short @@ -82,6 +140,7 @@ self.cursor = self.conn.cursor() self.longdesc_id = self.get_longdesc_id() self.user_ids = {} + self.default_notify = "cd %(bzdir)s && ./processmail %(id)s %(user)s" def run(self, *args, **kwargs): '''run a query.''' @@ -118,15 +177,23 @@ unknown.pop(id, None) return util.sort(unknown.keys()) - def notify(self, ids): + def notify(self, ids, committer): '''tell bugzilla to send mail.''' self.ui.status(_('telling bugzilla to send mail:\n')) + (user, userid) = self.get_bugzilla_user(committer) for id in ids: self.ui.status(_(' bug %s\n') % id) - cmd = self.ui.config('bugzilla', 'notify', - 'cd /var/www/html/bugzilla && ' - './processmail %s nobody@nowhere.com') % id + cmdfmt = self.ui.config('bugzilla', 'notify', self.default_notify) + bzdir = self.ui.config('bugzilla', 'bzdir', '/var/www/html/bugzilla') + try: + # Backwards-compatible with old notify string, which + # took one string. This will throw with a new format + # string. + cmd = cmdfmt % id + except TypeError: + cmd = cmdfmt % {'bzdir': bzdir, 'id': id, 'user': user} + self.ui.note(_('running notify command %s\n') % cmd) fp = util.popen('(%s) 2>&1' % cmd) out = fp.read() ret = fp.close() @@ -161,9 +228,10 @@ return bzuser return user - def add_comment(self, bugid, text, committer): - '''add comment to bug. try adding comment as committer of - changeset, otherwise as default bugzilla user.''' + def get_bugzilla_user(self, committer): + '''see if committer is a registered bugzilla user. Return + bugzilla username and userid if so. If not, return default + bugzilla username and userid.''' user = self.map_committer(committer) try: userid = self.get_user_id(user) @@ -174,9 +242,16 @@ raise util.Abort(_('cannot find bugzilla user id for %s') % user) userid = self.get_user_id(defaultuser) + user = defaultuser except KeyError: raise util.Abort(_('cannot find bugzilla user id for %s or %s') % (user, defaultuser)) + return (user, userid) + + def add_comment(self, bugid, text, committer): + '''add comment to bug. try adding comment as committer of + changeset, otherwise as default bugzilla user.''' + (user, userid) = self.get_bugzilla_user(committer) now = time.strftime('%Y-%m-%d %H:%M:%S') self.run('''insert into longdescs (bug_id, who, bug_when, thetext) @@ -185,12 +260,20 @@ self.run('''insert into bugs_activity (bug_id, who, bug_when, fieldid) values (%s, %s, %s, %s)''', (bugid, userid, now, self.longdesc_id)) + self.conn.commit() -class bugzilla_3_0(bugzilla_2_16): +class bugzilla_2_18(bugzilla_2_16): + '''support for bugzilla 2.18 series.''' + + def __init__(self, ui): + bugzilla_2_16.__init__(self, ui) + self.default_notify = "cd %(bzdir)s && perl -T contrib/sendbugmail.pl %(id)s %(user)s" + +class bugzilla_3_0(bugzilla_2_18): '''support for bugzilla 3.0 series.''' def __init__(self, ui): - bugzilla_2_16.__init__(self, ui) + bugzilla_2_18.__init__(self, ui) def get_longdesc_id(self): '''get identity of longdesc field''' @@ -205,6 +288,7 @@ # different schemas. _versions = { '2.16': bugzilla_2_16, + '2.18': bugzilla_2_18, '3.0': bugzilla_3_0 } @@ -320,7 +404,7 @@ if ids: for id in ids: bz.update(id, ctx) - bz.notify(ids) + bz.notify(ids, util.email(ctx.user())) except MySQLdb.MySQLError, err: raise util.Abort(_('database error: %s') % err[1]) diff -r f9fcb189c8e2 -r e9da3de01e0a hgext/churn.py --- a/hgext/churn.py Mon Jan 12 09:12:35 2009 +0100 +++ b/hgext/churn.py Mon Jan 12 09:13:45 2009 +0100 @@ -12,27 +12,6 @@ import os, sys import time, datetime -def get_tty_width(): - if 'COLUMNS' in os.environ: - try: - return int(os.environ['COLUMNS']) - except ValueError: - pass - try: - import termios, array, fcntl - for dev in (sys.stdout, sys.stdin): - try: - fd = dev.fileno() - if not os.isatty(fd): - continue - arri = fcntl.ioctl(fd, termios.TIOCGWINSZ, '\0' * 8) - return array.array('h', arri)[1] - except ValueError: - pass - except ImportError: - pass - return 80 - def maketemplater(ui, repo, tmpl): tmpl = templater.parsestring(tmpl, quoted=False) try: @@ -111,7 +90,7 @@ def churn(ui, repo, *pats, **opts): - '''Graph count of revisions grouped by template + '''graph count of revisions grouped by template Will graph count of changed lines or revisions grouped by template or alternatively by date, if dateformat is used. In this case it will override @@ -157,7 +136,7 @@ maxcount = float(max([v for k, v in rate])) maxname = max([len(k) for k, v in rate]) - ttywidth = get_tty_width() + ttywidth = util.termwidth() ui.debug(_("assuming %i character terminal\n") % ttywidth) width = ttywidth - maxname - 2 - 6 - 2 - 2 diff -r f9fcb189c8e2 -r e9da3de01e0a hgext/color.py --- a/hgext/color.py Mon Jan 12 09:12:35 2009 +0100 +++ b/hgext/color.py Mon Jan 12 09:13:45 2009 +0100 @@ -204,6 +204,7 @@ _diff_prefixes = [('diff', 'diffline'), ('copy', 'extended'), ('rename', 'extended'), + ('old', 'extended'), ('new', 'extended'), ('deleted', 'extended'), ('---', 'file_a'), diff -r f9fcb189c8e2 -r e9da3de01e0a hgext/convert/__init__.py --- a/hgext/convert/__init__.py Mon Jan 12 09:12:35 2009 +0100 +++ b/hgext/convert/__init__.py Mon Jan 12 09:13:45 2009 +0100 @@ -7,13 +7,14 @@ '''converting foreign VCS repositories to Mercurial''' import convcmd +import cvsps from mercurial import commands from mercurial.i18n import _ # Commands definition was moved elsewhere to ease demandload job. def convert(ui, src, dest=None, revmapfile=None, **opts): - """Convert a foreign SCM repository to a Mercurial one. + """convert a foreign SCM repository to a Mercurial one. Accepted source formats [identifiers]: - Mercurial [hg] @@ -183,7 +184,18 @@ def debugsvnlog(ui, **opts): return convcmd.debugsvnlog(ui, **opts) -commands.norepo += " convert debugsvnlog" +def debugcvsps(ui, *args, **opts): + '''create changeset information from CVS + + This command is intended as a debugging tool for the CVS to Mercurial + converter, and can be used as a direct replacement for cvsps. + + Hg debugcvsps reads the CVS rlog for current directory (or any named + directory) in the CVS repository, and converts the log to a series of + changesets based on matching commit log entries and dates.''' + return cvsps.debugcvsps(ui, *args, **opts) + +commands.norepo += " convert debugsvnlog debugcvsps" cmdtable = { "convert": @@ -200,4 +212,22 @@ (debugsvnlog, [], 'hg debugsvnlog'), + "debugcvsps": + (debugcvsps, + [ + # Main options shared with cvsps-2.1 + ('b', 'branches', [], _('only return changes on specified branches')), + ('p', 'prefix', '', _('prefix to remove from file names')), + ('r', 'revisions', [], _('only return changes after or between specified tags')), + ('u', 'update-cache', None, _("update cvs log cache")), + ('x', 'new-cache', None, _("create new cvs log cache")), + ('z', 'fuzz', 60, _('set commit time fuzz in seconds')), + ('', 'root', '', _('specify cvsroot')), + # Options specific to builtin cvsps + ('', 'parents', '', _('show parent changesets')), + ('', 'ancestors', '', _('show current changeset in ancestor branches')), + # Options that are ignored for compatibility with cvsps-2.1 + ('A', 'cvs-direct', None, 'ignored for compatibility'), + ], + 'hg debugcvsps [OPTION]... [PATH]...'), } diff -r f9fcb189c8e2 -r e9da3de01e0a hgext/convert/common.py --- a/hgext/convert/common.py Mon Jan 12 09:12:35 2009 +0100 +++ b/hgext/convert/common.py Mon Jan 12 09:13:45 2009 +0100 @@ -228,7 +228,9 @@ except TypeError: pass cmdline = [util.shellquote(arg) for arg in cmdline] - cmdline += ['2>', util.nulldev, '<', util.nulldev] + if not self.ui.debugflag: + cmdline += ['2>', util.nulldev] + cmdline += ['<', util.nulldev] cmdline = ' '.join(cmdline) return cmdline diff -r f9fcb189c8e2 -r e9da3de01e0a hgext/convert/convcmd.py --- a/hgext/convert/convcmd.py Mon Jan 12 09:12:35 2009 +0100 +++ b/hgext/convert/convcmd.py Mon Jan 12 09:13:45 2009 +0100 @@ -206,7 +206,7 @@ _('Overriding mapping for author %s, was %s, will be %s\n') % (srcauthor, self.authors[srcauthor], dstauthor)) else: - self.ui.debug(_('Mapping author %s to %s\n') + self.ui.debug(_('mapping author %s to %s\n') % (srcauthor, dstauthor)) self.authors[srcauthor] = dstauthor except IndexError: diff -r f9fcb189c8e2 -r e9da3de01e0a hgext/convert/cvs.py --- a/hgext/convert/cvs.py Mon Jan 12 09:12:35 2009 +0100 +++ b/hgext/convert/cvs.py Mon Jan 12 09:13:45 2009 +0100 @@ -144,11 +144,11 @@ if branch == "HEAD": branch = "" if branch: - latest = None + latest = 0 # the last changeset that contains a base # file is our parent for r in oldrevs: - latest = max(filerevids.get(r, None), latest) + latest = max(filerevids.get(r, 0), latest) if latest: p = [latest] diff -r f9fcb189c8e2 -r e9da3de01e0a hgext/convert/cvsps --- a/hgext/convert/cvsps Mon Jan 12 09:12:35 2009 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,154 +0,0 @@ -#!/usr/bin/env python -# -# Commandline front-end for cvsps.py -# -# Copyright 2008, Frank Kingswood -# -# This software may be used and distributed according to the terms -# of the GNU General Public License, incorporated herein by reference. - -import sys -from mercurial import util -from mercurial.i18n import _ -from optparse import OptionParser, SUPPRESS_HELP -from hgext.convert.cvsps import createlog, createchangeset, logerror - -def main(): - '''Main program to mimic cvsps.''' - - op = OptionParser(usage='%prog [-bpruvxz] path', - description='Read CVS rlog for current directory or named ' - 'path in repository, and convert the log to changesets ' - 'based on matching commit log entries and dates.') - - # Options that are ignored for compatibility with cvsps-2.1 - op.add_option('-A', dest='Ignore', action='store_true', help=SUPPRESS_HELP) - op.add_option('--cvs-direct', dest='Ignore', action='store_true', help=SUPPRESS_HELP) - op.add_option('-q', dest='Ignore', action='store_true', help=SUPPRESS_HELP) - - # Main options shared with cvsps-2.1 - op.add_option('-b', dest='Branches', action='append', default=[], - help='Only return changes on specified branches') - op.add_option('-p', dest='Prefix', action='store', default='', - help='Prefix to remove from file names') - op.add_option('-r', dest='Revisions', action='append', default=[], - help='Only return changes after or between specified tags') - op.add_option('-u', dest='Cache', action='store_const', const='update', - help="Update cvs log cache") - op.add_option('-v', dest='Verbose', action='count', default=0, - help='Be verbose') - op.add_option('-x', dest='Cache', action='store_const', const='write', - help="Create new cvs log cache") - op.add_option('-z', dest='Fuzz', action='store', type='int', default=60, - help='Set commit time fuzz', metavar='seconds') - op.add_option('--root', dest='Root', action='store', default='', - help='Specify cvsroot', metavar='cvsroot') - - # Options specific to this version - op.add_option('--parents', dest='Parents', action='store_true', - help='Show parent changesets') - op.add_option('--ancestors', dest='Ancestors', action='store_true', - help='Show current changeset in ancestor branches') - - options, args = op.parse_args() - - # Create a ui object for printing progress messages - class UI: - def __init__(self, verbose): - if verbose: - self.status = self.message - if verbose>1: - self.note = self.message - if verbose>2: - self.debug = self.message - def message(self, msg): - sys.stderr.write(msg) - def nomessage(self, msg): - pass - status = nomessage - note = nomessage - debug = nomessage - ui = UI(options.Verbose) - - try: - if args: - log = [] - for d in args: - log += createlog(ui, d, root=options.Root, cache=options.Cache) - else: - log = createlog(ui, root=options.Root, cache=options.Cache) - except logerror, e: - print e - return - - changesets = createchangeset(ui, log, options.Fuzz) - del log - - # Print changesets (optionally filtered) - - off = len(options.Revisions) - branches = {} # latest version number in each branch - ancestors = {} # parent branch - for cs in changesets: - - if options.Ancestors: - if cs.branch not in branches and cs.parents and cs.parents[0].id: - ancestors[cs.branch] = changesets[cs.parents[0].id-1].branch, cs.parents[0].id - branches[cs.branch] = cs.id - - # limit by branches - if options.Branches and (cs.branch or 'HEAD') not in options.Branches: - continue - - if not off: - # Note: trailing spaces on several lines here are needed to have - # bug-for-bug compatibility with cvsps. - print '---------------------' - print 'PatchSet %d ' % cs.id - print 'Date: %s' % util.datestr(cs.date, '%Y/%m/%d %H:%M:%S %1%2') - print 'Author: %s' % cs.author - print 'Branch: %s' % (cs.branch or 'HEAD') - print 'Tag%s: %s ' % (['', 's'][len(cs.tags)>1], - ','.join(cs.tags) or '(none)') - if options.Parents and cs.parents: - if len(cs.parents)>1: - print 'Parents: %s' % (','.join([str(p.id) for p in cs.parents])) - else: - print 'Parent: %d' % cs.parents[0].id - - if options.Ancestors: - b = cs.branch - r = [] - while b: - b, c = ancestors[b] - r.append('%s:%d:%d' % (b or "HEAD", c, branches[b])) - if r: - print 'Ancestors: %s' % (','.join(r)) - - print 'Log:' - print cs.comment - print - print 'Members: ' - for f in cs.entries: - fn = f.file - if fn.startswith(options.Prefix): - fn = fn[len(options.Prefix):] - print '\t%s:%s->%s%s ' % (fn, '.'.join([str(x) for x in f.parent]) or 'INITIAL', - '.'.join([str(x) for x in f.revision]), ['', '(DEAD)'][f.dead]) - print - - # have we seen the start tag? - if options.Revisions and off: - if options.Revisions[0] == str(cs.id) or \ - options.Revisions[0] in cs.tags: - off = False - - # see if we reached the end tag - if len(options.Revisions)>1 and not off: - if options.Revisions[1] == str(cs.id) or \ - options.Revisions[1] in cs.tags: - break - - -if __name__ == '__main__': - main() diff -r f9fcb189c8e2 -r e9da3de01e0a hgext/convert/cvsps.py --- a/hgext/convert/cvsps.py Mon Jan 12 09:12:35 2009 +0100 +++ b/hgext/convert/cvsps.py Mon Jan 12 09:13:45 2009 +0100 @@ -191,7 +191,13 @@ ui.note(_("running %s\n") % (' '.join(cmd))) ui.debug(_("prefix=%r directory=%r root=%r\n") % (prefix, directory, root)) - for line in util.popen(' '.join(cmd)): + pfp = util.popen(' '.join(cmd)) + peek = pfp.readline() + while True: + line = peek + if line == '': + break + peek = pfp.readline() if line.endswith('\n'): line = line[:-1] #ui.debug('state=%d line=%r\n' % (state, line)) @@ -263,7 +269,7 @@ if re_31.match(line): state = 5 else: - assert not re_32.match(line), _('Must have at least some revisions') + assert not re_32.match(line), _('must have at least some revisions') elif state == 5: # expecting revision number and possibly (ignored) lock indication @@ -312,7 +318,7 @@ e.branches = [tuple([int(y) for y in x.strip().split('.')]) for x in m.group(1).split(';')] state = 8 - elif re_31.match(line): + elif re_31.match(line) and re_50.match(peek): state = 5 store = True elif re_32.match(line): @@ -584,3 +590,95 @@ ui.status(_('%d changeset entries\n') % len(changesets)) return changesets + + +def debugcvsps(ui, *args, **opts): + '''Read CVS rlog for current directory or named path in repository, and + convert the log to changesets based on matching commit log entries and dates.''' + + if opts["new_cache"]: + cache = "write" + elif opts["update_cache"]: + cache = "update" + else: + cache = None + + revisions = opts["revisions"] + + try: + if args: + log = [] + for d in args: + log += createlog(ui, d, root=opts["root"], cache=cache) + else: + log = createlog(ui, root=opts["root"], cache=cache) + except logerror, e: + ui.write("%r\n"%e) + return + + changesets = createchangeset(ui, log, opts["fuzz"]) + del log + + # Print changesets (optionally filtered) + + off = len(revisions) + branches = {} # latest version number in each branch + ancestors = {} # parent branch + for cs in changesets: + + if opts["ancestors"]: + if cs.branch not in branches and cs.parents and cs.parents[0].id: + ancestors[cs.branch] = changesets[cs.parents[0].id-1].branch, cs.parents[0].id + branches[cs.branch] = cs.id + + # limit by branches + if opts["branches"] and (cs.branch or 'HEAD') not in opts["branches"]: + continue + + if not off: + # Note: trailing spaces on several lines here are needed to have + # bug-for-bug compatibility with cvsps. + ui.write('---------------------\n') + ui.write('PatchSet %d \n' % cs.id) + ui.write('Date: %s\n' % util.datestr(cs.date, '%Y/%m/%d %H:%M:%S %1%2')) + ui.write('Author: %s\n' % cs.author) + ui.write('Branch: %s\n' % (cs.branch or 'HEAD')) + ui.write('Tag%s: %s \n' % (['', 's'][len(cs.tags)>1], + ','.join(cs.tags) or '(none)')) + if opts["parents"] and cs.parents: + if len(cs.parents)>1: + ui.write('Parents: %s\n' % (','.join([str(p.id) for p in cs.parents]))) + else: + ui.write('Parent: %d\n' % cs.parents[0].id) + + if opts["ancestors"]: + b = cs.branch + r = [] + while b: + b, c = ancestors[b] + r.append('%s:%d:%d' % (b or "HEAD", c, branches[b])) + if r: + ui.write('Ancestors: %s\n' % (','.join(r))) + + ui.write('Log:\n') + ui.write('%s\n\n' % cs.comment) + ui.write('Members: \n') + for f in cs.entries: + fn = f.file + if fn.startswith(opts["prefix"]): + fn = fn[len(opts["prefix"]):] + ui.write('\t%s:%s->%s%s \n' % (fn, '.'.join([str(x) for x in f.parent]) or 'INITIAL', + '.'.join([str(x) for x in f.revision]), ['', '(DEAD)'][f.dead])) + ui.write('\n') + + # have we seen the start tag? + if revisions and off: + if revisions[0] == str(cs.id) or \ + revisions[0] in cs.tags: + off = False + + # see if we reached the end tag + if len(revisions)>1 and not off: + if revisions[1] == str(cs.id) or \ + revisions[1] in cs.tags: + break diff -r f9fcb189c8e2 -r e9da3de01e0a hgext/convert/darcs.py --- a/hgext/convert/darcs.py Mon Jan 12 09:12:35 2009 +0100 +++ b/hgext/convert/darcs.py Mon Jan 12 09:13:45 2009 +0100 @@ -32,7 +32,7 @@ if ElementTree is None: raise util.Abort(_("Python ElementTree module is not available")) - if not os.path.exists(os.path.join(path, '_darcs', 'inventory')): + if not os.path.exists(os.path.join(path, '_darcs', 'inventories')): raise NoRepo("%s does not look like a darcs repo" % path) self.path = os.path.realpath(path) diff -r f9fcb189c8e2 -r e9da3de01e0a hgext/convert/gnuarch.py --- a/hgext/convert/gnuarch.py Mon Jan 12 09:12:35 2009 +0100 +++ b/hgext/convert/gnuarch.py Mon Jan 12 09:13:45 2009 +0100 @@ -3,7 +3,8 @@ from common import NoRepo, commandline, commit, converter_source from mercurial.i18n import _ from mercurial import util -import os, shutil, tempfile, stat +import os, shutil, tempfile, stat, locale +from email.Parser import Parser class gnuarch_source(converter_source, commandline): @@ -13,6 +14,7 @@ self.summary = '' self.date = None self.author = '' + self.continuationof = None self.add_files = [] self.mod_files = [] self.del_files = [] @@ -46,38 +48,74 @@ self.parents = {} self.tags = {} self.modecache = {} + self.catlogparser = Parser() + self.locale = locale.getpreferredencoding() + self.archives = [] def before(self): + # Get registered archives + self.archives = [i.rstrip('\n') + for i in self.runlines0('archives', '-n')] + if self.execmd == 'tla': output = self.run0('tree-version', self.path) else: output = self.run0('tree-version', '-d', self.path) self.treeversion = output.strip() - self.ui.status(_('analyzing tree version %s...\n') % self.treeversion) - # Get name of temporary directory version = self.treeversion.split('/') self.tmppath = os.path.join(tempfile.gettempdir(), 'hg-%s' % version[1]) # Generate parents dictionary - child = [] - output, status = self.runlines('revisions', self.treeversion) - self.checkexit(status, 'archive registered?') - for l in output: - rev = l.strip() - self.changes[rev] = self.gnuarch_rev(rev) + self.parents[None] = [] + treeversion = self.treeversion + child = None + while treeversion: + self.ui.status(_('analyzing tree version %s...\n') % treeversion) + + archive = treeversion.split('/')[0] + if archive not in self.archives: + self.ui.status(_('tree analysis stopped because it points to an unregistered archive %s...\n') % archive) + break + + # Get the complete list of revisions for that tree version + output, status = self.runlines('revisions', '-r', '-f', treeversion) + self.checkexit(status, 'failed retrieveing revisions for %s' % treeversion) + + # No new iteration unless a revision has a continuation-of header + treeversion = None + + for l in output: + rev = l.strip() + self.changes[rev] = self.gnuarch_rev(rev) + self.parents[rev] = [] - # Read author, date and summary - catlog = self.runlines0('cat-log', '-d', self.path, rev) - self._parsecatlog(catlog, rev) + # Read author, date and summary + catlog, status = self.run('cat-log', '-d', self.path, rev) + if status: + catlog = self.run0('cat-archive-log', rev) + self._parsecatlog(catlog, rev) + + # Populate the parents map + self.parents[child].append(rev) - self.parents[rev] = child - child = [rev] - if rev == self.rev: - break - self.parents[None] = child + # Keep track of the current revision as the child of the next + # revision scanned + child = rev + + # Check if we have to follow the usual incremental history + # or if we have to 'jump' to a different treeversion given + # by the continuation-of header. + if self.changes[rev].continuationof: + treeversion = '--'.join(self.changes[rev].continuationof.split('--')[:-1]) + break + + # If we reached a base-0 revision w/o any continuation-of + # header, it means the tree history ends here. + if rev[-6:] == 'base-0': + break def after(self): self.ui.debug(_('cleaning up %s\n') % self.tmppath) @@ -135,7 +173,7 @@ def getcommit(self, rev): changes = self.changes[rev] return commit(author = changes.author, date = changes.date, - desc = changes.summary, parents = self.parents[rev]) + desc = changes.summary, parents = self.parents[rev], rev=rev) def gettags(self): return self.tags @@ -150,26 +188,19 @@ return os.system(cmdline) def _update(self, rev): - if rev == 'base-0': - # Initialise 'base-0' revision + self.ui.debug(_('applying revision %s...\n') % rev) + changeset, status = self.runlines('replay', '-d', self.tmppath, + rev) + if status: + # Something went wrong while merging (baz or tla + # issue?), get latest revision and try from there + shutil.rmtree(self.tmppath, ignore_errors=True) self._obtainrevision(rev) else: - self.ui.debug(_('applying revision %s...\n') % rev) - revision = '%s--%s' % (self.treeversion, rev) - changeset, status = self.runlines('replay', '-d', self.tmppath, - revision) - if status: - # Something went wrong while merging (baz or tla - # issue?), get latest revision and try from there - shutil.rmtree(self.tmppath, ignore_errors=True) - self._obtainrevision(rev) - else: - old_rev = self.parents[rev][0] - self.ui.debug(_('computing changeset between %s and %s...\n') - % (old_rev, rev)) - rev_a = '%s--%s' % (self.treeversion, old_rev) - rev_b = '%s--%s' % (self.treeversion, rev) - self._parsechangeset(changeset, rev) + old_rev = self.parents[rev][0] + self.ui.debug(_('computing changeset between %s and %s...\n') + % (old_rev, rev)) + self._parsechangeset(changeset, rev) def _getfile(self, name, rev): mode = os.lstat(os.path.join(self.tmppath, name)).st_mode @@ -217,8 +248,7 @@ def _obtainrevision(self, rev): self.ui.debug(_('obtaining revision %s...\n') % rev) - revision = '%s--%s' % (self.treeversion, rev) - output = self._execute('get', revision, self.tmppath) + output = self._execute('get', rev, self.tmppath) self.checkexit(output) self.ui.debug(_('analysing revision %s...\n') % rev) files = self._readcontents(self.tmppath) @@ -230,20 +260,27 @@ return path def _parsecatlog(self, data, rev): - summary = [] - for l in data: - l = l.strip() - if summary: - summary.append(l) - elif l.startswith('Summary:'): - summary.append(l[len('Summary: '):]) - elif l.startswith('Standard-date:'): - date = l[len('Standard-date: '):] - strdate = util.strdate(date, '%Y-%m-%d %H:%M:%S') - self.changes[rev].date = util.datestr(strdate) - elif l.startswith('Creator:'): - self.changes[rev].author = l[len('Creator: '):] - self.changes[rev].summary = '\n'.join(summary) + try: + catlog = self.catlogparser.parsestr(data) + + # Commit date + self.changes[rev].date = util.datestr( + util.strdate(catlog['Standard-date'], + '%Y-%m-%d %H:%M:%S')) + + # Commit author + self.changes[rev].author = self.recode(catlog['Creator']) + + # Commit description + self.changes[rev].summary = '\n\n'.join((catlog['Summary'], + catlog.get_payload())) + self.changes[rev].summary = self.recode(self.changes[rev].summary) + + # Commit revision origin when dealing with a branch or tag + if catlog.has_key('Continuation-of'): + self.changes[rev].continuationof = self.recode(catlog['Continuation-of']) + except Exception, err: + raise util.Abort(_('could not parse cat-log of %s') % rev) def _parsechangeset(self, data, rev): for l in data: diff -r f9fcb189c8e2 -r e9da3de01e0a hgext/convert/subversion.py --- a/hgext/convert/subversion.py Mon Jan 12 09:12:35 2009 +0100 +++ b/hgext/convert/subversion.py Mon Jan 12 09:13:45 2009 +0100 @@ -601,7 +601,7 @@ part = "/".join(parts[:i]) info = part, copyfrom.get(part, None) if info[1] is not None: - self.ui.debug(_("Found parent directory %s\n") % info[1]) + self.ui.debug(_("found parent directory %s\n") % info[1]) rc = info return rc @@ -616,7 +616,7 @@ self.ui.debug(entrypath[len(frompath):] + '\n') entrypath = froment.copyfrom_path + entrypath[len(frompath):] fromrev = froment.copyfrom_rev - self.ui.debug(_("Info: %s %s %s %s\n") % (frompath, froment, ent, entrypath)) + self.ui.debug(_("info: %s %s %s %s\n") % (frompath, froment, ent, entrypath)) # We can avoid the reparent calls if the module has not changed # but it probably does not worth the pain. @@ -757,7 +757,7 @@ self.ui.note(_('found parent of branch %s at %d: %s\n') % (self.module, prevnum, prevmodule)) else: - self.ui.debug(_("No copyfrom path, don't know what to do.\n")) + self.ui.debug(_("no copyfrom path, don't know what to do.\n")) paths = [] # filter out unrelated paths diff -r f9fcb189c8e2 -r e9da3de01e0a hgext/extdiff.py --- a/hgext/extdiff.py Mon Jan 12 09:12:35 2009 +0100 +++ b/hgext/extdiff.py Mon Jan 12 09:13:45 2009 +0100 @@ -80,9 +80,7 @@ '''snapshot files from working directory. if not using snapshot, -I/-X does not work and recursive diff in tools like kdiff3 and meld displays too many files.''' - repo_root = repo.root - - dirname = os.path.basename(repo_root) + dirname = os.path.basename(repo.root) if dirname == "": dirname = "root" base = os.path.join(tmproot, dirname) @@ -105,8 +103,7 @@ fp.write(chunk) fp.close() - fns_and_mtime.append((dest, os.path.join(repo_root, fn), - os.path.getmtime(dest))) + fns_and_mtime.append((dest, repo.wjoin(fn), os.path.getmtime(dest))) return dirname, fns_and_mtime @@ -169,7 +166,7 @@ for copy_fn, working_fn, mtime in fns_and_mtime: if os.path.getmtime(copy_fn) != mtime: - ui.debug(_('File changed while diffing. ' + ui.debug(_('file changed while diffing. ' 'Overwriting: %s (src: %s)\n') % (working_fn, copy_fn)) util.copyfile(copy_fn, working_fn) diff -r f9fcb189c8e2 -r e9da3de01e0a hgext/fetch.py --- a/hgext/fetch.py Mon Jan 12 09:12:35 2009 +0100 +++ b/hgext/fetch.py Mon Jan 12 09:13:45 2009 +0100 @@ -11,7 +11,7 @@ from mercurial import commands, cmdutil, hg, util, url def fetch(ui, repo, source='default', **opts): - '''Pull changes from a remote repository, merge new changes if needed. + '''pull changes from a remote repository, merge new changes if needed. This finds all changes from the repository at the specified path or URL and adds them to the local repository. diff -r f9fcb189c8e2 -r e9da3de01e0a hgext/hgk.py --- a/hgext/hgk.py Mon Jan 12 09:12:35 2009 +0100 +++ b/hgext/hgk.py Mon Jan 12 09:13:45 2009 +0100 @@ -130,7 +130,7 @@ ui.write('\0') def base(ui, repo, node1, node2): - """Output common ancestor information""" + """output common ancestor information""" node1 = repo.lookup(node1) node2 = repo.lookup(node2) n = repo.changelog.ancestor(node1, node2) @@ -282,7 +282,7 @@ count += 1 def revparse(ui, repo, *revs, **opts): - """Parse given revisions""" + """parse given revisions""" def revstr(rev): if rev == 'HEAD': rev = 'tip' diff -r f9fcb189c8e2 -r e9da3de01e0a hgext/keyword.py --- a/hgext/keyword.py Mon Jan 12 09:12:35 2009 +0100 +++ b/hgext/keyword.py Mon Jan 12 09:13:45 2009 +0100 @@ -425,14 +425,10 @@ keyword substitutions. Monkeypatches patch and webcommands.''' - try: - if (not repo.local() or not kwtools['inc'] - or kwtools['hgcmd'] in nokwcommands.split() - or '.hg' in util.splitpath(repo.root) - or repo._url.startswith('bundle:')): - return - except AttributeError: - pass + if (not hasattr(repo, 'dirstate') or not kwtools['inc'] + or kwtools['hgcmd'] in nokwcommands.split() + or '.hg' in util.splitpath(repo.root)): + return kwtools['templater'] = kwt = kwtemplater(ui, repo) diff -r f9fcb189c8e2 -r e9da3de01e0a hgext/mq.py --- a/hgext/mq.py Mon Jan 12 09:12:35 2009 +0100 +++ b/hgext/mq.py Mon Jan 12 09:13:45 2009 +0100 @@ -963,10 +963,10 @@ raise top = self.applied[-1].name if ret[0]: - self.ui.write( - "Errors during apply, please fix and refresh %s\n" % top) + self.ui.write(_("Errors during apply, please fix and " + "refresh %s\n") % top) else: - self.ui.write("Now at: %s\n" % top) + self.ui.write(_("Now at: %s\n") % top) return ret[0] finally: del wlock @@ -1602,7 +1602,7 @@ index = self.full_series_end() + i self.full_series[index:index] = [patchname] self.parse_series() - self.ui.warn("adding %s to series file\n" % patchname) + self.ui.warn(_("adding %s to series file\n") % patchname) i += 1 added.append(patchname) patchname = None @@ -1786,7 +1786,7 @@ return q.qseries(repo, start=t-1, length=1, status='A', summary=opts.get('summary')) else: - ui.write("No patches applied\n") + ui.write(_("No patches applied\n")) return 1 def next(ui, repo, **opts): @@ -1794,7 +1794,7 @@ q = repo.mq end = q.series_end() if end == len(q.series): - ui.write("All patches applied\n") + ui.write(_("All patches applied\n")) return 1 return q.qseries(repo, start=end, length=1, summary=opts.get('summary')) @@ -1803,10 +1803,10 @@ q = repo.mq l = len(q.applied) if l == 1: - ui.write("Only one patch applied\n") + ui.write(_("Only one patch applied\n")) return 1 if not l: - ui.write("No patches applied\n") + ui.write(_("No patches applied\n")) return 1 return q.qseries(repo, start=l-2, length=1, status='A', summary=opts.get('summary')) @@ -2018,7 +2018,7 @@ status(q.series.index(q.lookup(patch))) def header(ui, repo, patch=None): - """Print the header of the topmost or specified patch""" + """print the header of the topmost or specified patch""" q = repo.mq if patch: diff -r f9fcb189c8e2 -r e9da3de01e0a hgext/patchbomb.py --- a/hgext/patchbomb.py Mon Jan 12 09:12:35 2009 +0100 +++ b/hgext/patchbomb.py Mon Jan 12 09:13:45 2009 +0100 @@ -9,8 +9,7 @@ The remainder of the changeset description. - [Optional] If the diffstat program is installed, the result of - running diffstat on the patch. + [Optional] The result of running diffstat on the patch. The patch itself, as generated by "hg export". @@ -64,23 +63,10 @@ import os, errno, socket, tempfile, cStringIO import email.MIMEMultipart, email.MIMEBase import email.Utils, email.Encoders, email.Generator -from mercurial import cmdutil, commands, hg, mail, patch, util +from mercurial import cmdutil, commands, hg, mail, mdiff, patch, util from mercurial.i18n import _ from mercurial.node import bin -class exportee: - def __init__(self, container): - self.lines = [] - self.container = container - self.name = 'email' - - def write(self, data): - self.lines.append(data) - - def close(self): - self.container.append(''.join(self.lines).split('\n')) - self.lines = [] - def prompt(ui, prompt, default=None, rest=': ', empty_ok=False): if not ui.interactive: return default @@ -99,16 +85,12 @@ def cdiffstat(ui, summary, patchlines): s = patch.diffstat(patchlines) - if s: - if summary: - ui.write(summary, '\n') - ui.write(s, '\n') - ans = prompt(ui, _('Does the diffstat above look okay? '), 'y') - if not ans.lower().startswith('y'): - raise util.Abort(_('diffstat rejected')) - elif s is None: - ui.warn(_('no diffstat information available\n')) - s = '' + if summary: + ui.write(summary, '\n') + ui.write(s, '\n') + ans = prompt(ui, _('does the diffstat above look okay? '), 'y') + if not ans.lower().startswith('y'): + raise util.Abort(_('diffstat rejected')) return s def makepatch(ui, repo, patch, opts, _charsets, idx, total, patchname=None): @@ -239,6 +221,13 @@ o = repo.changelog.nodesbetween(o, revs or None)[0] return [str(repo.changelog.rev(r)) for r in o] + def getpatches(revs): + for r in cmdutil.revrange(repo, revs): + output = cStringIO.StringIO() + p = patch.export(repo, [r], fp=output, + opts=mdiff.diffopts(git=opts.get('git'))) + yield output.getvalue().split('\n') + def getbundle(dest): tmpdir = tempfile.mkdtemp(prefix='hg-email-bundle-') tmpfn = os.path.join(tmpdir, 'bundle') @@ -308,7 +297,7 @@ % len(patches)) name = None - for p, i in zip(patches, xrange(len(patches))): + for i, p in enumerate(patches): jumbo.extend(p) if patchnames: name = patchnames[i] @@ -360,18 +349,14 @@ ui.config('patchbomb', 'from') or prompt(ui, 'From', ui.username())) + # internal option used by pbranches patches = opts.get('patches') if patches: msgs = getpatchmsgs(patches, opts.get('patchnames')) elif opts.get('bundle'): msgs = getbundlemsgs(getbundle(dest)) else: - patches = [] - commands.export(ui, repo, *revs, **{'output': exportee(patches), - 'switch_parent': False, - 'text': None, - 'git': opts.get('git')}) - msgs = getpatchmsgs(patches) + msgs = getpatchmsgs(list(getpatches(revs))) def getaddrs(opt, prpt, default = None): addrs = opts.get(opt) or (ui.config('email', opt) or diff -r f9fcb189c8e2 -r e9da3de01e0a hgext/purge.py --- a/hgext/purge.py Mon Jan 12 09:12:35 2009 +0100 +++ b/hgext/purge.py Mon Jan 12 09:13:45 2009 +0100 @@ -32,28 +32,26 @@ import os def purge(ui, repo, *dirs, **opts): - '''removes files not tracked by mercurial + '''removes files not tracked by Mercurial - Delete files not known to mercurial, this is useful to test local and - uncommitted changes in the otherwise clean source tree. + Delete files not known to Mercurial. This is useful to test local and + uncommitted changes in an otherwise-clean source tree. This means that purge will delete: - Unknown files: files marked with "?" by "hg status" - - Ignored files: files usually ignored by Mercurial because they match - a pattern in a ".hgignore" file - Empty directories: in fact Mercurial ignores directories unless they contain files under source control managment But it will leave untouched: - - Unmodified tracked files - - Modified tracked files + - Modified and unmodified tracked files + - Ignored files (unless --all is specified) - New files added to the repository (with "hg add") If directories are given on the command line, only files in these directories are considered. - Be careful with purge, you could irreversibly delete some files you + Be careful with purge, as you could irreversibly delete some files you forgot to add to the repository. If you only want to print the list of - files that this program would delete use the --print option. + files that this program would delete, use the --print option. ''' act = not opts['print'] eol = '\n' @@ -64,7 +62,7 @@ def remove(remove_func, name): if act: try: - remove_func(os.path.join(repo.root, name)) + remove_func(repo.wjoin(name)) except OSError: m = _('%s cannot be removed') % name if opts['abort_on_err']: diff -r f9fcb189c8e2 -r e9da3de01e0a hgext/rebase.py --- a/hgext/rebase.py Mon Jan 12 09:12:35 2009 +0100 +++ b/hgext/rebase.py Mon Jan 12 09:13:45 2009 +0100 @@ -34,7 +34,7 @@ if not first: ancestor.ancestor = newancestor else: - repo.ui.debug(_("First revision, do not change ancestor\n")) + repo.ui.debug(_("first revision, do not change ancestor\n")) stats = merge.update(repo, rev, True, True, False) return stats diff -r f9fcb189c8e2 -r e9da3de01e0a hgext/win32mbcs.py --- a/hgext/win32mbcs.py Mon Jan 12 09:12:35 2009 +0100 +++ b/hgext/win32mbcs.py Mon Jan 12 09:13:45 2009 +0100 @@ -8,7 +8,7 @@ # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. # -"""Allow to use MBCS path with problematic encoding. +"""allow to use MBCS path with problematic encoding. Some MBCS encodings are not good for some path operations (i.e. splitting path, case conversion, etc.) with its encoded bytes. diff -r f9fcb189c8e2 -r e9da3de01e0a hgext/zeroconf/__init__.py --- a/hgext/zeroconf/__init__.py Mon Jan 12 09:12:35 2009 +0100 +++ b/hgext/zeroconf/__init__.py Mon Jan 12 09:13:45 2009 +0100 @@ -6,6 +6,29 @@ # the GNU General Public License (version 2), incorporated herein by # reference. +'''zeroconf support for mercurial repositories + +Zeroconf enabled repositories will be announced in a network without the need +to configure a server or a service. They can be discovered without knowing +their actual IP address. + +To use the zeroconf extension add the following entry to your hgrc file: + +[extensions] +hgext.zeroconf = + +To allow other people to discover your repository using run "hg serve" in your +repository. + + $ cd test + $ hg serve + +You can discover zeroconf enabled repositories by running "hg paths". + + $ hg paths + zc-test = http://example.com:8000/test +''' + import Zeroconf, socket, time, os from mercurial import ui from mercurial import extensions diff -r f9fcb189c8e2 -r e9da3de01e0a mercurial/changelog.py --- a/mercurial/changelog.py Mon Jan 12 09:12:35 2009 +0100 +++ b/mercurial/changelog.py Mon Jan 12 09:13:45 2009 +0100 @@ -179,7 +179,7 @@ user = user.strip() if "\n" in user: - raise RevlogError(_("username %s contains a newline") % `user`) + raise RevlogError(_("username %s contains a newline") % repr(user)) user, desc = util.fromlocal(user), util.fromlocal(desc) if date: diff -r f9fcb189c8e2 -r e9da3de01e0a mercurial/commands.py --- a/mercurial/commands.py Mon Jan 12 09:12:35 2009 +0100 +++ b/mercurial/commands.py Mon Jan 12 09:13:45 2009 +0100 @@ -328,29 +328,34 @@ state = hbisect.load_state(repo) if command: + commandpath = util.find_exe(command) changesets = 1 - while changesets: - # update state - status = os.spawnlp(os.P_WAIT, command) - node = repo.lookup(rev or '.') - if status == 125: - transition = "skip" - elif status == 0: - transition = "good" - # status < 0 means process was killed - elif status == 127 or status < 0: - break - else: - transition = "bad" - state[transition].append(node) - ui.note(_('Changeset %s: %s\n') % (short(node), transition)) - check_state(state, interactive=False) - # bisect - nodes, changesets, good = hbisect.bisect(repo.changelog, state) - # update to next check - cmdutil.bail_if_changed(repo) - hg.clean(repo, nodes[0], show_stats=False) - hbisect.save_state(repo, state) + try: + while changesets: + # update state + status = os.spawnl(os.P_WAIT, commandpath) + if status == 125: + transition = "skip" + elif status == 0: + transition = "good" + # status < 0 means process was killed + elif status == 127: + raise util.Abort(_("failed to execute %s") % command) + elif status < 0: + raise util.Abort(_("%s killed") % command) + else: + transition = "bad" + node = repo.lookup(rev or '.') + state[transition].append(node) + ui.note(_('Changeset %s: %s\n') % (short(node), transition)) + check_state(state, interactive=False) + # bisect + nodes, changesets, good = hbisect.bisect(repo.changelog, state) + # update to next check + cmdutil.bail_if_changed(repo) + hg.clean(repo, nodes[0], show_stats=False) + finally: + hbisect.save_state(repo, state) return print_result(nodes, not status) # update state @@ -688,7 +693,10 @@ ui.write("%s\n" % "\n".join(options)) return - ui.write("%s\n" % "\n".join(util.sort(cmdutil.findpossible(cmd, table)))) + cmdlist = cmdutil.findpossible(cmd, table) + if ui.verbose: + cmdlist = [' '.join(c[0]) for c in cmdlist.values()] + ui.write("%s\n" % "\n".join(util.sort(cmdlist))) def debugfsinfo(ui, path = "."): file('.debugfsinfo', 'w').write('') @@ -1325,7 +1333,7 @@ # description doc = gettext(i[0].__doc__) if not doc: - doc = _("(No help text available)") + doc = _("(no help text available)") if ui.quiet: doc = doc.splitlines(0)[0] ui.write("\n%s\n" % doc.rstrip()) @@ -1354,7 +1362,7 @@ continue doc = gettext(e[0].__doc__) if not doc: - doc = _("(No help text available)") + doc = _("(no help text available)") h[f] = doc.splitlines(0)[0].rstrip() cmds[f] = c.lstrip("^") @@ -1397,7 +1405,7 @@ # description if not doc: - doc = _("(No help text available)") + doc = _("(no help text available)") if callable(doc): doc = doc() @@ -1410,7 +1418,7 @@ except KeyError: raise cmdutil.UnknownCommand(name) - doc = gettext(mod.__doc__) or _('No help text available') + doc = gettext(mod.__doc__) or _('no help text available') doc = doc.splitlines(0) ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0])) for d in doc[1:]: @@ -1794,7 +1802,7 @@ if not rev and abs not in repo.dirstate: continue if opts.get('fullpath'): - ui.write(os.path.join(repo.root, abs), end) + ui.write(repo.wjoin(abs), end) else: ui.write(((pats and m.rel(abs)) or abs), end) ret = 0 @@ -2822,8 +2830,6 @@ def tags(ui, repo): """list repository tags - List the repository tags. - This lists both regular and local tags. When the -v/--verbose switch is used, a third column "local" is printed for local tags. """ @@ -3071,7 +3077,7 @@ ('g', 'good', False, _('mark changeset good')), ('b', 'bad', False, _('mark changeset bad')), ('s', 'skip', False, _('skip testing changeset')), - ('c', 'command', '', _('Use command to check changeset state')), + ('c', 'command', '', _('use command to check changeset state')), ('U', 'noupdate', False, _('do not update to target'))], _("[-gbsr] [-c CMD] [REV]")), "branch": diff -r f9fcb189c8e2 -r e9da3de01e0a mercurial/dispatch.py --- a/mercurial/dispatch.py Mon Jan 12 09:12:35 2009 +0100 +++ b/mercurial/dispatch.py Mon Jan 12 09:13:45 2009 +0100 @@ -90,7 +90,7 @@ else: raise except socket.error, inst: - ui.warn(_("abort: %s\n") % inst[-1]) + ui.warn(_("abort: %s\n") % inst.args[-1]) except IOError, inst: if hasattr(inst, "code"): ui.warn(_("abort: %s\n") % inst) @@ -100,7 +100,7 @@ except: # it might be anything, for example a string reason = inst.reason ui.warn(_("abort: error: %s\n") % reason) - elif hasattr(inst, "args") and inst[0] == errno.EPIPE: + elif hasattr(inst, "args") and inst.args[0] == errno.EPIPE: if ui.debugflag: ui.warn(_("broken pipe\n")) elif getattr(inst, "strerror", None): @@ -116,13 +116,13 @@ else: ui.warn(_("abort: %s\n") % inst.strerror) except util.UnexpectedOutput, inst: - ui.warn(_("abort: %s") % inst[0]) - if not isinstance(inst[1], basestring): - ui.warn(" %r\n" % (inst[1],)) - elif not inst[1]: + ui.warn(_("abort: %s") % inst.args[0]) + if not isinstance(inst.args[1], basestring): + ui.warn(" %r\n" % (inst.args[1],)) + elif not inst.args[1]: ui.warn(_(" empty string\n")) else: - ui.warn("\n%r\n" % util.ellipsis(inst[1])) + ui.warn("\n%r\n" % util.ellipsis(inst.args[1])) except ImportError, inst: m = str(inst).split()[-1] ui.warn(_("abort: could not import module %s!\n") % m) diff -r f9fcb189c8e2 -r e9da3de01e0a mercurial/hbisect.py --- a/mercurial/hbisect.py Mon Jan 12 09:12:35 2009 +0100 +++ b/mercurial/hbisect.py Mon Jan 12 09:13:45 2009 +0100 @@ -102,7 +102,7 @@ if value == perfect: # found a perfect candidate? quit early break - if y < perfect: # all downhill from here? + if y < perfect and rev not in skip: # all downhill from here? for c in children.get(rev, []): poison[c] = True # poison children continue diff -r f9fcb189c8e2 -r e9da3de01e0a mercurial/hg.py --- a/mercurial/hg.py Mon Jan 12 09:12:35 2009 +0100 +++ b/mercurial/hg.py Mon Jan 12 09:13:45 2009 +0100 @@ -252,8 +252,6 @@ note = ", ".join([_("%d files %s") % s for s in stats]) repo.ui.status("%s\n" % note) -def _update(repo, node): return update(repo, node) - def update(repo, node): """update the working directory to node, merging linear changes""" stats = _merge.update(repo, node, False, False, None) @@ -262,6 +260,9 @@ repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n")) return stats[3] > 0 +# naming conflict in clone() +_update = update + def clean(repo, node, show_stats=True): """forcibly switch the working directory to node, clobbering changes""" stats = _merge.update(repo, node, False, True, None) diff -r f9fcb189c8e2 -r e9da3de01e0a mercurial/hgweb/hgweb_mod.py --- a/mercurial/hgweb/hgweb_mod.py Mon Jan 12 09:12:35 2009 +0100 +++ b/mercurial/hgweb/hgweb_mod.py Mon Jan 12 09:13:45 2009 +0100 @@ -284,14 +284,13 @@ raise ErrorResponse(HTTP_UNAUTHORIZED, 'read not authorized') allow_read = self.configlist('web', 'allow_read') - result = (not allow_read) or (allow_read == ['*']) or (user in allow_read) - if not result: + result = (not allow_read) or (allow_read == ['*']) + if not result or user in allow_read: raise ErrorResponse(HTTP_UNAUTHORIZED, 'read not authorized') if op == 'pull' and not self.allowpull: raise ErrorResponse(HTTP_UNAUTHORIZED, 'pull not authorized') - # op is None when checking allow/deny_read permissions for a web-browser request - elif op == 'pull' or op is None: + elif op == 'pull' or op is None: # op is None for interface requests return # enforce that you can only push using POST requests diff -r f9fcb189c8e2 -r e9da3de01e0a mercurial/hgweb/hgwebdir_mod.py --- a/mercurial/hgweb/hgwebdir_mod.py Mon Jan 12 09:12:35 2009 +0100 +++ b/mercurial/hgweb/hgwebdir_mod.py Mon Jan 12 09:13:45 2009 +0100 @@ -102,11 +102,11 @@ user = req.env.get('REMOTE_USER') - deny_read = ui.configlist('web', 'deny_read', default=None, untrusted=True) + deny_read = ui.configlist('web', 'deny_read', untrusted=True) if deny_read and (not user or deny_read == ['*'] or user in deny_read): return False - allow_read = ui.configlist('web', 'allow_read', default=None, untrusted=True) + allow_read = ui.configlist('web', 'allow_read', untrusted=True) # by default, allow reading if no allow_read option has been set if (not allow_read) or (allow_read == ['*']) or (user in allow_read): return True diff -r f9fcb189c8e2 -r e9da3de01e0a mercurial/localrepo.py --- a/mercurial/localrepo.py Mon Jan 12 09:12:35 2009 +0100 +++ b/mercurial/localrepo.py Mon Jan 12 09:13:45 2009 +0100 @@ -1579,7 +1579,7 @@ if self.ui.verbose or source == 'bundle': self.ui.status(_("%d changesets found\n") % len(nodes)) if self.ui.debugflag: - self.ui.debug(_("List of changesets:\n")) + self.ui.debug(_("list of changesets:\n")) for node in nodes: self.ui.debug("%s\n" % hex(node)) diff -r f9fcb189c8e2 -r e9da3de01e0a mercurial/patch.py --- a/mercurial/patch.py Mon Jan 12 09:12:35 2009 +0100 +++ b/mercurial/patch.py Mon Jan 12 09:13:45 2009 +0100 @@ -9,7 +9,7 @@ from i18n import _ from node import hex, nullid, short import base85, cmdutil, mdiff, util, revlog, diffhelpers, copies -import cStringIO, email.Parser, os, re, errno +import cStringIO, email.Parser, os, re, errno, math import sys, tempfile, zlib gitre = re.compile('diff --git a/(.*) b/(.*)') @@ -794,9 +794,7 @@ def readline(self): if self.buf: - l = self.buf[0] - del self.buf[0] - return l + return self.buf.pop(0) return self.fp.readline() def __iter__(self): @@ -1059,7 +1057,7 @@ gp = patches[f] if gp and gp.mode: islink, isexec = gp.mode - dst = os.path.join(repo.root, gp.path) + dst = repo.wjoin(gp.path) # patch won't create empty files if gp.op == 'ADD' and not os.path.exists(dst): flags = (isexec and 'x' or '') + (islink and 'l' or '') @@ -1340,19 +1338,61 @@ for chunk in diff(repo, prev, node, opts=opts): fp.write(chunk) - if fp not in (sys.stdout, repo.ui): - fp.close() for seqno, rev in enumerate(revs): single(rev, seqno+1, fp) -def diffstat(patchlines): - if not util.find_exe('diffstat'): - return - output = util.filter('\n'.join(patchlines), - 'diffstat -p1 -w79 2>%s' % util.nulldev) - stat = [l.lstrip() for l in output.splitlines(True)] - last = stat.pop() - stat.insert(0, last) - stat = ''.join(stat) - return stat +def diffstatdata(lines): + filename = None + for line in lines: + if line.startswith('diff'): + if filename: + yield (filename, adds, removes) + # set numbers to 0 anyway when starting new file + adds = 0 + removes = 0 + if line.startswith('diff --git'): + filename = gitre.search(line).group(1) + else: + # format: "diff -r ... -r ... file name" + filename = line.split(None, 5)[-1] + elif line.startswith('+') and not line.startswith('+++'): + adds += 1 + elif line.startswith('-') and not line.startswith('---'): + removes += 1 + yield (filename, adds, removes) + +def diffstat(lines): + output = [] + stats = list(diffstatdata(lines)) + width = util.termwidth() - 2 + + maxtotal, maxname = 0, 0 + totaladds, totalremoves = 0, 0 + for filename, adds, removes in stats: + totaladds += adds + totalremoves += removes + maxname = max(maxname, len(filename)) + maxtotal = max(maxtotal, adds+removes) + + countwidth = len(str(maxtotal)) + graphwidth = width - countwidth - maxname + if graphwidth < 10: + graphwidth = 10 + + factor = int(math.ceil(float(maxtotal) / graphwidth)) + + for filename, adds, removes in stats: + # If diffstat runs out of room it doesn't print anything, which + # isn't very useful, so always print at least one + or - if there + # were at least some changes + pluses = '+' * max(adds/factor, int(bool(adds))) + minuses = '-' * max(removes/factor, int(bool(removes))) + output.append(' %-*s | %*.d %s%s\n' % (maxname, filename, countwidth, + adds+removes, pluses, minuses)) + + if stats: + output.append(' %d files changed, %d insertions(+), %d deletions(-)\n' % + (len(stats), totaladds, totalremoves)) + + return ''.join(output) diff -r f9fcb189c8e2 -r e9da3de01e0a mercurial/ui.py --- a/mercurial/ui.py Mon Jan 12 09:12:35 2009 +0100 +++ b/mercurial/ui.py Mon Jan 12 09:13:45 2009 +0100 @@ -340,7 +340,7 @@ if user is None: user = os.environ.get("EMAIL") if user is None and self.configbool("ui", "askusername"): - user = self.prompt(_("Enter a commit username:"), default=None) + user = self.prompt(_("enter a commit username:"), default=None) if user is None: try: user = '%s@%s' % (util.getuser(), socket.getfqdn()) @@ -350,7 +350,7 @@ if not user: raise util.Abort(_("Please specify a username.")) if "\n" in user: - raise util.Abort(_("username %s contains a newline\n") % `user`) + raise util.Abort(_("username %s contains a newline\n") % repr(user)) return user def shortuser(self, user): diff -r f9fcb189c8e2 -r e9da3de01e0a mercurial/util.py --- a/mercurial/util.py Mon Jan 12 09:12:35 2009 +0100 +++ b/mercurial/util.py Mon Jan 12 09:13:45 2009 +0100 @@ -705,7 +705,7 @@ if cwd is not None and oldcwd != cwd: os.chdir(oldcwd) -class SignatureError: +class SignatureError(Exception): pass def checksignature(func): @@ -1991,3 +1991,24 @@ def uirepr(s): # Avoid double backslash in Windows path repr() return repr(s).replace('\\\\', '\\') + +def termwidth(): + if 'COLUMNS' in os.environ: + try: + return int(os.environ['COLUMNS']) + except ValueError: + pass + try: + import termios, array, fcntl + for dev in (sys.stdout, sys.stdin): + try: + fd = dev.fileno() + if not os.isatty(fd): + continue + arri = fcntl.ioctl(fd, termios.TIOCGWINSZ, '\0' * 8) + return array.array('h', arri)[1] + except ValueError: + pass + except ImportError: + pass + return 80 diff -r f9fcb189c8e2 -r e9da3de01e0a mercurial/util_win32.py --- a/mercurial/util_win32.py Mon Jan 12 09:12:35 2009 +0100 +++ b/mercurial/util_win32.py Mon Jan 12 09:13:45 2009 +0100 @@ -19,7 +19,7 @@ import util from win32com.shell import shell,shellcon -class WinError: +class WinError(Exception): winerror_map = { winerror.ERROR_ACCESS_DENIED: errno.EACCES, winerror.ERROR_ACCOUNT_DISABLED: errno.EACCES, diff -r f9fcb189c8e2 -r e9da3de01e0a setup.py --- a/setup.py Mon Jan 12 09:12:35 2009 +0100 +++ b/setup.py Mon Jan 12 09:13:45 2009 +0100 @@ -9,6 +9,23 @@ if not hasattr(sys, 'version_info') or sys.version_info < (2, 3, 0, 'final'): raise SystemExit("Mercurial requires python 2.3 or later.") +# Solaris Python packaging brain damage +try: + import hashlib + sha = hashlib.sha1() +except: + try: + import sha + except: + raise SystemExit( + "Couldn't import standard hashlib (incomplete Python install).") + +try: + import zlib +except: + raise SystemExit( + "Couldn't import standard zlib (incomplete Python install).") + import os import shutil import tempfile diff -r f9fcb189c8e2 -r e9da3de01e0a tests/tampered.hg Binary file tests/tampered.hg has changed diff -r f9fcb189c8e2 -r e9da3de01e0a tests/test-acl.out --- a/tests/test-acl.out Mon Jan 12 09:12:35 2009 +0100 +++ b/tests/test-acl.out Mon Jan 12 09:13:45 2009 +0100 @@ -15,7 +15,7 @@ searching for changes common changesets up to 6675d58eff77 3 changesets found -List of changesets: +list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd 911600dab2ae7a9baff75958b84fe606851ce955 @@ -43,7 +43,7 @@ searching for changes common changesets up to 6675d58eff77 3 changesets found -List of changesets: +list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd 911600dab2ae7a9baff75958b84fe606851ce955 @@ -75,7 +75,7 @@ searching for changes common changesets up to 6675d58eff77 3 changesets found -List of changesets: +list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd 911600dab2ae7a9baff75958b84fe606851ce955 @@ -112,7 +112,7 @@ searching for changes common changesets up to 6675d58eff77 3 changesets found -List of changesets: +list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd 911600dab2ae7a9baff75958b84fe606851ce955 @@ -151,7 +151,7 @@ searching for changes common changesets up to 6675d58eff77 3 changesets found -List of changesets: +list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd 911600dab2ae7a9baff75958b84fe606851ce955 @@ -193,7 +193,7 @@ searching for changes common changesets up to 6675d58eff77 3 changesets found -List of changesets: +list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd 911600dab2ae7a9baff75958b84fe606851ce955 @@ -234,7 +234,7 @@ searching for changes common changesets up to 6675d58eff77 3 changesets found -List of changesets: +list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd 911600dab2ae7a9baff75958b84fe606851ce955 @@ -278,7 +278,7 @@ searching for changes common changesets up to 6675d58eff77 3 changesets found -List of changesets: +list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd 911600dab2ae7a9baff75958b84fe606851ce955 @@ -321,7 +321,7 @@ searching for changes common changesets up to 6675d58eff77 3 changesets found -List of changesets: +list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd 911600dab2ae7a9baff75958b84fe606851ce955 @@ -365,7 +365,7 @@ searching for changes common changesets up to 6675d58eff77 3 changesets found -List of changesets: +list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd 911600dab2ae7a9baff75958b84fe606851ce955 @@ -409,7 +409,7 @@ searching for changes common changesets up to 6675d58eff77 3 changesets found -List of changesets: +list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd 911600dab2ae7a9baff75958b84fe606851ce955 @@ -458,7 +458,7 @@ searching for changes common changesets up to 6675d58eff77 3 changesets found -List of changesets: +list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd 911600dab2ae7a9baff75958b84fe606851ce955 @@ -506,7 +506,7 @@ searching for changes common changesets up to 6675d58eff77 3 changesets found -List of changesets: +list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd 911600dab2ae7a9baff75958b84fe606851ce955 @@ -561,7 +561,7 @@ searching for changes common changesets up to 6675d58eff77 3 changesets found -List of changesets: +list of changesets: ef1ea85a6374b77d6da9dcda9541f498f2d17df7 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd 911600dab2ae7a9baff75958b84fe606851ce955 diff -r f9fcb189c8e2 -r e9da3de01e0a tests/test-audit-path --- a/tests/test-audit-path Mon Jan 12 09:12:35 2009 +0100 +++ b/tests/test-audit-path Mon Jan 12 09:13:45 2009 +0100 @@ -41,4 +41,8 @@ hg manifest -r3 hg update -Cr3 +echo % attack /tmp/test +hg manifest -r4 +hg update -Cr4 2>&1 | sed -e "s|$HGTMP|[HGTMP]|" + exit 0 diff -r f9fcb189c8e2 -r e9da3de01e0a tests/test-audit-path.out --- a/tests/test-audit-path.out Mon Jan 12 09:12:35 2009 +0100 +++ b/tests/test-audit-path.out Mon Jan 12 09:13:45 2009 +0100 @@ -10,7 +10,7 @@ adding changesets adding manifests adding file changes -added 4 changesets with 5 changes to 5 files (+3 heads) +added 5 changesets with 6 changes to 6 files (+4 heads) (run 'hg heads' to see heads, 'hg merge' to merge) % attack .hg/test .hg/test @@ -25,3 +25,6 @@ % attack ../test ../test abort: path contains illegal component: ../test +% attack /tmp/test +/tmp/test +abort: No such file or directory: [HGTMP]/test-audit-path/target//tmp/test diff -r f9fcb189c8e2 -r e9da3de01e0a tests/test-bdiff --- a/tests/test-bdiff Mon Jan 12 09:12:35 2009 +0100 +++ b/tests/test-bdiff Mon Jan 12 09:13:45 2009 +0100 @@ -9,13 +9,13 @@ if d: c = mpatch.patches(a, [d]) if c != b: - print "***", `a`, `b` + print "***", repr(a), repr(b) print "bad:" - print `c`[:200] - print `d` + print repr(c)[:200] + print repr(d) def test(a, b): - print "***", `a`, `b` + print "***", repr(a), repr(b) test1(a, b) test1(b, a) diff -r f9fcb189c8e2 -r e9da3de01e0a tests/test-bisect --- a/tests/test-bisect Mon Jan 12 09:12:35 2009 +0100 +++ b/tests/test-bisect Mon Jan 12 09:13:45 2009 +0100 @@ -72,3 +72,13 @@ echo % test no action hg bisect -r hg bisect || echo failure + +echo % reproduce AssertionError, issue1445 +hg bisect -r +hg bisect -b 6 +hg bisect -g 0 +hg bisect -s +hg bisect -s +hg bisect -s +hg bisect -s +hg bisect -g diff -r f9fcb189c8e2 -r e9da3de01e0a tests/test-bisect.out --- a/tests/test-bisect.out Mon Jan 12 09:12:35 2009 +0100 +++ b/tests/test-bisect.out Mon Jan 12 09:13:45 2009 +0100 @@ -286,3 +286,20 @@ % test no action abort: cannot bisect (no known good revisions) failure +% reproduce AssertionError, issue1445 +Testing changeset 3:b53bea5e2fcb (6 changesets remaining, ~2 tests) +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +Testing changeset 2:db07c04beaca (6 changesets remaining, ~2 tests) +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +Testing changeset 4:9b2ba8336a65 (6 changesets remaining, ~2 tests) +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +Testing changeset 1:5cd978ea5149 (6 changesets remaining, ~2 tests) +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +Testing changeset 5:7874a09ea728 (6 changesets remaining, ~2 tests) +1 files updated, 0 files merged, 0 files removed, 0 files unresolved +The first bad revision is: +changeset: 6:a3d5c6fdf0d3 +user: test +date: Thu Jan 01 00:00:06 1970 +0000 +summary: msg 6 + diff -r f9fcb189c8e2 -r e9da3de01e0a tests/test-bookmarks-current --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-bookmarks-current Mon Jan 12 09:13:45 2009 +0100 @@ -0,0 +1,41 @@ +#!/bin/sh + +echo "[extensions]" >> $HGRCPATH +echo "bookmarks=" >> $HGRCPATH + +echo "[bookmarks]" >> $HGRCPATH +echo "track.current = True" >> $HGRCPATH + +hg init + +echo % no bookmarks +hg bookmarks + +echo % set bookmark X +hg bookmark X + +echo % update to bookmark X +hg update X + +echo % list bookmarks +hg bookmarks + +echo % rename +hg bookmark -m X Z + +echo % list bookmarks +hg bookmarks + +echo % new bookmark Y +hg bookmark Y + +echo % list bookmarks +hg bookmark + +echo % commit +echo 'b' > b +hg add b +hg commit -m'test' + +echo % list bookmarks +hg bookmark diff -r f9fcb189c8e2 -r e9da3de01e0a tests/test-bookmarks-current.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-bookmarks-current.out Mon Jan 12 09:13:45 2009 +0100 @@ -0,0 +1,18 @@ +% no bookmarks +no bookmarks set +% set bookmark X +% update to bookmark X +0 files updated, 0 files merged, 0 files removed, 0 files unresolved +% list bookmarks + * X -1:000000000000 +% rename +% list bookmarks + * Z -1:000000000000 +% new bookmark Y +% list bookmarks + Y -1:000000000000 + * Z -1:000000000000 +% commit +% list bookmarks + Y -1:000000000000 + * Z 0:719295282060 diff -r f9fcb189c8e2 -r e9da3de01e0a tests/test-bookmarks-rebase.out --- a/tests/test-bookmarks-rebase.out Mon Jan 12 09:12:35 2009 +0100 +++ b/tests/test-bookmarks-rebase.out Mon Jan 12 09:13:45 2009 +0100 @@ -18,6 +18,8 @@ rebase completed changeset: 3:9163974d1cb5 tag: tip +tag: two +tag: one parent: 1:925d80f479bb parent: 2:db815d6d32e6 user: test diff -r f9fcb189c8e2 -r e9da3de01e0a tests/test-bookmarks.out --- a/tests/test-bookmarks.out Mon Jan 12 09:12:35 2009 +0100 +++ b/tests/test-bookmarks.out Mon Jan 12 09:13:45 2009 +0100 @@ -7,6 +7,7 @@ * X 0:f7b1eb17ad24 % look up bookmark changeset: 0:f7b1eb17ad24 +tag: X tag: tip user: test date: Thu Jan 01 00:00:00 1970 +0000 @@ -51,7 +52,10 @@ * x y 2:0316ce92851d % look up stripped bookmark name changeset: 2:0316ce92851d +tag: X2 +tag: Y tag: tip +tag: x y user: test date: Thu Jan 01 00:00:00 1970 +0000 summary: 2 diff -r f9fcb189c8e2 -r e9da3de01e0a tests/test-convert-bzr-merges --- a/tests/test-convert-bzr-merges Mon Jan 12 09:12:35 2009 +0100 +++ b/tests/test-convert-bzr-merges Mon Jan 12 09:13:45 2009 +0100 @@ -18,6 +18,7 @@ bzr add -q file-branch1 bzr commit -q -m 'Added branch1 file' cd ../source +sleep 1 echo content > file-parent bzr add -q file-parent bzr commit -q -m 'Added parent file' @@ -27,6 +28,7 @@ echo somecontent > file-branch2 bzr add -q file-branch2 bzr commit -q -m 'Added brach2 file' +sleep 1 cd ../source bzr merge -q ../source-branch1 bzr merge -q --force ../source-branch2 diff -r f9fcb189c8e2 -r e9da3de01e0a tests/test-convert-cvs-builtincvsps --- a/tests/test-convert-cvs-builtincvsps Mon Jan 12 09:12:35 2009 +0100 +++ b/tests/test-convert-cvs-builtincvsps Mon Jan 12 09:13:45 2009 +0100 @@ -100,5 +100,22 @@ hgcat b/c hg -R src-filemap log --template '#rev# #desc# files: #files#\n' +echo % commit a new revision with funny log message +cd src +sleep 1 +echo e >> a +cvscall -q commit -m'funny +---------------------------- +log message' . | grep '<--' |\ + sed -e 's:.*src/\(.*\),v.*:checking in src/\1,v:g' +cd .. + +echo % convert again +hg convert src src-hg | sed -e 's/connecting to.*cvsrepo/connecting to cvsrepo/g' + echo "graphlog = " >> $HGRCPATH hg -R src-hg glog --template '#rev# (#branches#) #desc# files: #files#\n' + +echo % testing debugcvsps +cd src +hg debugcvsps | sed -e 's/Author:.*/Author:/' -e 's/Date:.*/Date:/' diff -r f9fcb189c8e2 -r e9da3de01e0a tests/test-convert-cvs-builtincvsps.out --- a/tests/test-convert-cvs-builtincvsps.out Mon Jan 12 09:12:35 2009 +0100 +++ b/tests/test-convert-cvs-builtincvsps.out Mon Jan 12 09:13:45 2009 +0100 @@ -124,6 +124,22 @@ 2 update tags files: .hgtags 1 ci0 files: b/c 0 Initial revision files: b/c +% commit a new revision with funny log message +checking in src/a,v +% convert again +using builtin cvsps +collecting CVS rlog +9 log entries +creating changesets +6 changeset entries +connecting to cvsrepo +scanning source... +sorting... +converting... +0 funny +o 6 (branch) funny +| ---------------------------- +| log message files: a o 5 (branch) ci2 files: b/c | | o 4 () ci1 files: a b/c @@ -136,3 +152,85 @@ |/ o 0 () Initial revision files: a b/c +% testing debugcvsps +collecting CVS rlog +9 log entries +creating changesets +6 changeset entries +--------------------- +PatchSet 1 +Date: +Author: +Branch: HEAD +Tag: (none) +Log: +Initial revision + +Members: + a:INITIAL->1.1 + b/c:INITIAL->1.1 + +--------------------- +PatchSet 2 +Date: +Author: +Branch: INITIAL +Tag: start +Log: +import + +Members: + a:1.1->1.1.1.1 + b/c:1.1->1.1.1.1 + +--------------------- +PatchSet 3 +Date: +Author: +Branch: HEAD +Tag: (none) +Log: +ci0 + +Members: + b/c:1.1->1.2 + +--------------------- +PatchSet 4 +Date: +Author: +Branch: HEAD +Tag: (none) +Log: +ci1 + +Members: + a:1.1->1.2 + b/c:1.2->1.3 + +--------------------- +PatchSet 5 +Date: +Author: +Branch: branch +Tag: (none) +Log: +ci2 + +Members: + b/c:1.1->1.1.2.1 + +--------------------- +PatchSet 6 +Date: +Author: +Branch: branch +Tag: (none) +Log: +funny +---------------------------- +log message + +Members: + a:1.2->1.2.2.1 + diff -r f9fcb189c8e2 -r e9da3de01e0a tests/test-convert.out --- a/tests/test-convert.out Mon Jan 12 09:12:35 2009 +0100 +++ b/tests/test-convert.out Mon Jan 12 09:13:45 2009 +0100 @@ -1,6 +1,6 @@ hg convert [OPTION]... SOURCE [DEST [REVMAP]] -Convert a foreign SCM repository to a Mercurial one. +convert a foreign SCM repository to a Mercurial one. Accepted source formats [identifiers]: - Mercurial [hg] diff -r f9fcb189c8e2 -r e9da3de01e0a tests/test-mq.out --- a/tests/test-mq.out Mon Jan 12 09:12:35 2009 +0100 +++ b/tests/test-mq.out Mon Jan 12 09:13:45 2009 +0100 @@ -33,7 +33,7 @@ qfold fold the named patches into the current patch qgoto push or pop patches until named patch is at top of stack qguard set or print guards for a patch - qheader Print the header of the topmost or specified patch + qheader print the header of the topmost or specified patch qimport import a patch qinit init a new queue repository qnew create a new patch diff -r f9fcb189c8e2 -r e9da3de01e0a tests/test-notify.out --- a/tests/test-notify.out Mon Jan 12 09:12:35 2009 +0100 +++ b/tests/test-notify.out Mon Jan 12 09:13:45 2009 +0100 @@ -150,7 +150,8 @@ b diffstat: -files patched: 1 + a | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (6 lines): diff -r f9fcb189c8e2 -r e9da3de01e0a tests/test-patchbomb --- a/tests/test-patchbomb Mon Jan 12 09:12:35 2009 +0100 +++ b/tests/test-patchbomb Mon Jan 12 09:13:45 2009 +0100 @@ -11,6 +11,8 @@ echo "[extensions]" >> $HGRCPATH echo "patchbomb=" >> $HGRCPATH +COLUMNS=80; export COLUMNS + hg init t cd t echo a > a diff -r f9fcb189c8e2 -r e9da3de01e0a tests/test-patchbomb.out --- a/tests/test-patchbomb.out Mon Jan 12 09:12:35 2009 +0100 +++ b/tests/test-patchbomb.out Mon Jan 12 09:13:45 2009 +0100 @@ -196,7 +196,8 @@ c -files patched: 1 + c | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) Displaying [PATCH] test ... @@ -211,7 +212,8 @@ To: foo Cc: bar -files patched: 1 + c | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) # HG changeset patch @@ -232,15 +234,19 @@ a -files patched: 1 + a | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) b -files patched: 1 + b | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) Final summary: -files patched: 2 + a | 1 + + b | 1 + + 2 files changed, 2 insertions(+), 0 deletions(-) Write the introductory message for the patch series. @@ -258,7 +264,9 @@ Cc: bar -files patched: 2 + a | 1 + + b | 1 + + 2 files changed, 2 insertions(+), 0 deletions(-) Displaying [PATCH 1 of 2] a ... Content-Type: text/plain; charset="us-ascii" @@ -274,7 +282,8 @@ To: foo Cc: bar -files patched: 1 + a | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) # HG changeset patch @@ -304,7 +313,8 @@ To: foo Cc: bar -files patched: 1 + b | 1 + + 1 files changed, 1 insertions(+), 0 deletions(-) # HG changeset patch diff -r f9fcb189c8e2 -r e9da3de01e0a tests/test-pull-http --- a/tests/test-pull-http Mon Jan 12 09:12:35 2009 +0100 +++ b/tests/test-pull-http Mon Jan 12 09:13:45 2009 +0100 @@ -19,7 +19,7 @@ hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log cat hg.pid >> $DAEMON_PIDS hg clone http://localhost:$HGPORT/ test3 | sed -e 's,:[0-9][0-9]*/,/,' -kill `cat hg.pid` +"$TESTDIR/killdaemons.py" echo % serve errors cat errors.log diff -r f9fcb189c8e2 -r e9da3de01e0a tests/test-walkrepo.py --- a/tests/test-walkrepo.py Mon Jan 12 09:12:35 2009 +0100 +++ b/tests/test-walkrepo.py Mon Jan 12 09:13:45 2009 +0100 @@ -24,26 +24,26 @@ reposet = frozenset(walkrepos('.', followsym=True)) if sym and (len(reposet) != 3): print "reposet = %r" % (reposet,) - raise SystemExit(1, "Found %d repositories when I should have found 3" % (len(reposet),)) + print "Found %d repositories when I should have found 3" % (len(reposet),) if (not sym) and (len(reposet) != 2): print "reposet = %r" % (reposet,) - raise SystemExit(1, "Found %d repositories when I should have found 2" % (len(reposet),)) + print "Found %d repositories when I should have found 2" % (len(reposet),) sub1set = frozenset((pjoin('.', 'sub1'), pjoin('.', 'circle', 'subdir', 'sub1'))) if len(sub1set & reposet) != 1: print "sub1set = %r" % (sub1set,) print "reposet = %r" % (reposet,) - raise SystemExit(1, "sub1set and reposet should have exactly one path in common.") + print "sub1set and reposet should have exactly one path in common." sub2set = frozenset((pjoin('.', 'subsub1'), pjoin('.', 'subsubdir', 'subsub1'))) if len(sub2set & reposet) != 1: print "sub2set = %r" % (sub2set,) print "reposet = %r" % (reposet,) - raise SystemExit(1, "sub1set and reposet should have exactly one path in common.") + print "sub1set and reposet should have exactly one path in common." sub3 = pjoin('.', 'circle', 'top1') if sym and not (sub3 in reposet): print "reposet = %r" % (reposet,) - raise SystemExit(1, "Symbolic links are supported and %s is not in reposet" % (sub3,)) + print "Symbolic links are supported and %s is not in reposet" % (sub3,) runtest() if sym: