# HG changeset patch # User Matt Mackall # Date 1139199518 21600 # Node ID 7b4128f689bd2ff92c8329974b36f9ee02e24084 # Parent 586b50294ea84be6c0a732dea164b27b0108fd92# Parent 4a3d4843a1bc3f98e919daeecdbdbc22604146e8 Merge with crew diff --git a/contrib/bash_completion b/contrib/bash_completion --- a/contrib/bash_completion +++ b/contrib/bash_completion @@ -2,36 +2,36 @@ shopt -s extglob _hg_command_list() { - hg --debug help 2>/dev/null | \ + "$hg" --debug help 2>/dev/null | \ awk 'function command_line(line) { - gsub(/,/, "", line) - gsub(/:.*/, "", line) - split(line, aliases) - command = aliases[1] - delete aliases[1] - print command - for (i in aliases) - if (index(command, aliases[i]) != 1) - print aliases[i] - } - /^list of commands:/ {commands=1} - commands && /^ debug/ {a[i++] = $0; next;} - commands && /^ [^ ]/ {command_line($0)} - /^global options:/ {exit 0} - END {for (i in a) command_line(a[i])}' + gsub(/,/, "", line) + gsub(/:.*/, "", line) + split(line, aliases) + command = aliases[1] + delete aliases[1] + print command + for (i in aliases) + if (index(command, aliases[i]) != 1) + print aliases[i] + } + /^list of commands:/ {commands=1} + commands && /^ debug/ {a[i++] = $0; next;} + commands && /^ [^ ]/ {command_line($0)} + /^global options:/ {exit 0} + END {for (i in a) command_line(a[i])}' } _hg_option_list() { - hg -v help $1 2> /dev/null | \ - awk '/^ *-/ { - for (i = 1; i <= NF; i ++) { + "$hg" -v help $1 2>/dev/null | \ + awk '/^ *-/ { + for (i = 1; i <= NF; i ++) { if (index($i, "-") != 1) - break; + break; print $i; - } - }' + } + }' } @@ -56,29 +56,29 @@ shopt -s extglob _hg_paths() { - local paths="$(hg paths 2> /dev/null | sed -e 's/ = .*$//')" - COMPREPLY=(${COMPREPLY[@]:-} $( compgen -W '$paths' -- "$cur" )) + local paths="$("$hg" paths 2>/dev/null | sed -e 's/ = .*$//')" + COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$paths' -- "$cur")) } _hg_repos() { local i - for i in $( compgen -d -- "$cur" ); do - test ! -d "$i"/.hg || COMPREPLY=(${COMPREPLY[@]:-} "$i") + for i in $(compgen -d -- "$cur"); do + test ! -d "$i"/.hg || COMPREPLY=(${COMPREPLY[@]:-} "$i") done } _hg_status() { - local files="$( hg status -n$1 . 2> /dev/null)" - COMPREPLY=(${COMPREPLY[@]:-} $( compgen -W '$files' -- "$cur" )) + local files="$("$hg" status -n$1 . 2>/dev/null)" + COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$files' -- "$cur")) } _hg_tags() { - local tags="$(hg tags 2> /dev/null | - sed -e 's/[0-9]*:[a-f0-9]\{40\}$//; s/ *$//')" - COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -W '$tags' -- "$cur") ) + local tags="$("$hg" tags 2>/dev/null | + sed -e 's/[0-9]*:[a-f0-9]\{40\}$//; s/ *$//')" + COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$tags' -- "$cur")) } # this is "kind of" ugly... @@ -87,7 +87,7 @@ shopt -s extglob local i count=0 local filters="$1" - for (( i=1; $i<=$COMP_CWORD; i++ )); do + for ((i=1; $i<=$COMP_CWORD; i++)); do if [[ "${COMP_WORDS[i]}" != -* ]]; then if [[ ${COMP_WORDS[i-1]} == @($filters|$global_args) ]]; then continue @@ -104,6 +104,7 @@ shopt -s extglob local cur prev cmd opts i # global options that receive an argument local global_args='--cwd|-R|--repository' + local hg="$1" COMPREPLY=() cur="$2" @@ -112,7 +113,7 @@ shopt -s extglob # searching for the command # (first non-option argument that doesn't follow a global option that # receives an argument) - for (( i=1; $i<=$COMP_CWORD; i++ )); do + for ((i=1; $i<=$COMP_CWORD; i++)); do if [[ ${COMP_WORDS[i]} != -* ]]; then if [[ ${COMP_WORDS[i-1]} != @($global_args) ]]; then cmd="${COMP_WORDS[i]}" @@ -124,7 +125,7 @@ shopt -s extglob if [[ "$cur" == -* ]]; then opts=$(_hg_option_list $cmd) - COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -W '$opts' -- "$cur") ) + COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$opts' -- "$cur")) return fi @@ -146,7 +147,7 @@ shopt -s extglob fi # canonicalize command name - cmd=$(hg -q help "$cmd" 2> /dev/null | sed -e 's/^hg //; s/ .*//; 1q') + cmd=$("$hg" -q help "$cmd" 2>/dev/null | sed -e 's/^hg //; s/ .*//; 1q') if [ "$cmd" != status ] && [ "$prev" = -r ] || [ "$prev" = --rev ]; then _hg_tags @@ -190,17 +191,17 @@ shopt -s extglob if [ $count = 1 ]; then _hg_paths fi - _hg_repos + _hg_repos ;; debugindex|debugindexdot) - COMPREPLY=(${COMPREPLY[@]:-} $( compgen -f -X "!*.i" -- "$cur" )) + COMPREPLY=(${COMPREPLY[@]:-} $(compgen -f -X "!*.i" -- "$cur")) ;; debugdata) - COMPREPLY=(${COMPREPLY[@]:-} $( compgen -f -X "!*.d" -- "$cur" )) + COMPREPLY=(${COMPREPLY[@]:-} $(compgen -f -X "!*.d" -- "$cur")) ;; esac } -complete -o bashdefault -o default -F _hg hg 2> /dev/null \ +complete -o bashdefault -o default -F _hg hg 2>/dev/null \ || complete -o default -F _hg hg diff --git a/contrib/macosx/Readme.html b/contrib/macosx/Readme.html new file mode 100644 --- /dev/null +++ b/contrib/macosx/Readme.html @@ -0,0 +1,38 @@ + + + + + + + + + +

Before you install

+


+

This is not a stand-alone version of Mercurial.

+


+

To use it, you must have the “official unofficial” MacPython 2.4.1 installed.

+


+

You can download MacPython 2.4.1 from here:

+

http://python.org/ftp/python/2.4.1/MacPython-OSX-2.4.1-1.dmg

+


+

For more information on MacPython, go here:

+

http://undefined.org/python

+


+

After you install

+


+

This package installs the hg executable in /usr/local/bin. This directory may not be in your shell's search path. Don't forget to check.

+


+

Reporting problems

+


+

If you run into any problems, please file a bug online:

+

http://www.selenic.com/mercurial/bts

+ + diff --git a/contrib/macosx/Welcome.html b/contrib/macosx/Welcome.html new file mode 100644 --- /dev/null +++ b/contrib/macosx/Welcome.html @@ -0,0 +1,17 @@ + + + + + + + + + +

This is a prepackaged release of Mercurial for Mac OS X.

+


+

It is based on Mercurial 0.8.

+ + diff --git a/contrib/macosx/macosx-build.txt b/contrib/macosx/macosx-build.txt new file mode 100644 --- /dev/null +++ b/contrib/macosx/macosx-build.txt @@ -0,0 +1,11 @@ +to build a new macosx binary package: + +install macpython from http://undefined.org/python/ + +install py2app from http://pythonmac.org/packages/ + +make sure /usr/local/bin is in your path + +run bdist_mpkg in top-level hg directory + +find packaged stuff in dist directory diff --git a/contrib/win32/ReadMe.html b/contrib/win32/ReadMe.html --- a/contrib/win32/ReadMe.html +++ b/contrib/win32/ReadMe.html @@ -5,7 +5,7 @@ -

Mercurial version 0.7 for Windows

+

Mercurial version 0.8 for Windows

Welcome to Mercurial for Windows!

diff --git a/contrib/win32/mercurial.iss b/contrib/win32/mercurial.iss --- a/contrib/win32/mercurial.iss +++ b/contrib/win32/mercurial.iss @@ -4,7 +4,7 @@ [Setup] AppCopyright=Copyright 2005 Matt Mackall and others AppName=Mercurial -AppVerName=Mercurial version 0.7 +AppVerName=Mercurial version 0.8 InfoAfterFile=contrib/win32/postinstall.txt LicenseFile=COPYING ShowLanguageDialog=yes @@ -14,10 +14,10 @@ AppSupportURL=http://www.selenic.com/mer AppUpdatesURL=http://www.selenic.com/mercurial AppID={{4B95A5F1-EF59-4B08-BED8-C891C46121B3} AppContact=mercurial@selenic.com -OutputBaseFilename=Mercurial-0.7 +OutputBaseFilename=Mercurial-0.8 DefaultDirName={sd}\Mercurial SourceDir=C:\hg\hg-release -VersionInfoVersion=0.7 +VersionInfoVersion=0.8 VersionInfoDescription=Mercurial distributed SCM VersionInfoCopyright=Copyright 2005 Matt Mackall and others VersionInfoCompany=Matt Mackall and others diff --git a/contrib/win32/postinstall.txt b/contrib/win32/postinstall.txt --- a/contrib/win32/postinstall.txt +++ b/contrib/win32/postinstall.txt @@ -8,6 +8,27 @@ file that comes with this package. Release Notes ------------- +2006-01-29 v0.8 + +* Upgrade notes: + + - diff and status command are now repo-wide by default + (use 'hg diff .' for the old behavior) + - GPG signing is now done with the gpg extension + - the --text option for commit, rawcommit, and tag has been removed + - the copy/rename --parents option has been removed + +* Major changes from 0.7 to 0.8: + + - faster status, diff, and commit + - reduced memory usage for push and pull + - improved extension API + - new bisect, gpg, hgk, and win32text extensions + - short URLs, binary file handling, and optional gitweb skin for hgweb + - numerous new command options including log --keyword and pull --rev + - improved hooks and file filtering + + 2005-09-21 v0.7 with modifications * New INI files have been added to control Mercurial's behaviour: diff --git a/doc/Makefile b/doc/Makefile --- a/doc/Makefile +++ b/doc/Makefile @@ -15,7 +15,7 @@ html: $(HTML) asciidoc -d manpage -b docbook $*.txt %.html: %.txt - asciidoc -b html4 $*.txt + asciidoc -b html4 $*.txt || asciidoc -b html $*.txt clean: $(RM) $(MAN) $(MAN:%=%.xml) $(MAN:%=%.html) diff --git a/hgext/gpg.py b/hgext/gpg.py --- a/hgext/gpg.py +++ b/hgext/gpg.py @@ -1,6 +1,14 @@ -import os, tempfile, binascii, errno +# GnuPG signing extension for Mercurial +# +# Copyright 2005, 2006 Benoit Boissinot +# +# This software may be used and distributed according to the terms +# of the GNU General Public License, incorporated herein by reference. + +import os, tempfile, binascii from mercurial import util from mercurial import node as hgnode +from mercurial.i18n import gettext as _ class gpg: def __init__(self, path, key=None): @@ -14,6 +22,7 @@ class gpg: def verify(self, data, sig): """ returns of the good and bad signatures""" try: + # create temporary files fd, sigfile = tempfile.mkstemp(prefix="hggpgsig") fp = os.fdopen(fd, 'wb') fp.write(sig) @@ -22,8 +31,8 @@ class gpg: fp = os.fdopen(fd, 'wb') fp.write(data) fp.close() - gpgcmd = "%s --logger-fd 1 --status-fd 1 --verify \"%s\" \"%s\"" % (self.path, sigfile, datafile) - #gpgcmd = "%s --status-fd 1 --verify \"%s\" \"%s\"" % (self.path, sigfile, datafile) + gpgcmd = ("%s --logger-fd 1 --status-fd 1 --verify " + "\"%s\" \"%s\"" % (self.path, sigfile, datafile)) ret = util.filter("", gpgcmd) except: for f in (sigfile, datafile): @@ -41,7 +50,7 @@ class gpg: continue l = l[9:] if l.startswith("ERRSIG"): - err = "error while verifying signature" + err = _("error while verifying signature") break elif l.startswith("VALIDSIG"): # fingerprint of the primary key @@ -61,12 +70,97 @@ class gpg: return err, keys def newgpg(ui, **opts): + """create a new gpg instance""" gpgpath = ui.config("gpg", "cmd", "gpg") gpgkey = opts.get('key') if not gpgkey: gpgkey = ui.config("gpg", "key", None) return gpg(gpgpath, gpgkey) +def sigwalk(repo): + """ + walk over every sigs, yields a couple + ((node, version, sig), (filename, linenumber)) + """ + def parsefile(fileiter, context): + ln = 1 + for l in fileiter: + if not l: + continue + yield (l.split(" ", 2), (context, ln)) + ln +=1 + + fl = repo.file(".hgsigs") + h = fl.heads() + h.reverse() + # read the heads + for r in h: + fn = ".hgsigs|%s" % hgnode.short(r) + for item in parsefile(fl.read(r).splitlines(), fn): + yield item + try: + # read local signatures + fn = "localsigs" + for item in parsefile(repo.opener(fn), fn): + yield item + except IOError: + pass + +def getkeys(ui, repo, mygpg, sigdata, context): + """get the keys who signed a data""" + fn, ln = context + node, version, sig = sigdata + prefix = "%s:%d" % (fn, ln) + node = hgnode.bin(node) + + data = node2txt(repo, node, version) + sig = binascii.a2b_base64(sig) + err, keys = mygpg.verify(data, sig) + if err: + ui.warn("%s:%d %s\n" % (fn, ln , err)) + return None + + validkeys = [] + # warn for expired key and/or sigs + for key in keys: + if key[0] == "BADSIG": + ui.write(_("%s Bad signature from \"%s\"\n") % (prefix, key[2])) + continue + if key[0] == "EXPSIG": + ui.write(_("%s Note: Signature has expired" + " (signed by: \"%s\")\n") % (prefix, key[2])) + elif key[0] == "EXPKEYSIG": + ui.write(_("%s Note: This key has expired" + " (signed by: \"%s\")\n") % (prefix, key[2])) + validkeys.append((key[1], key[2], key[3])) + return validkeys + +def sigs(ui, repo): + """list signed changesets""" + mygpg = newgpg(ui) + revs = {} + + for data, context in sigwalk(repo): + node, version, sig = data + fn, ln = context + try: + n = repo.lookup(node) + except KeyError: + ui.warn(_("%s:%d node does not exist\n") % (fn, ln)) + continue + r = repo.changelog.rev(n) + keys = getkeys(ui, repo, mygpg, data, context) + if not keys: + continue + revs.setdefault(r, []) + revs[r].extend(keys) + nodes = list(revs) + nodes.reverse() + for rev in nodes: + for k in revs[rev]: + r = "%5d:%s" % (rev, hgnode.hex(repo.changelog.node(rev))) + ui.write("%-30s %s\n" % (keystr(ui, k), r)) + def check(ui, repo, rev): """verify all the signatures there may be for a particular revision""" mygpg = newgpg(ui) @@ -74,63 +168,30 @@ def check(ui, repo, rev): hexrev = hgnode.hex(rev) keys = [] - def addsig(fn, ln, l): - if not l: return - n, v, sig = l.split(" ", 2) - if n == hexrev: - data = node2txt(repo, rev, v) - sig = binascii.a2b_base64(sig) - err, k = mygpg.verify(data, sig) - if not err: - keys.append((k, fn, ln)) - else: - ui.warn("%s:%d %s\n" % (fn, ln , err)) - - fl = repo.file(".hgsigs") - h = fl.heads() - h.reverse() - # read the heads - for r in h: - ln = 1 - for l in fl.read(r).splitlines(): - addsig(".hgsigs|%s" % hgnode.short(r), ln, l) - ln +=1 - try: - # read local signatures - ln = 1 - f = repo.opener("localsigs") - for l in f: - addsig("localsigs", ln, l) - ln +=1 - except IOError: - pass + for data, context in sigwalk(repo): + node, version, sig = data + if node == hexrev: + k = getkeys(ui, repo, mygpg, data, context) + if k: + keys.extend(k) if not keys: - ui.write("%s not signed\n" % hgnode.short(rev)) + ui.write(_("No valid signature for %s\n") % hgnode.short(rev)) return - valid = [] - # warn for expired key and/or sigs - for k, fn, ln in keys: - prefix = "%s:%d" % (fn, ln) - for key in k: - if key[0] == "BADSIG": - ui.write("%s Bad signature from \"%s\"\n" % (prefix, key[2])) - continue - if key[0] == "EXPSIG": - ui.write("%s Note: Signature has expired" - " (signed by: \"%s\")\n" % (prefix, key[2])) - elif key[0] == "EXPKEYSIG": - ui.write("%s Note: This key has expired" - " (signed by: \"%s\")\n" % (prefix, key[2])) - valid.append((key[1], key[2], key[3])) + # print summary ui.write("%s is signed by:\n" % hgnode.short(rev)) - for keyid, user, fingerprint in valid: - role = getrole(ui, fingerprint) - ui.write(" %s (%s)\n" % (user, role)) + for key in keys: + ui.write(" %s\n" % keystr(ui, key)) -def getrole(ui, fingerprint): - return ui.config("gpg", fingerprint, "no role defined") +def keystr(ui, key): + """associate a string to a key (username, comment)""" + keyid, user, fingerprint = key + comment = ui.config("gpg", fingerprint, None) + if comment: + return "%s (%s)" % (user, comment) + else: + return user def sign(ui, repo, *revs, **opts): """add a signature for the current tip or a given revision""" @@ -150,7 +211,7 @@ def sign(ui, repo, *revs, **opts): data = node2txt(repo, n, sigver) sig = mygpg.sign(data) if not sig: - raise util.Abort("Error while signing") + raise util.Abort(_("Error while signing")) sig = binascii.b2a_base64(sig) sig = sig.replace("\n", "") sigmessage += "%s %s %s\n" % (hexnode, sigver, sig) @@ -162,9 +223,9 @@ def sign(ui, repo, *revs, **opts): for x in repo.changes(): if ".hgsigs" in x and not opts["force"]: - raise util.Abort("working copy of .hgsigs is changed " - "(please commit .hgsigs manually" - "or use --force)") + raise util.Abort(_("working copy of .hgsigs is changed " + "(please commit .hgsigs manually " + "or use --force)")) repo.wfile(".hgsigs", "ab").write(sigmessage) @@ -176,7 +237,8 @@ def sign(ui, repo, *revs, **opts): message = opts['message'] if not message: - message = "\n".join(["Added signature for changeset %s" % hgnode.hex(n) + message = "\n".join([_("Added signature for changeset %s") + % hgnode.hex(n) for n in nodes]) try: repo.commit([".hgsigs"], message, opts['user'], opts['date']) @@ -188,19 +250,20 @@ def node2txt(repo, node, ver): if ver == "0": return "%s\n" % hgnode.hex(node) else: - util.Abort("unknown signature version") + raise util.Abort(_("unknown signature version")) cmdtable = { "sign": (sign, - [('l', 'local', None, "make the signature local"), - ('f', 'force', None, "sign even if the sigfile is modified"), - ('', 'no-commit', None, "do not commit the sigfile after signing"), - ('m', 'message', "", "commit message"), - ('d', 'date', "", "date code"), - ('u', 'user', "", "user"), - ('k', 'key', "", "the key id to sign with")], - "hg sign [OPTION]... REVISIONS"), - "sigcheck": (check, [], 'hg sigcheck REVISION') + [('l', 'local', None, _("make the signature local")), + ('f', 'force', None, _("sign even if the sigfile is modified")), + ('', 'no-commit', None, _("do not commit the sigfile after signing")), + ('m', 'message', "", _("commit message")), + ('d', 'date', "", _("date code")), + ('u', 'user', "", _("user")), + ('k', 'key', "", _("the key id to sign with"))], + _("hg sign [OPTION]... [REVISION]...")), + "sigcheck": (check, [], _('hg sigcheck REVISION')), + "sigs": (sigs, [], _('hg sigs')), } diff --git a/contrib/patchbomb b/hgext/patchbomb.py old mode 100755 new mode 100644 rename from contrib/patchbomb rename to hgext/patchbomb.py --- a/contrib/patchbomb +++ b/hgext/patchbomb.py @@ -1,7 +1,5 @@ -#!/usr/bin/python -# -# Interactive script for sending a collection of Mercurial changesets -# as a series of patch emails. +# Command for sending a collection of Mercurial changesets as a series +# of patch emails. # # The series is started off with a "[PATCH 0 of N]" introduction, # which describes the series as a whole. @@ -50,9 +48,9 @@ from email.MIMEMultipart import MIMEMultipart from email.MIMEText import MIMEText from mercurial import commands -from mercurial import fancyopts from mercurial import hg from mercurial import ui +from mercurial.i18n import gettext as _ import os import popen2 import smtplib @@ -89,6 +87,17 @@ def diffstat(patch): except: pass def patchbomb(ui, repo, *revs, **opts): + '''send changesets as a series of patch emails + + The series starts with a "[PATCH 0 of N]" introduction, which + describes the series as a whole. + + Each patch email has a Subject line of "[PATCH M of N] ...", using + the first line of the changeset description as the subject text. + The message contains two or three body parts. First, the rest of + the changeset description. Next, (optionally) if the diffstat + program is installed, the result of running diffstat on the patch. + Finally, the patch itself, as generated by "hg export".''' def prompt(prompt, default = None, rest = ': ', empty_ok = False): if default: prompt += ' [%s]' % default prompt += rest @@ -97,7 +106,7 @@ def patchbomb(ui, repo, *revs, **opts): if r: return r if default is not None: return default if empty_ok: return r - ui.warn('Please enter a valid value.\n') + ui.warn(_('Please enter a valid value.\n')) def confirm(s): if not prompt(s, default = 'y', rest = '? ').lower().startswith('y'): @@ -109,7 +118,7 @@ def patchbomb(ui, repo, *revs, **opts): if summary: ui.write(summary, '\n') ui.write(s, '\n') - confirm('Does the diffstat above look okay') + confirm(_('Does the diffstat above look okay')) return s def makepatch(patch, idx, total): @@ -162,20 +171,20 @@ def patchbomb(ui, repo, *revs, **opts): self.container.append(''.join(self.lines).split('\n')) self.lines = [] - commands.export(ui, repo, *args, **{'output': exportee(patches), + commands.export(ui, repo, *revs, **{'output': exportee(patches), 'switch_parent': False, 'text': None}) jumbo = [] msgs = [] - ui.write('This patch series consists of %d patches.\n\n' % len(patches)) + ui.write(_('This patch series consists of %d patches.\n\n') % len(patches)) for p, i in zip(patches, range(len(patches))): jumbo.extend(p) msgs.append(makepatch(p, i + 1, len(patches))) - ui.write('\nWrite the introductory message for the patch series.\n\n') + ui.write(_('\nWrite the introductory message for the patch series.\n\n')) sender = (opts['from'] or ui.config('patchbomb', 'from') or prompt('From', ui.username())) @@ -193,7 +202,7 @@ def patchbomb(ui, repo, *revs, **opts): to = getaddrs('to', 'To') cc = getaddrs('cc', 'Cc', '') - ui.write('Finish with ^D or a dot on a line by itself.\n\n') + ui.write(_('Finish with ^D or a dot on a line by itself.\n\n')) body = [] @@ -208,7 +217,7 @@ def patchbomb(ui, repo, *revs, **opts): ui.write('\n') if opts['diffstat']: - d = cdiffstat('Final summary:\n', jumbo) + d = cdiffstat(_('Final summary:\n'), jumbo) if d: msg.attach(MIMEText(d)) msgs.insert(0, msg) @@ -252,25 +261,15 @@ def patchbomb(ui, repo, *revs, **opts): if not opts['test']: s.close() -if __name__ == '__main__': - optspec = [('c', 'cc', [], 'email addresses of copy recipients'), - ('d', 'diffstat', None, 'add diffstat output to messages'), - ('f', 'from', '', 'email address of sender'), - ('', 'plain', None, 'omit hg patch header'), - ('n', 'test', None, 'print messages that would be sent'), - ('s', 'subject', '', 'subject of introductory message'), - ('t', 'to', [], 'email addresses of recipients')] - options = {} - try: - args = fancyopts.fancyopts(sys.argv[1:], commands.globalopts + optspec, - options) - except fancyopts.getopt.GetoptError, inst: - u = ui.ui() - u.warn('error: %s' % inst) - sys.exit(1) - - u = ui.ui(options["verbose"], options["debug"], options["quiet"], - not options["noninteractive"]) - repo = hg.repository(ui = u) - - patchbomb(u, repo, *args, **options) +cmdtable = { + 'email': + (patchbomb, + [('c', 'cc', [], 'email addresses of copy recipients'), + ('d', 'diffstat', None, 'add diffstat output to messages'), + ('f', 'from', '', 'email address of sender'), + ('', 'plain', None, 'omit hg patch header'), + ('n', 'test', None, 'print messages that would be sent'), + ('s', 'subject', '', 'subject of introductory message'), + ('t', 'to', [], 'email addresses of recipients')], + "hg email [OPTION]... [REV]...") + } diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -1399,6 +1399,13 @@ class localrepository(object): modified, added, removed, deleted, unknown = self.changes() + # is this a jump, or a merge? i.e. is there a linear path + # from p1 to p2? + linear_path = (pa == p1 or pa == p2) + + if allow and linear_path: + raise util.Abort(_("there is nothing to merge, " + "just use 'hg update'")) if allow and not forcemerge: if modified or added or removed: raise util.Abort(_("outstanding uncommited changes")) @@ -1411,10 +1418,6 @@ class localrepository(object): raise util.Abort(_("'%s' already exists in the working" " dir and differs from remote") % f) - # is this a jump, or a merge? i.e. is there a linear path - # from p1 to p2? - linear_path = (pa == p1 or pa == p2) - # resolve the manifest to determine which files # we care about merging self.ui.note(_("resolving manifests\n")) diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -81,7 +81,7 @@ try: author='Matt Mackall', author_email='mpm@selenic.com', url='http://selenic.com/mercurial', - description='scalable distributed SCM', + description='Scalable distributed SCM', license='GNU GPL', packages=['mercurial', 'hgext'], ext_modules=[Extension('mercurial.mpatch', ['mercurial/mpatch.c']), @@ -92,6 +92,10 @@ try: glob.glob('templates/*.tmpl'))], cmdclass=cmdclass, scripts=['hg', 'hgmerge'], + options=dict(bdist_mpkg=dict(zipdist=True, + license='COPYING', + readme='contrib/macosx/Readme.html', + welcome='contrib/macosx/Welcome.html')), **py2exe_opts) finally: mercurial.version.forget_version() diff --git a/templates/fileannotate-gitweb.tmpl b/templates/fileannotate-gitweb.tmpl --- a/templates/fileannotate-gitweb.tmpl +++ b/templates/fileannotate-gitweb.tmpl @@ -10,7 +10,7 @@
#file|escape#
diff --git a/templates/fileannotate-raw.tmpl b/templates/fileannotate-raw.tmpl new file mode 100644 --- /dev/null +++ b/templates/fileannotate-raw.tmpl @@ -0,0 +1,5 @@ +#header# +#annotate%annotateline# +#footer# + + diff --git a/templates/fileannotate.tmpl b/templates/fileannotate.tmpl --- a/templates/fileannotate.tmpl +++ b/templates/fileannotate.tmpl @@ -10,6 +10,7 @@ manifest file revisions +raw

Annotate #file|escape#

diff --git a/templates/map b/templates/map --- a/templates/map +++ b/templates/map @@ -43,7 +43,7 @@ filediffparent = "parent #rev#: #node|short#" filediffchild = "child #rev#:#node|short#" filelogchild = "child #rev#: #node|short#" -indexentry = "#name|escape##shortdesc|escape##contact|obfuscate##lastupdate|age# agoRSS" +indexentry = "#name|escape##shortdesc##contact|obfuscate##lastupdate|age# agoRSS" index = index.tmpl archiveentry = "#type|escape# " notfound = notfound.tmpl diff --git a/templates/map-raw b/templates/map-raw --- a/templates/map-raw +++ b/templates/map-raw @@ -1,15 +1,16 @@ header = header-raw.tmpl footer = "" changeset = changeset-raw.tmpl -annotateline = "#author#@#rev#
#line|escape#
" -difflineplus = "#line|escape#" -difflineminus = "#line|escape#" -difflineat = "#line|escape#" -diffline = "#line|escape#" +difflineplus = "#line#" +difflineminus = "#line#" +difflineat = "#line#" +diffline = "#line#" changesetparent = "# parent: #node#" changesetchild = "# child: #node#" -filenodelink = "#file|urlescape#" +filenodelink = "" filerevision = filerevision-raw.tmpl -fileline = "#line|escape#" +fileline = "#line#" diffblock = "#lines#" filediff = filediff-raw.tmpl +fileannotate = fileannotate-raw.tmpl +annotateline = "#author#@#rev#: #line#" diff --git a/tests/test-up-local-change b/tests/test-up-local-change --- a/tests/test-up-local-change +++ b/tests/test-up-local-change @@ -24,11 +24,34 @@ hg commit -m "2" -d "0 0" cd ../r2 hg -q pull ../r1 hg status +hg parents hg --debug up +hg parents +hg --debug up 0 +hg parents hg --debug up -m || echo failed -hg --debug up -f -m +hg parents +hg --debug up hg parents hg -v history hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" +# create a second head +cd ../r1 +hg up 0 +echo b2 > b +echo a3 > a +hg addremove +hg commit -m "3" -d "0 0" + +cd ../r2 +hg -q pull ../r1 +hg status +hg parents +hg --debug up || echo failed +hg --debug up -m || echo failed +hg --debug up -f -m +hg parents +hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ + -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" diff --git a/tests/test-up-local-change.out b/tests/test-up-local-change.out --- a/tests/test-up-local-change.out +++ b/tests/test-up-local-change.out @@ -7,6 +7,11 @@ diff -r c19d34741b0a a +abc adding b M a +changeset: 0:c19d34741b0a +user: test +date: Thu Jan 1 00:00:00 1970 +0000 +summary: 1 + resolving manifests force None allow None moddirstate True linear True ancestor a0c8bcbbb45c local a0c8bcbbb45c remote 1165e8bd193e @@ -16,11 +21,38 @@ getting b merging a resolving a file a: my b789fdd96dc2 other d730145abbf9 ancestor b789fdd96dc2 -abort: outstanding uncommited changes -failed +changeset: 1:1e71731e6fbb +tag: tip +user: test +date: Thu Jan 1 00:00:00 1970 +0000 +summary: 2 + resolving manifests - force None allow 1 moddirstate True linear True - ancestor 1165e8bd193e local 1165e8bd193e remote 1165e8bd193e + force None allow None moddirstate True linear True + ancestor a0c8bcbbb45c local 1165e8bd193e remote a0c8bcbbb45c +remote deleted b +removing b +changeset: 0:c19d34741b0a +user: test +date: Thu Jan 1 00:00:00 1970 +0000 +summary: 1 + +abort: there is nothing to merge, just use 'hg update' +failed +changeset: 0:c19d34741b0a +user: test +date: Thu Jan 1 00:00:00 1970 +0000 +summary: 1 + +resolving manifests + force None allow None moddirstate True linear True + ancestor a0c8bcbbb45c local a0c8bcbbb45c remote 1165e8bd193e + a versions differ, resolve +remote created b +getting b +merging a +resolving a +file a: my b789fdd96dc2 other d730145abbf9 ancestor b789fdd96dc2 changeset: 1:1e71731e6fbb tag: tip user: test @@ -50,3 +82,52 @@ diff -r 1e71731e6fbb a @@ -1,1 +1,1 @@ a2 -a2 +abc +adding b +M a +changeset: 1:1e71731e6fbb +user: test +date: Thu Jan 1 00:00:00 1970 +0000 +summary: 2 + +resolving manifests + force None allow None moddirstate True linear False + ancestor a0c8bcbbb45c local 1165e8bd193e remote 4096f2872392 + a versions differ, resolve + b versions differ, resolve +this update spans a branch affecting the following files: + a (resolve) + b (resolve) +aborting update spanning branches! +(use update -m to merge across branches or -C to lose changes) +failed +abort: outstanding uncommited changes +failed +resolving manifests + force None allow 1 moddirstate True linear False + ancestor a0c8bcbbb45c local 1165e8bd193e remote 4096f2872392 + a versions differ, resolve + b versions differ, resolve +merging a +resolving a +file a: my d730145abbf9 other 13e0d5f949fa ancestor b789fdd96dc2 +merging b +resolving b +file b: my 1e88685f5dde other 61de8c7723ca ancestor 000000000000 +changeset: 1:1e71731e6fbb +user: test +date: Thu Jan 1 00:00:00 1970 +0000 +summary: 2 + +changeset: 2:83c51d0caff4 +tag: tip +parent: 0:c19d34741b0a +user: test +date: Thu Jan 1 00:00:00 1970 +0000 +summary: 3 + +diff -r 1e71731e6fbb a +--- a/a ++++ b/a +@@ -1,1 +1,1 @@ a2 +-a2 ++abc