Mercurial > hg
changeset 1769:982fb022a16a
Merged RSS feed for tags from Peter van Dijk
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Tue, 21 Feb 2006 16:04:47 +0100 |
parents | b9fac31f34c9 (diff) f79afc26ae3b (current diff) |
children | 0762feff3043 b9671b41e360 |
files | mercurial/hgweb.py |
diffstat | 57 files changed, 1612 insertions(+), 743 deletions(-) [+] |
line wrap: on
line diff
--- a/contrib/bash_completion Fri Feb 03 11:23:34 2006 +0100 +++ b/contrib/bash_completion Tue Feb 21 16:04:47 2006 +0100 @@ -2,36 +2,36 @@ _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 @@ _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 @@ 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 @@ 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 @@ # 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 @@ 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 @@ 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 @@ 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
--- a/contrib/convert-repo Fri Feb 03 11:23:34 2006 +0100 +++ b/contrib/convert-repo Tue Feb 21 16:04:47 2006 +0100 @@ -21,7 +21,7 @@ # interrupted and can be run repeatedly to copy new commits. import sys, os, zlib, sha, time -from mercurial import hg, ui, util, commands +from mercurial import hg, ui, util class convert_git: def __init__(self, path): @@ -113,7 +113,7 @@ except: pass - def putcommit(self, files, parents, author, date, text): + def putcommit(self, files, parents, author, dest, text): seen = {} pl = [] for p in parents: @@ -129,13 +129,8 @@ while parents: p1 = p2 p2 = parents.pop(0) - self.repo.dirstate.setparents(hg.bin(p1), hg.bin(p2)) - if len(files) > 0: - olddir = os.getcwd() - os.chdir(self.path) - commands.addremove(self.repo.ui, self.repo, *files) - os.chdir(olddir) - self.repo.commit(files, text, author, date) + self.repo.rawcommit(files, text, author, dest, + hg.bin(p1), hg.bin(p2)) text = "(octopus merge fixup)\n" p2 = hg.hex(self.repo.changelog.tip()) @@ -265,6 +260,7 @@ t = self.toposort(parents) t = [n for n in t if n not in self.map] num = len(t) + c = None for c in t: num -= 1 @@ -279,7 +275,7 @@ if v in self.map: ctags[k] = self.map[v] - if ctags: + if c and ctags: nrev = self.dest.puttags(ctags) # write another hash correspondence to override the previous # one so we don't end up with extra tag heads
--- a/contrib/hbisect.py Fri Feb 03 11:23:34 2006 +0100 +++ b/contrib/hbisect.py Tue Feb 21 16:04:47 2006 +0100 @@ -187,7 +187,7 @@ check_clean(self.ui, self.repo) rev = self.next() self.ui.write("Now testing %s\n" % hg.hex(rev)) - return self.repo.update(rev, allow=True, force=True) + return self.repo.update(rev, force=True) def good(self, rev): self.goodrevs.append(rev) @@ -232,7 +232,7 @@ b.good(new_rev) ui.write("it is good\n") anc = b.ancestors() - repo.update(new_rev, allow=True, force=True) + repo.update(new_rev, force=True) for v in anc: if v != rev: ui.warn("fail to found cset! :(\n")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/macosx/Readme.html Tue Feb 21 16:04:47 2006 +0100 @@ -0,0 +1,38 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> + <meta http-equiv="Content-Style-Type" content="text/css"> + <title></title> + <style type="text/css"> + p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Helvetica} + p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px} + p.p3 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica} + p.p4 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; color: #000fed} + span.s1 {text-decoration: underline} + span.s2 {font: 12.0px Courier} + </style> +</head> +<body> +<p class="p1"><b>Before you install</b></p> +<p class="p2"><br></p> +<p class="p3">This is <i>not</i> a stand-alone version of Mercurial.</p> +<p class="p2"><br></p> +<p class="p3">To use it, you must have the “official unofficial” MacPython 2.4.1 installed.</p> +<p class="p2"><br></p> +<p class="p3">You can download MacPython 2.4.1 from here:</p> +<p class="p4"><span class="s1"><a href="http://python.org/ftp/python/2.4.1/MacPython-OSX-2.4.1-1.dmg">http://python.org/ftp/python/2.4.1/MacPython-OSX-2.4.1-1.dmg</a></span></p> +<p class="p2"><br></p> +<p class="p3">For more information on MacPython, go here:</p> +<p class="p4"><span class="s1"><a href="http://undefined.org/python/">http://undefined.org/python</a></span></p> +<p class="p2"><br></p> +<p class="p1"><b>After you install</b></p> +<p class="p2"><br></p> +<p class="p3">This package installs the <span class="s2">hg</span> executable in <span class="s2">/usr/local/bin</span>. This directory may not be in your shell's search path. Don't forget to check.</p> +<p class="p2"><br></p> +<p class="p1"><b>Reporting problems</b></p> +<p class="p2"><br></p> +<p class="p3">If you run into any problems, please file a bug online:</p> +<p class="p3"><a href="http://www.selenic.com/mercurial/bts">http://www.selenic.com/mercurial/bts</a></p> +</body> +</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/macosx/Welcome.html Tue Feb 21 16:04:47 2006 +0100 @@ -0,0 +1,17 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> + <meta http-equiv="Content-Style-Type" content="text/css"> + <title></title> + <style type="text/css"> + p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica} + p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px} + </style> +</head> +<body> +<p class="p1">This is a prepackaged release of <a href="http://www.selenic.com/mercurial">Mercurial</a> for Mac OS X.</p> +<p class="p2"><br></p> +<p class="p1">It is based on Mercurial 0.8.</p> +</body> +</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/macosx/macosx-build.txt Tue Feb 21 16:04:47 2006 +0100 @@ -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
--- a/contrib/patchbomb Fri Feb 03 11:23:34 2006 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,276 +0,0 @@ -#!/usr/bin/python -# -# Interactive script 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. -# -# 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: -# -# The remainder of the changeset description. -# -# [Optional] If the diffstat program is installed, the result of -# running diffstat on the patch. -# -# The patch itself, as generated by "hg export". -# -# Each message refers to all of its predecessors using the In-Reply-To -# and References headers, so they will show up as a sequence in -# threaded mail and news readers, and in mail archives. -# -# For each changeset, you will be prompted with a diffstat summary and -# the changeset summary, so you can be sure you are sending the right -# changes. -# -# It is best to run this script with the "-n" (test only) flag before -# firing it up "for real", in which case it will use your pager to -# display each of the messages that it would send. -# -# To configure a default mail host, add a section like this to your -# hgrc file: -# -# [smtp] -# host = my_mail_host -# port = 1025 -# tls = yes # or omit if not needed -# username = user # if SMTP authentication required -# password = password # if SMTP authentication required - PLAINTEXT -# -# To configure other defaults, add a section like this to your hgrc -# file: -# -# [patchbomb] -# from = My Name <my@email> -# to = recipient1, recipient2, ... -# cc = cc1, cc2, ... - -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 -import os -import popen2 -import smtplib -import socket -import sys -import tempfile -import time - -try: - # readline gives raw_input editing capabilities, but is not - # present on windows - import readline -except ImportError: pass - -def diffstat(patch): - fd, name = tempfile.mkstemp() - try: - p = popen2.Popen3('diffstat -p1 -w79 2>/dev/null > ' + name) - try: - for line in patch: print >> p.tochild, line - p.tochild.close() - if p.wait(): return - fp = os.fdopen(fd, 'r') - stat = [] - for line in fp: stat.append(line.lstrip()) - last = stat.pop() - stat.insert(0, last) - stat = ''.join(stat) - if stat.startswith('0 files'): raise ValueError - return stat - except: raise - finally: - try: os.unlink(name) - except: pass - -def patchbomb(ui, repo, *revs, **opts): - def prompt(prompt, default = None, rest = ': ', empty_ok = False): - if default: prompt += ' [%s]' % default - prompt += rest - while True: - r = raw_input(prompt) - if r: return r - if default is not None: return default - if empty_ok: return r - ui.warn('Please enter a valid value.\n') - - def confirm(s): - if not prompt(s, default = 'y', rest = '? ').lower().startswith('y'): - raise ValueError - - def cdiffstat(summary, patch): - s = diffstat(patch) - if s: - if summary: - ui.write(summary, '\n') - ui.write(s, '\n') - confirm('Does the diffstat above look okay') - return s - - def makepatch(patch, idx, total): - desc = [] - node = None - body = '' - for line in patch: - if line.startswith('#'): - if line.startswith('# Node ID'): node = line.split()[-1] - continue - if line.startswith('diff -r'): break - desc.append(line) - if not node: raise ValueError - - #body = ('\n'.join(desc[1:]).strip() or - # 'Patch subject is complete summary.') - #body += '\n\n\n' - - if opts['plain']: - while patch and patch[0].startswith('# '): patch.pop(0) - if patch: patch.pop(0) - while patch and not patch[0].strip(): patch.pop(0) - if opts['diffstat']: - body += cdiffstat('\n'.join(desc), patch) + '\n\n' - body += '\n'.join(patch) - msg = MIMEText(body) - subj = '[PATCH %d of %d] %s' % (idx, total, desc[0].strip()) - if subj.endswith('.'): subj = subj[:-1] - msg['Subject'] = subj - msg['X-Mercurial-Node'] = node - return msg - - start_time = int(time.time()) - - def genmsgid(id): - return '<%s.%s@%s>' % (id[:20], start_time, socket.getfqdn()) - - patches = [] - - 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 = [] - - commands.export(ui, repo, *args, **{'output': exportee(patches), - 'switch_parent': False, - 'text': None}) - - jumbo = [] - msgs = [] - - 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') - - sender = (opts['from'] or ui.config('patchbomb', 'from') or - prompt('From', ui.username())) - - msg = MIMEMultipart() - msg['Subject'] = '[PATCH 0 of %d] %s' % ( - len(patches), - opts['subject'] or - prompt('Subject:', rest = ' [PATCH 0 of %d] ' % len(patches))) - - def getaddrs(opt, prpt, default = None): - addrs = opts[opt] or (ui.config('patchbomb', opt) or - prompt(prpt, default = default)).split(',') - return [a.strip() for a in addrs if a.strip()] - to = getaddrs('to', 'To') - cc = getaddrs('cc', 'Cc', '') - - ui.write('Finish with ^D or a dot on a line by itself.\n\n') - - body = [] - - while True: - try: l = raw_input() - except EOFError: break - if l == '.': break - body.append(l) - - msg.attach(MIMEText('\n'.join(body) + '\n')) - - ui.write('\n') - - if opts['diffstat']: - d = cdiffstat('Final summary:\n', jumbo) - if d: msg.attach(MIMEText(d)) - - msgs.insert(0, msg) - - if not opts['test']: - s = smtplib.SMTP() - s.connect(host = ui.config('smtp', 'host', 'mail'), - port = int(ui.config('smtp', 'port', 25))) - if ui.configbool('smtp', 'tls'): - s.ehlo() - s.starttls() - s.ehlo() - username = ui.config('smtp', 'username') - password = ui.config('smtp', 'password') - if username and password: - s.login(username, password) - parent = None - tz = time.strftime('%z') - for m in msgs: - try: - m['Message-Id'] = genmsgid(m['X-Mercurial-Node']) - except TypeError: - m['Message-Id'] = genmsgid('patchbomb') - if parent: - m['In-Reply-To'] = parent - else: - parent = m['Message-Id'] - m['Date'] = time.strftime('%a, %e %b %Y %T ', time.localtime(start_time)) + tz - start_time += 1 - m['From'] = sender - m['To'] = ', '.join(to) - if cc: m['Cc'] = ', '.join(cc) - ui.status('Sending ', m['Subject'], ' ...\n') - if opts['test']: - fp = os.popen(os.getenv('PAGER', 'more'), 'w') - fp.write(m.as_string(0)) - fp.write('\n') - fp.close() - else: - s.sendmail(sender, to + cc, m.as_string(0)) - 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)
--- a/contrib/win32/ReadMe.html Fri Feb 03 11:23:34 2006 +0100 +++ b/contrib/win32/ReadMe.html Tue Feb 21 16:04:47 2006 +0100 @@ -5,7 +5,7 @@ </head> <body> - <h1>Mercurial version 0.7 for Windows</h1> + <h1>Mercurial version 0.8 for Windows</h1> <p>Welcome to Mercurial for Windows!</p>
--- a/contrib/win32/mercurial.iss Fri Feb 03 11:23:34 2006 +0100 +++ b/contrib/win32/mercurial.iss Tue Feb 21 16:04:47 2006 +0100 @@ -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 @@ 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
--- a/contrib/win32/postinstall.txt Fri Feb 03 11:23:34 2006 +0100 +++ b/contrib/win32/postinstall.txt Tue Feb 21 16:04:47 2006 +0100 @@ -8,6 +8,27 @@ 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:
--- a/doc/Makefile Fri Feb 03 11:23:34 2006 +0100 +++ b/doc/Makefile Tue Feb 21 16:04:47 2006 +0100 @@ -15,7 +15,7 @@ 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)
--- a/doc/hg.1.txt Fri Feb 03 11:23:34 2006 +0100 +++ b/doc/hg.1.txt Tue Feb 21 16:04:47 2006 +0100 @@ -223,9 +223,11 @@ probably with undesirable results. options: - -a, --text treat all files as text - -I, --include <pat> include names matching the given patterns - -X, --exclude <pat> exclude names matching the given patterns + -a, --text treat all files as text + -I, --include <pat> include names matching the given patterns + -p, --show-function show which function each change is in + -X, --exclude <pat> exclude names matching the given patterns + -w, --ignore-all-space ignore white space when comparing lines export [-o filespec] [revision] ...:: Print the changeset header and diffs for one or more revisions. @@ -374,6 +376,11 @@ options: -I, --include <pat> include names matching the given patterns -X, --exclude <pat> exclude names matching the given patterns + -b, --branch show branches + -k, --keyword <str> search for keywords + -l, --limit <num> print no more than this many changes + -M, --no-merges do not show merges + -m, --only-merges only show merges -r, --rev <A> show the specified revision or range -p, --patch show patch @@ -541,10 +548,12 @@ options: -A, --accesslog <file> name of access log file to write to + -d, --daemon run server in background, as a daemon -E, --errorlog <file> name of error log file to write to -a, --address <addr> address to use -p, --port <n> port to use (default: 8000) -n, --name <name> name to show in web pages (default: working dir) + --pid-file <file> write server process ID to given file -t, --templatedir <path> web templates to use -6, --ipv6 use IPv6 in addition to IPv4 @@ -600,9 +609,12 @@ This lists both regular and local tags. -tip:: +tip [-p]:: Show the tip revision. + options: + -p, --patch show patch + unbundle <file>:: (EXPERIMENTAL)
--- a/doc/hgrc.5.txt Fri Feb 03 11:23:34 2006 +0100 +++ b/doc/hgrc.5.txt Tue Feb 21 16:04:47 2006 +0100 @@ -141,20 +141,75 @@ [hooks] # do not use the site-wide hook - commit = - commit.email = /my/email/hook - commit.autobuild = /my/build/hook + incoming = + incoming.email = /my/email/hook + incoming.autobuild = /my/build/hook + + Most hooks are run with environment variables set that give added + useful information. For each hook below, the environment variables + it is passed are listed with names of the form "$HG_foo". changegroup;; - Run after a changegroup has been added via push or pull. Passed - the ID of the first new changeset in $NODE. + Run after a changegroup has been added via push, pull or + unbundle. ID of the first new changeset is in $HG_NODE. commit;; - Run after a changeset has been created or for each changeset - pulled. Passed the ID of the newly created changeset in - environment variable $NODE. + Run after a changeset has been created in the local repository. + ID of the newly created changeset is in $HG_NODE. Parent + changeset IDs are in $HG_PARENT1 and $HG_PARENT2. + incoming;; + Run after a changeset has been pulled, pushed, or unbundled into + the local repository. The ID of the newly arrived changeset is in + $HG_NODE. + outgoing;; + Run after sending changes from local repository to another. ID of + first changeset sent is in $HG_NODE. Source of operation is in + $HG_SOURCE; see "preoutgoing" hook for description. + prechangegroup;; + Run before a changegroup is added via push, pull or unbundle. + Exit status 0 allows the changegroup to proceed. Non-zero status + will cause the push, pull or unbundle to fail. precommit;; - Run before starting a commit. Exit status 0 allows the commit to - proceed. Non-zero status will cause the commit to fail. + Run before starting a local commit. Exit status 0 allows the + commit to proceed. Non-zero status will cause the commit to fail. + Parent changeset IDs are in $HG_PARENT1 and $HG_PARENT2. + preoutgoing;; + Run before computing changes to send from the local repository to + another. Non-zero status will cause failure. This lets you + prevent pull over http or ssh. Also prevents against local pull, + push (outbound) or bundle commands, but not effective, since you + can just copy files instead then. Source of operation is in + $HG_SOURCE. If "serve", operation is happening on behalf of + remote ssh or http repository. If "push", "pull" or "bundle", + operation is happening on behalf of repository on same system. + pretag;; + Run before creating a tag. Exit status 0 allows the tag to be + created. Non-zero status will cause the tag to fail. ID of + changeset to tag is in $HG_NODE. Name of tag is in $HG_TAG. Tag + is local if $HG_LOCAL=1, in repo if $HG_LOCAL=0. + pretxnchangegroup;; + Run after a changegroup has been added via push, pull or unbundle, + but before the transaction has been committed. Changegroup is + visible to hook program. This lets you validate incoming changes + before accepting them. Passed the ID of the first new changeset + in $HG_NODE. Exit status 0 allows the transaction to commit. + Non-zero status will cause the transaction to be rolled back and + the push, pull or unbundle will fail. + pretxncommit;; + Run after a changeset has been created but the transaction not yet + committed. Changeset is visible to hook program. This lets you + validate commit message and changes. Exit status 0 allows the + commit to proceed. Non-zero status will cause the transaction to + be rolled back. ID of changeset is in $HG_NODE. Parent changeset + IDs are in $HG_PARENT1 and $HG_PARENT2. + tag;; + Run after a tag is created. ID of tagged changeset is in + $HG_NODE. Name of tag is in $HG_TAG. Tag is local if + $HG_LOCAL=1, in repo if $HG_LOCAL=0. + + In earlier releases, the names of hook environment variables did not + have a "HG_" prefix. These unprefixed names are still provided in + the environment for backwards compatibility, but their use is + deprecated, and they will be removed in a future release. http_proxy:: Used to access web-based Mercurial repositories through a HTTP
--- a/hg Fri Feb 03 11:23:34 2006 +0100 +++ b/hg Tue Feb 21 16:04:47 2006 +0100 @@ -1,9 +1,8 @@ #!/usr/bin/env python # -# mercurial - a minimal scalable distributed SCM -# v0.6 "paola" +# mercurial - scalable distributed SCM # -# Copyright 2005 Matt Mackall <mpm@selenic.com> +# Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference.
--- a/hgeditor Fri Feb 03 11:23:34 2006 +0100 +++ b/hgeditor Tue Feb 21 16:04:47 2006 +0100 @@ -34,7 +34,6 @@ } ( - cd "`hg root`" grep '^HG: changed' "$1" | cut -b 13- | while read changed; do hg diff "$changed" >> "$HGTMP/diff" done
--- a/hgext/gpg.py Fri Feb 03 11:23:34 2006 +0100 +++ b/hgext/gpg.py Tue Feb 21 16:04:47 2006 +0100 @@ -1,6 +1,14 @@ -import os, tempfile, binascii, errno +# GnuPG signing extension for Mercurial +# +# Copyright 2005, 2006 Benoit Boissinot <benoit.boissinot@ens-lyon.org> +# +# 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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')), }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hgext/patchbomb.py Tue Feb 21 16:04:47 2006 +0100 @@ -0,0 +1,291 @@ +# 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. +# +# 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: +# +# The remainder of the changeset description. +# +# [Optional] If the diffstat program is installed, the result of +# running diffstat on the patch. +# +# The patch itself, as generated by "hg export". +# +# Each message refers to all of its predecessors using the In-Reply-To +# and References headers, so they will show up as a sequence in +# threaded mail and news readers, and in mail archives. +# +# For each changeset, you will be prompted with a diffstat summary and +# the changeset summary, so you can be sure you are sending the right +# changes. +# +# It is best to run this script with the "-n" (test only) flag before +# firing it up "for real", in which case it will use your pager to +# display each of the messages that it would send. +# +# The "-m" (mbox) option will create an mbox file instead of sending +# the messages directly. This can be reviewed e.g. with "mutt -R -f mbox", +# and finally sent with "formail -s sendmail -bm -t < mbox". +# +# To configure a default mail host, add a section like this to your +# hgrc file: +# +# [smtp] +# host = my_mail_host +# port = 1025 +# tls = yes # or omit if not needed +# username = user # if SMTP authentication required +# password = password # if SMTP authentication required - PLAINTEXT +# +# To configure other defaults, add a section like this to your hgrc +# file: +# +# [patchbomb] +# from = My Name <my@email> +# to = recipient1, recipient2, ... +# cc = cc1, cc2, ... + +from email.MIMEMultipart import MIMEMultipart +from email.MIMEText import MIMEText +from email.Utils import parseaddr +from mercurial import commands +from mercurial import hg +from mercurial import ui +from mercurial.i18n import gettext as _ +import os +import popen2 +import smtplib +import socket +import sys +import tempfile +import time + +try: + # readline gives raw_input editing capabilities, but is not + # present on windows + import readline +except ImportError: pass + +def diffstat(patch): + fd, name = tempfile.mkstemp() + try: + p = popen2.Popen3('diffstat -p1 -w79 2>/dev/null > ' + name) + try: + for line in patch: print >> p.tochild, line + p.tochild.close() + if p.wait(): return + fp = os.fdopen(fd, 'r') + stat = [] + for line in fp: stat.append(line.lstrip()) + last = stat.pop() + stat.insert(0, last) + stat = ''.join(stat) + if stat.startswith('0 files'): raise ValueError + return stat + except: raise + finally: + try: os.unlink(name) + 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 + while True: + r = raw_input(prompt) + if r: return r + if default is not None: return default + if empty_ok: return r + ui.warn(_('Please enter a valid value.\n')) + + def confirm(s): + if not prompt(s, default = 'y', rest = '? ').lower().startswith('y'): + raise ValueError + + def cdiffstat(summary, patch): + s = diffstat(patch) + if s: + if summary: + ui.write(summary, '\n') + ui.write(s, '\n') + confirm(_('Does the diffstat above look okay')) + return s + + def makepatch(patch, idx, total): + desc = [] + node = None + body = '' + for line in patch: + if line.startswith('#'): + if line.startswith('# Node ID'): node = line.split()[-1] + continue + if line.startswith('diff -r'): break + desc.append(line) + if not node: raise ValueError + + #body = ('\n'.join(desc[1:]).strip() or + # 'Patch subject is complete summary.') + #body += '\n\n\n' + + if opts['plain']: + while patch and patch[0].startswith('# '): patch.pop(0) + if patch: patch.pop(0) + while patch and not patch[0].strip(): patch.pop(0) + if opts['diffstat']: + body += cdiffstat('\n'.join(desc), patch) + '\n\n' + body += '\n'.join(patch) + msg = MIMEText(body) + subj = '[PATCH %d of %d] %s' % (idx, total, desc[0].strip()) + if subj.endswith('.'): subj = subj[:-1] + msg['Subject'] = subj + msg['X-Mercurial-Node'] = node + return msg + + start_time = int(time.time()) + + def genmsgid(id): + return '<%s.%s@%s>' % (id[:20], start_time, socket.getfqdn()) + + patches = [] + + 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 = [] + + 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)) + + 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')) + + sender = (opts['from'] or ui.config('patchbomb', 'from') or + prompt('From', ui.username())) + + msg = MIMEMultipart() + msg['Subject'] = '[PATCH 0 of %d] %s' % ( + len(patches), + opts['subject'] or + prompt('Subject:', rest = ' [PATCH 0 of %d] ' % len(patches))) + + def getaddrs(opt, prpt, default = None): + addrs = opts[opt] or (ui.config('patchbomb', opt) or + prompt(prpt, default = default)).split(',') + return [a.strip() for a in addrs if a.strip()] + to = getaddrs('to', 'To') + cc = getaddrs('cc', 'Cc', '') + + ui.write(_('Finish with ^D or a dot on a line by itself.\n\n')) + + body = [] + + while True: + try: l = raw_input() + except EOFError: break + if l == '.': break + body.append(l) + + msg.attach(MIMEText('\n'.join(body) + '\n')) + + ui.write('\n') + + if opts['diffstat']: + d = cdiffstat(_('Final summary:\n'), jumbo) + if d: msg.attach(MIMEText(d)) + + msgs.insert(0, msg) + + if not opts['test'] and not opts['mbox']: + s = smtplib.SMTP() + s.connect(host = ui.config('smtp', 'host', 'mail'), + port = int(ui.config('smtp', 'port', 25))) + if ui.configbool('smtp', 'tls'): + s.ehlo() + s.starttls() + s.ehlo() + username = ui.config('smtp', 'username') + password = ui.config('smtp', 'password') + if username and password: + s.login(username, password) + parent = None + tz = time.strftime('%z') + sender_addr = parseaddr(sender)[1] + for m in msgs: + try: + m['Message-Id'] = genmsgid(m['X-Mercurial-Node']) + except TypeError: + m['Message-Id'] = genmsgid('patchbomb') + if parent: + m['In-Reply-To'] = parent + else: + parent = m['Message-Id'] + m['Date'] = time.strftime('%a, %e %b %Y %T ', time.localtime(start_time)) + tz + start_time += 1 + m['From'] = sender + m['To'] = ', '.join(to) + if cc: m['Cc'] = ', '.join(cc) + if opts['test']: + ui.status('Displaying ', m['Subject'], ' ...\n') + fp = os.popen(os.getenv('PAGER', 'more'), 'w') + fp.write(m.as_string(0)) + fp.write('\n') + fp.close() + elif opts['mbox']: + ui.status('Writing ', m['Subject'], ' ...\n') + fp = open(opts['mbox'], m.has_key('In-Reply-To') and 'ab+' or 'wb+') + date = time.asctime(time.localtime(start_time)) + fp.write('From %s %s\n' % (sender_addr, date)) + fp.write(m.as_string(0)) + fp.write('\n\n') + fp.close() + else: + ui.status('Sending ', m['Subject'], ' ...\n') + s.sendmail(sender, to + cc, m.as_string(0)) + if not opts['test'] and not opts['mbox']: + s.close() + +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'), + ('m', 'mbox', '', 'write messages to mbox file instead of sending them'), + ('s', 'subject', '', 'subject of introductory message'), + ('t', 'to', [], 'email addresses of recipients')], + "hg email [OPTION]... [REV]...") + }
--- a/hgmerge Fri Feb 03 11:23:34 2006 +0100 +++ b/hgmerge Tue Feb 21 16:04:47 2006 +0100 @@ -17,127 +17,151 @@ # find decent versions of our utilities, insisting on the GNU versions where we # need to +MERGE=merge DIFF3=gdiff3 DIFF=gdiff PATCH=gpatch +type $MERGE >/dev/null 2>&1 || MERGE= type $DIFF3 >/dev/null 2>&1 || DIFF3=diff3 type $DIFF >/dev/null 2>&1 || DIFF=diff -type $PATCH >/dev/null 2>&1 || PATCH=patch +type $PATCH >/dev/null 2>&1 || PATCH=patch $DIFF3 --version >/dev/null 2>&1 || DIFF3= -# Back up our file -cp "$LOCAL" "$LOCAL.orig" +# find optional visual utilities +FILEMERGE='/Developer/Applications/Utilities/FileMerge.app/Contents/MacOS/FileMerge' +KDIFF3=kdiff3 +TKDIFF=tkdiff + +type $FILEMERGE >/dev/null 2>&1 || FILEMERGE= +type $KDIFF3 >/dev/null 2>&1 || KDIFF3= +type $TKDIFF >/dev/null 2>&1 || TKDIFF= + +# random part of names +RAND="$RANDOM.$RANDOM.$RANDOM.$$" + +# temporary directory for diff+patch merge +HGTMP="${TMPDIR-/tmp}/hgmerge.$RAND" + +# backup file +BACKUP="$LOCAL.orig.$RAND" + +# file used to test for file change +CHGTEST="$LOCAL.chg.$RAND" + +# put all your required cleanup here +cleanup() { + rm -f "$BACKUP" "$CHGTEST" + rm -rf "$HGTMP" +} + +# functions concerning program exit +success() { + cleanup + exit 0 +} + +failure() { + echo "merge failed" 1>&2 + mv "$BACKUP" "$LOCAL" + cleanup + exit 1 +} + +# Clean up when interrupted +trap "failure" 1 2 3 6 15 # HUP INT QUIT ABRT TERM + +# Back up our file (and try hard to keep the mtime unchanged) +mv "$LOCAL" "$BACKUP" +cp "$BACKUP" "$LOCAL" # Attempt to do a non-interactive merge -if type merge > /dev/null 2>&1; then - merge "$LOCAL" "$BASE" "$OTHER" 2> /dev/null && exit 0 - cp "$LOCAL.orig" "$LOCAL" +if [ -n "$MERGE" ]; then + $MERGE "$LOCAL" "$BASE" "$OTHER" 2> /dev/null && success + cp "$BACKUP" "$LOCAL" elif [ -n "$DIFF3" ]; then - echo $DIFF3 -m "$LOCAL.orig" "$BASE" "$OTHER" - $DIFF3 -m "$LOCAL.orig" "$BASE" "$OTHER" > "$LOCAL" && exit 0 + echo $DIFF3 -m "$BACKUP" "$BASE" "$OTHER" + $DIFF3 -m "$BACKUP" "$BASE" "$OTHER" > "$LOCAL" && success if [ $? -eq 2 ]; then echo "$DIFF3 failed! Exiting." 1>&2 - cp "$LOCAL.orig" "$LOCAL" - exit 1 + cp "$BACKUP" "$LOCAL" + failure fi - cp "$LOCAL.orig" "$LOCAL" + cp "$BACKUP" "$LOCAL" fi # on MacOS X try FileMerge.app, shipped with Apple's developer tools -# TODO: make proper temp files. foo.orig and foo.link are dangerous -FILEMERGE='/Developer/Applications/Utilities/FileMerge.app/Contents/MacOS/FileMerge' -if type "$FILEMERGE" > /dev/null 2>&1; then - cp "$LOCAL.orig" "$LOCAL" - ln "$LOCAL" "$LOCAL.link" +if [ -n "$FILEMERGE" ]; then + cp "$BACKUP" "$LOCAL" + cp "$BACKUP" "$CHGTEST" # filemerge prefers the right by default - if ! "$FILEMERGE" -left "$OTHER" -right "$LOCAL" -ancestor "$BASE" -merge "$LOCAL" + $FILEMERGE -left "$OTHER" -right "$LOCAL" -ancestor "$BASE" -merge "$LOCAL" + [ $? -ne 0 ] && echo "FileMerge failed to launch" && failure + if test "$LOCAL" -nt "$CHGTEST" then - echo "FileMerge failed to launch" - exit 1 - fi - if ! test "$LOCAL" -ef "$LOCAL.link" - then - rm "$LOCAL.orig" "$LOCAL.link" - exit 0 + success else - rm "$LOCAL.link" - echo "$LOCAL is unchanged. Was the merge successful?" + echo "$LOCAL seems unchanged. Was the merge successful?" select answer in yes no do - if test "$answer" == "yes" - then - rm "$LOCAL.orig" - exit 0 - else - exit 1 - fi + test "$answer" == "yes" && success || failure done - exit 1 fi + failure fi if [ -n "$DISPLAY" ]; then # try using kdiff3, which is fairly nice - if type kdiff3 > /dev/null 2>&1; then - kdiff3 --auto "$BASE" "$LOCAL" "$OTHER" -o "$LOCAL" || exit 1 - exit 0 + if [ -n "$KDIFF3" ]; then + $KDIFF3 --auto "$BASE" "$LOCAL" "$OTHER" -o "$LOCAL" || failure + success fi # try using tkdiff, which is a bit less sophisticated - if type tkdiff > /dev/null 2>&1; then - tkdiff "$LOCAL" "$OTHER" -a "$BASE" -o "$LOCAL" || exit 1 - exit 0 + if [ -n "$TKDIFF" ]; then + $TKDIFF "$LOCAL" "$OTHER" -a "$BASE" -o "$LOCAL" || failure + success fi fi # Attempt to do a merge with $EDITOR -if type merge > /dev/null 2>&1; then +if [ -n "$MERGE" ]; then echo "conflicts detected in $LOCAL" - merge "$LOCAL" "$BASE" "$OTHER" 2>/dev/null || $EDITOR "$LOCAL" - exit 0 + $MERGE "$LOCAL" "$BASE" "$OTHER" 2>/dev/null || $EDITOR "$LOCAL" + success fi if [ -n "$DIFF3" ]; then echo "conflicts detected in $LOCAL" - $DIFF3 -m "$LOCAL.orig" "$BASE" "$OTHER" > "$LOCAL" || { + $DIFF3 -m "$BACKUP" "$BASE" "$OTHER" > "$LOCAL" || { case $? in 1) $EDITOR "$LOCAL" ;; 2) echo "$DIFF3 failed! Exiting." 1>&2 - cp "$LOCAL.orig" "$LOCAL" - exit 1 ;; + cp "$BACKUP" "$LOCAL" + failure ;; esac - exit 0 + success } fi -HGTMP="" -cleanup_exit() { - rm -rf "$HGTMP" -} - # attempt to manually merge with diff and patch if [ -n "$DIFF" -a -n "$PATCH" ]; then - # Remove temporary files even if we get interrupted - trap "cleanup_exit" 0 # normal exit - trap "exit 1" 1 2 3 6 15 # HUP INT QUIT ABRT TERM - HGTMP="${TMPDIR-/tmp}/hgmerge.$RANDOM.$RANDOM.$RANDOM.$$" (umask 077 && mkdir "$HGTMP") || { - echo "Could not create temporary directory! Exiting." 1>&2 - exit 1 + echo "Could not create temporary directory $HGTMP" 1>&2 + failure } $DIFF -u "$BASE" "$OTHER" > "$HGTMP/diff" || : if $PATCH "$LOCAL" < "$HGTMP/diff"; then - exit 0 + success else # If rejects are empty after using the editor, merge was ok - $EDITOR "$LOCAL" "$LOCAL.rej" && test -s "$LOCAL.rej" || exit 0 + $EDITOR "$LOCAL" "$LOCAL.rej" && test -s "$LOCAL.rej" || success fi - exit 1 + failure fi echo "hgmerge: unable to find merge, tkdiff, kdiff3, or diff+patch!" -exit 1 +failure
--- a/mercurial/commands.py Fri Feb 03 11:23:34 2006 +0100 +++ b/mercurial/commands.py Tue Feb 21 16:04:47 2006 +0100 @@ -115,8 +115,8 @@ yield rev minrev, maxrev = min(revs), max(revs) - for file in files: - filelog = repo.file(file) + for file_ in files: + filelog = repo.file(file_) # A zero count may be a directory or deleted file, so # try to find matching entries on the slow path. if filelog.count() == 0: @@ -127,7 +127,7 @@ if rev < minrev: break fncache.setdefault(rev, []) - fncache[rev].append(file) + fncache[rev].append(file_) wanted[rev] = 1 if slowpath: # The slow path checks files modified in every changeset. @@ -261,7 +261,7 @@ mode) def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always, - changes=None, text=False): + changes=None, text=False, opts={}): if not changes: changes = repo.changes(node1, node2, files, match=match) modified, added, removed, deleted, unknown = changes @@ -296,8 +296,8 @@ date1 = util.datestr(change[2]) diffopts = ui.diffopts() - showfunc = diffopts['showfunc'] - ignorews = diffopts['ignorews'] + showfunc = opts.get('show_function') or diffopts['showfunc'] + ignorews = opts.get('ignore_all_space') or diffopts['ignorews'] for f in modified: to = None if f in mmap: @@ -405,6 +405,8 @@ # description doc = i[0].__doc__ + if not doc: + doc = _("(No help text available)") if ui.quiet: doc = doc.splitlines(0)[0] ui.write("%s\n" % doc.rstrip()) @@ -445,10 +447,10 @@ f = f.lstrip("^") if not ui.debugflag and f.startswith("debug"): continue - d = "" - if e[0].__doc__: - d = e[0].__doc__.splitlines(0)[0].rstrip() - h[f] = d + doc = e[0].__doc__ + if not doc: + doc = _("(No help text available)") + h[f] = doc.splitlines(0)[0].rstrip() cmds[f] = c.lstrip("^") fns = h.keys() @@ -516,6 +518,9 @@ New files are ignored if they match any of the patterns in .hgignore. As with add, these changes take effect at the next commit. """ + return addremove_lock(ui, repo, pats, opts) + +def addremove_lock(ui, repo, pats, opts, wlock=None): add, remove = [], [] for src, abs, rel, exact in walk(repo, pats, opts): if src == 'f' and repo.dirstate.state(abs) == '?': @@ -526,8 +531,8 @@ remove.append(abs) if ui.verbose or not exact: ui.status(_('removing %s\n') % ((pats and rel) or abs)) - repo.add(add) - repo.remove(remove) + repo.add(add, wlock=wlock) + repo.remove(remove, wlock=wlock) def annotate(ui, repo, *pats, **opts): """show changeset information per file line @@ -616,7 +621,7 @@ dest = ui.expandpath(dest, repo.root) other = hg.repository(ui, dest) o = repo.findoutgoing(other) - cg = repo.changegroup(o) + cg = repo.changegroup(o, 'bundle') try: f.write("HG10") @@ -719,8 +724,8 @@ # can end up with extra data in the cloned revlogs that's # not pointed to by changesets, thus causing verify to # fail - l1 = lock.lock(os.path.join(source, ".hg", "lock")) - except OSError: + l1 = other.lock() + except lock.LockException: copy = False if copy: @@ -812,14 +817,19 @@ reasons = {'?': _('is not managed'), 'a': _('has been marked for add'), 'r': _('has been marked for remove')} - reason = reasons.get(repo.dirstate.state(abs)) + state = repo.dirstate.state(abs) + reason = reasons.get(state) if reason: + if state == 'a': + origsrc = repo.dirstate.copied(abs) + if origsrc is not None: + return origsrc if exact: ui.warn(_('%s: not copying - file %s\n') % (rel, reason)) else: - return True - - def copy(abssrc, relsrc, target, exact): + return abs + + def copy(origsrc, abssrc, relsrc, target, exact): abstarget = util.canonpath(repo.root, cwd, target) reltarget = util.pathto(cwd, abstarget) prevsrc = targets.get(abstarget) @@ -858,7 +868,7 @@ if ui.verbose or not exact: ui.status(_('copying %s to %s\n') % (relsrc, reltarget)) targets[abstarget] = abssrc - repo.copy(abssrc, abstarget) + repo.copy(origsrc, abstarget) copied.append((abssrc, relsrc, exact)) def targetpathfn(pat, dest, srcs): @@ -932,8 +942,9 @@ for pat in pats: srcs = [] for tag, abssrc, relsrc, exact in walk(repo, [pat], opts): - if okaytocopy(abssrc, relsrc, exact): - srcs.append((abssrc, relsrc, exact)) + origsrc = okaytocopy(abssrc, relsrc, exact) + if origsrc: + srcs.append((origsrc, abssrc, relsrc, exact)) if not srcs: continue copylist.append((tfn(pat, dest, srcs), srcs)) @@ -941,8 +952,8 @@ raise util.Abort(_('no files to copy')) for targetpath, srcs in copylist: - for abssrc, relsrc, exact in srcs: - copy(abssrc, relsrc, targetpath(abssrc), exact) + for origsrc, abssrc, relsrc, exact in srcs: + copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact) if errors: ui.warn(_('(consider using --after)\n')) @@ -974,6 +985,18 @@ a = r.ancestor(r.lookup(rev1), r.lookup(rev2)) ui.write("%d:%s\n" % (r.rev(a), hex(a))) +def debugrebuildstate(ui, repo, rev=None): + """rebuild the dirstate as it would look like for the given revision""" + if not rev: + rev = repo.changelog.tip() + else: + rev = repo.lookup(rev) + change = repo.changelog.read(rev) + n = change[0] + files = repo.manifest.readflags(n) + wlock = repo.wlock() + repo.dirstate.rebuild(rev, files.iteritems()) + def debugcheckstate(ui, repo): """validate the correctness of the current dirstate""" parent1, parent2 = repo.dirstate.parents() @@ -1134,7 +1157,7 @@ fns, matchfn, anypats = matchpats(repo, pats, opts) dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn, - text=opts['text']) + text=opts['text'], opts=opts) def doexport(ui, repo, changeset, seqno, total, revwidth, opts): node = repo.lookup(changeset) @@ -1278,6 +1301,7 @@ s = linestate(line, lnum, cstart, cend) m[s] = s + # FIXME: prev isn't used, why ? prev = {} ucache = {} def display(fn, rev, states, prevstates): @@ -1587,7 +1611,19 @@ self.write(*args) def __getattr__(self, key): return getattr(self.ui, key) + changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts) + + if opts['limit']: + try: + limit = int(opts['limit']) + except ValueError: + raise util.Abort(_('limit must be a positive integer')) + if limit <= 0: raise util.Abort(_('limit must be positive')) + else: + limit = sys.maxint + count = 0 + for st, rev, fns in changeiter: if st == 'window': du = dui(ui) @@ -1601,7 +1637,6 @@ if opts['only_merges'] and len(parents) != 2: continue - br = None if opts['keyword']: changes = getchange(rev) miss = 0 @@ -1614,7 +1649,8 @@ if miss: continue - if opts['branch']: + br = None + if opts['branches']: br = repo.branchlookup([repo.changelog.node(rev)]) show_changeset(du, repo, rev, brinfo=br) @@ -1623,8 +1659,11 @@ dodiff(du, du, repo, prev, changenode, match=matchfn) du.write("\n\n") elif st == 'iter': - for args in du.hunk[rev]: - ui.write(*args) + if count == limit: break + if du.hunk[rev]: + count += 1 + for args in du.hunk[rev]: + ui.write(*args) def manifest(ui, repo, rev=None): """output the latest or given revision of the project manifest @@ -1675,7 +1714,7 @@ dodiff(ui, ui, repo, prev, n) ui.write("\n") -def parents(ui, repo, rev=None): +def parents(ui, repo, rev=None, branches=None): """show the parents of the working dir or revision Print the working directory's parent revisions. @@ -1685,9 +1724,12 @@ else: p = repo.dirstate.parents() + br = None + if branches is not None: + br = repo.branchlookup(p) for n in p: if n != nullid: - show_changeset(ui, repo, changenode=n) + show_changeset(ui, repo, changenode=n, brinfo=br) def paths(ui, search=None): """show definition of symbolic path names @@ -1990,7 +2032,7 @@ arg, roots = getarg() nodes = map(bin, roots.split(" ")) - cg = repo.changegroup(nodes) + cg = repo.changegroup(nodes, 'serve') while 1: d = cg.read(4096) if not d: @@ -2013,6 +2055,16 @@ if opts[o]: ui.setconfig("web", o, opts[o]) + if opts['daemon'] and not opts['daemon_pipefds']: + rfd, wfd = os.pipe() + args = sys.argv[:] + args.append('--daemon-pipefds=%d,%d' % (rfd, wfd)) + pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0), + args[0], args) + os.close(wfd) + os.read(rfd, 1) + os._exit(0) + try: httpd = hgweb.create_server(repo) except socket.error, inst: @@ -2031,6 +2083,25 @@ ui.status(_('listening at http://%s:%d/\n') % (addr, port)) else: ui.status(_('listening at http://%s/\n') % addr) + + if opts['pid_file']: + fp = open(opts['pid_file'], 'w') + fp.write(str(os.getpid())) + fp.close() + + if opts['daemon_pipefds']: + rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')] + os.close(rfd) + os.write(wfd, 'y') + os.close(wfd) + sys.stdout.flush() + sys.stderr.flush() + fd = os.open(util.nulldev, os.O_RDWR) + if fd != 0: os.dup2(fd, 0) + if fd != 1: os.dup2(fd, 1) + if fd != 2: os.dup2(fd, 2) + if fd not in (0, 1, 2): os.close(fd) + httpd.serve_forever() def status(ui, repo, *pats, **opts): @@ -2107,8 +2178,12 @@ if name.find(c) >= 0: raise util.Abort(_("%s cannot be used in a tag name") % repr(c)) + repo.hook('pretag', throw=True, node=r, tag=name, + local=int(not not opts['local'])) + if opts['local']: repo.opener("localtags", "a").write("%s %s\n" % (r, name)) + repo.hook('tag', node=r, tag=name, local=1) return for x in repo.changes(): @@ -2124,6 +2199,7 @@ _("Added tag %s for changeset %s") % (name, r)) try: repo.commit([".hgtags"], message, opts['user'], opts['date']) + repo.hook('tag', node=r, tag=name, local=0) except ValueError, inst: raise util.Abort(str(inst)) @@ -2144,13 +2220,18 @@ r = " ?:?" ui.write("%-30s %s\n" % (t, r)) -def tip(ui, repo): +def tip(ui, repo, **opts): """show the tip revision Show the tip revision. """ n = repo.changelog.tip() - show_changeset(ui, repo, changenode=n) + br = None + if opts['branches']: + br = repo.branchlookup([n]) + show_changeset(ui, repo, changenode=n, brinfo=br) + if opts['patch']: + dodiff(ui, ui, repo, repo.changelog.parents(n)[0], n) def unbundle(ui, repo, fname, **opts): """apply a changegroup file @@ -2308,6 +2389,10 @@ _('forcibly copy over an existing managed file'))], _('hg copy [OPTION]... [SOURCE]... DEST')), "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')), + "debugrebuildstate": + (debugrebuildstate, + [('r', 'rev', "", _("revision to rebuild to"))], + _('debugrebuildstate [-r REV] [REV]')), "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')), "debugconfig": (debugconfig, [], _('debugconfig')), "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')), @@ -2326,7 +2411,12 @@ [('r', 'rev', [], _('revision')), ('a', 'text', None, _('treat all files as text')), ('I', 'include', [], _('include names matching the given patterns')), - ('X', 'exclude', [], _('exclude names matching the given patterns'))], + ('p', 'show-function', None, + _('show which function each change is in')), + ('w', 'ignore-all-space', None, + _('ignore white space when comparing lines')), + ('X', 'exclude', [], + _('exclude names matching the given patterns'))], _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')), "^export": (export, @@ -2354,7 +2444,7 @@ _('hg grep [OPTION]... PATTERN [FILE]...')), "heads": (heads, - [('b', 'branches', None, _('find branch info')), + [('b', 'branches', None, _('show branches')), ('r', 'rev', '', _('show only heads which are descendants of rev'))], _('hg heads [-b] [-r <rev>]')), "help": (help_, [], _('hg help [COMMAND]')), @@ -2388,8 +2478,9 @@ (log, [('I', 'include', [], _('include names matching the given patterns')), ('X', 'exclude', [], _('exclude names matching the given patterns')), - ('b', 'branch', None, _('show branches')), + ('b', 'branches', None, _('show branches')), ('k', 'keyword', [], _('search for a keyword')), + ('l', 'limit', '', _('limit number of changes displayed')), ('r', 'rev', [], _('show the specified revision or range')), ('M', 'no-merges', None, _('do not show merges')), ('m', 'only-merges', None, _('show only merges')), @@ -2401,7 +2492,10 @@ ('p', 'patch', None, _('show patch')), ('n', 'newest-first', None, _('show newest record first'))], _('hg outgoing [-p] [-n] [-M] [DEST]')), - "^parents": (parents, [], _('hg parents [REV]')), + "^parents": + (parents, + [('b', 'branches', None, _('show branches'))], + _('hg parents [-b] [REV]')), "paths": (paths, [], _('hg paths [NAME]')), "^pull": (pull, @@ -2452,11 +2546,14 @@ "^serve": (serve, [('A', 'accesslog', '', _('name of access log file to write to')), + ('d', 'daemon', None, _('run server in background')), + ('', 'daemon-pipefds', '', _('used internally by daemon mode')), ('E', 'errorlog', '', _('name of error log file to write to')), ('p', 'port', 0, _('port to use (default: 8000)')), ('a', 'address', '', _('address to use')), ('n', 'name', '', _('name to show in web pages (default: working dir)')), + ('', 'pid-file', '', _('name of file to write process ID to')), ('', 'stdio', None, _('for remote clients')), ('t', 'templates', '', _('web templates to use')), ('', 'style', '', _('template style to use')), @@ -2484,7 +2581,11 @@ ('r', 'rev', '', _('revision to tag'))], _('hg tag [-r REV] [OPTION]... NAME')), "tags": (tags, [], _('hg tags')), - "tip": (tip, [], _('hg tip')), + "tip": + (tip, + [('b', 'branches', None, _('show branches')), + ('p', 'patch', None, _('show patch'))], + _('hg [-b] [-p] tip')), "unbundle": (unbundle, [('u', 'update', None, @@ -2524,17 +2625,20 @@ def find(cmd): """Return (aliases, command table entry) for command string.""" choice = None + count = 0 for e in table.keys(): aliases = e.lstrip("^").split("|") if cmd in aliases: return aliases, table[e] for a in aliases: if a.startswith(cmd): - if choice: - raise AmbiguousCommand(cmd) - else: - choice = aliases, table[e] - break + count += 1 + choice = aliases, table[e] + break + + if count > 1: + raise AmbiguousCommand(cmd) + if choice: return choice
--- a/mercurial/dirstate.py Fri Feb 03 11:23:34 2006 +0100 +++ b/mercurial/dirstate.py Tue Feb 21 16:04:47 2006 +0100 @@ -197,6 +197,19 @@ def clear(self): self.map = {} + self.copies = {} + self.markdirty() + + def rebuild(self, parent, files): + self.clear() + umask = os.umask(0) + os.umask(umask) + for f, mode in files: + if mode: + self.map[f] = ('n', ~umask, -1, 0) + else: + self.map[f] = ('n', ~umask & 0666, -1, 0) + self.pl = (parent, nullid) self.markdirty() def write(self): @@ -270,11 +283,11 @@ elif not dc: dc = self.filterfiles(files) - def statmatch(file, stat): - file = util.pconvert(file) - if file not in dc and self.ignore(file): + def statmatch(file_, stat): + file_ = util.pconvert(file_) + if file_ not in dc and self.ignore(file_): return False - return match(file) + return match(file_) return self.walkhelper(files=files, statmatch=statmatch, dc=dc) @@ -350,9 +363,9 @@ continue if stat.S_ISDIR(st.st_mode): cmp1 = (lambda x, y: cmp(x[1], y[1])) - sorted = [ x for x in findfiles(f) ] - sorted.sort(cmp1) - for e in sorted: + sorted_ = [ x for x in findfiles(f) ] + sorted_.sort(cmp1) + for e in sorted_: yield e else: ff = util.normpath(ff) @@ -380,7 +393,7 @@ for src, fn, st in self.statwalk(files, match): try: - type, mode, size, time = self[fn] + type_, mode, size, time = self[fn] except KeyError: unknown.append(fn) continue @@ -399,22 +412,23 @@ nonexistent = False # XXX: what to do with file no longer present in the fs # who are not removed in the dirstate ? - if nonexistent and type in "nm": + if nonexistent and type_ in "nm": deleted.append(fn) continue # check the common case first - if type == 'n': + if type_ == 'n': if not st: st = os.stat(fn) - if size != st.st_size or (mode ^ st.st_mode) & 0100: + if size >= 0 and (size != st.st_size + or (mode ^ st.st_mode) & 0100): modified.append(fn) elif time != st.st_mtime: lookup.append(fn) - elif type == 'm': + elif type_ == 'm': modified.append(fn) - elif type == 'a': + elif type_ == 'a': added.append(fn) - elif type == 'r': + elif type_ == 'r': removed.append(fn) return (lookup, modified, added, removed, deleted, unknown)
--- a/mercurial/hgweb.py Fri Feb 03 11:23:34 2006 +0100 +++ b/mercurial/hgweb.py Tue Feb 21 16:04:47 2006 +0100 @@ -298,19 +298,25 @@ def changelog(self, pos): def changenav(**map): - def seq(factor=1): - yield 1 * factor - yield 3 * factor - #yield 5 * factor + def seq(factor, maxchanges=None): + if maxchanges: + yield maxchanges + if maxchanges >= 20 and maxchanges <= 40: + yield 50 + else: + yield 1 * factor + yield 3 * factor for f in seq(factor * 10): yield f l = [] - for f in seq(): - if f < self.maxchanges / 2: + last = 0 + for f in seq(1, self.maxchanges): + if f < self.maxchanges or f <= last: continue if f > count: break + last = f r = "%d" % f if pos + f < count: l.append(("+" + r, pos + f)) @@ -958,7 +964,7 @@ nodes = map(bin, req.form['roots'][0].split(" ")) z = zlib.compressobj() - f = self.repo.changegroup(nodes) + f = self.repo.changegroup(nodes, 'serve') while 1: chunk = f.read(4096) if not chunk:
--- a/mercurial/httprepo.py Fri Feb 03 11:23:34 2006 +0100 +++ b/mercurial/httprepo.py Tue Feb 21 16:04:47 2006 +0100 @@ -119,7 +119,7 @@ self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n") raise - def changegroup(self, nodes): + def changegroup(self, nodes, kind): n = " ".join(map(hex, nodes)) f = self.do_cmd("changegroup", roots=n) bytes = 0
--- a/mercurial/localrepo.py Fri Feb 03 11:23:34 2006 +0100 +++ b/mercurial/localrepo.py Tue Feb 21 16:04:47 2006 +0100 @@ -48,30 +48,36 @@ except IOError: pass - def hook(self, name, **args): + def hook(self, name, throw=False, **args): def runhook(name, cmd): self.ui.note(_("running hook %s: %s\n") % (name, cmd)) old = {} for k, v in args.items(): k = k.upper() + old['HG_' + k] = os.environ.get(k, None) old[k] = os.environ.get(k, None) - os.environ[k] = v + os.environ['HG_' + k] = str(v) + os.environ[k] = str(v) - # Hooks run in the repository root - olddir = os.getcwd() - os.chdir(self.root) - r = os.system(cmd) - os.chdir(olddir) + try: + # Hooks run in the repository root + olddir = os.getcwd() + os.chdir(self.root) + r = os.system(cmd) + finally: + for k, v in old.items(): + if v is not None: + os.environ[k] = v + else: + del os.environ[k] - for k, v in old.items(): - if v != None: - os.environ[k] = v - else: - del os.environ[k] + os.chdir(olddir) if r: - self.ui.warn(_("abort: %s hook failed with status %d!\n") % - (name, r)) + desc, r = util.explain_exit(r) + if throw: + raise util.Abort(_('%s hook %s') % (name, desc)) + self.ui.warn(_('error: %s hook %s\n') % (name, desc)) return False return True @@ -225,7 +231,7 @@ self.join("journal"), after) def recover(self): - lock = self.lock() + l = self.lock() if os.path.exists(self.join("journal")): self.ui.status(_("rolling back interrupted transaction\n")) transaction.rollback(self.opener, self.join("journal")) @@ -236,9 +242,10 @@ self.ui.warn(_("no interrupted transaction available\n")) return False - def undo(self): - wlock = self.wlock() - lock = self.lock() + def undo(self, wlock=None): + if not wlock: + wlock = self.wlock() + l = self.lock() if os.path.exists(self.join("undo")): self.ui.status(_("rolling back last transaction\n")) transaction.rollback(self.opener, self.join("undo")) @@ -247,27 +254,46 @@ else: self.ui.warn(_("no undo information available\n")) - def lock(self, wait=1): + def do_lock(self, lockname, wait, releasefn=None, acquirefn=None): try: - return lock.lock(self.join("lock"), 0) - except lock.LockHeld, inst: - if wait: - self.ui.warn(_("waiting for lock held by %s\n") % inst.args[0]) - return lock.lock(self.join("lock"), wait) - raise inst - - def wlock(self, wait=1): - try: - wlock = lock.lock(self.join("wlock"), 0, self.dirstate.write) + l = lock.lock(self.join(lockname), 0, releasefn) except lock.LockHeld, inst: if not wait: raise inst self.ui.warn(_("waiting for lock held by %s\n") % inst.args[0]) - wlock = lock.lock(self.join("wlock"), wait, self.dirstate.write) - self.dirstate.read() - return wlock + l = lock.lock(self.join(lockname), wait, releasefn) + if acquirefn: + acquirefn() + return l + + def lock(self, wait=1): + return self.do_lock("lock", wait) + + def wlock(self, wait=1): + return self.do_lock("wlock", wait, + self.dirstate.write, + self.dirstate.read) - def rawcommit(self, files, text, user, date, p1=None, p2=None): + def checkfilemerge(self, filename, text, filelog, manifest1, manifest2): + "determine whether a new filenode is needed" + fp1 = manifest1.get(filename, nullid) + fp2 = manifest2.get(filename, nullid) + + if fp2 != nullid: + # is one parent an ancestor of the other? + fpa = filelog.ancestor(fp1, fp2) + if fpa == fp1: + fp1, fp2 = fp2, nullid + elif fpa == fp2: + fp2 = nullid + + # is the file unmodified from the parent? report existing entry + if fp2 == nullid and text == filelog.read(fp1): + return (fp1, None, None) + + return (None, fp1, fp2) + + def rawcommit(self, files, text, user, date, p1=None, p2=None, wlock=None): orig_parent = self.dirstate.parents()[0] or nullid p1 = p1 or self.dirstate.parents()[0] or nullid p2 = p2 or self.dirstate.parents()[1] or nullid @@ -283,8 +309,9 @@ else: update_dirstate = 0 - wlock = self.wlock() - lock = self.lock() + if not wlock: + wlock = self.wlock() + l = self.lock() tr = self.transaction() mm = m1.copy() mfm = mf1.copy() @@ -296,27 +323,10 @@ r = self.file(f) mfm[f] = tm - fp1 = m1.get(f, nullid) - fp2 = m2.get(f, nullid) - - # is the same revision on two branches of a merge? - if fp2 == fp1: - fp2 = nullid - - if fp2 != nullid: - # is one parent an ancestor of the other? - fpa = r.ancestor(fp1, fp2) - if fpa == fp1: - fp1, fp2 = fp2, nullid - elif fpa == fp2: - fp2 = nullid - - # is the file unmodified from the parent? - if t == r.read(fp1): - # record the proper existing parent in manifest - # no need to add a revision - mm[f] = fp1 - continue + (entry, fp1, fp2) = self.checkfilemerge(f, t, r, m1, m2) + if entry: + mm[f] = entry + continue mm[f] = r.add(t, {}, tr, linkrev, fp1, fp2) changed.append(f) @@ -340,7 +350,7 @@ self.dirstate.setparents(n, nullid) def commit(self, files=None, text="", user=None, date=None, - match=util.always, force=False): + match=util.always, force=False, wlock=None): commit = [] remove = [] changed = [] @@ -370,11 +380,15 @@ self.ui.status(_("nothing changed\n")) return None - if not self.hook("precommit"): - return None + xp1 = hex(p1) + if p2 == nullid: xp2 = '' + else: xp2 = hex(p2) - wlock = self.wlock() - lock = self.lock() + self.hook("precommit", throw=True, parent1=xp1, parent2=xp2) + + if not wlock: + wlock = self.wlock() + l = self.lock() tr = self.transaction() # check in files @@ -400,22 +414,9 @@ self.ui.debug(_(" %s: copy %s:%s\n") % (f, cp, meta["copyrev"])) fp1, fp2 = nullid, nullid else: - fp1 = m1.get(f, nullid) - fp2 = m2.get(f, nullid) - - if fp2 != nullid: - # is one parent an ancestor of the other? - fpa = r.ancestor(fp1, fp2) - if fpa == fp1: - fp1, fp2 = fp2, nullid - elif fpa == fp2: - fp2 = nullid - - # is the file unmodified from the parent? - if not meta and t == r.read(fp1) and fp2 == nullid: - # record the proper existing parent in manifest - # no need to add a revision - new[f] = fp1 + entry, fp1, fp2 = self.checkfilemerge(f, t, r, m1, m2) + if entry: + new[f] = entry continue new[f] = r.add(t, meta, tr, linkrev, fp1, fp2) @@ -437,29 +438,34 @@ new.sort() if not text: - edittext = "" + edittext = [""] if p2 != nullid: - edittext += "HG: branch merge\n" - edittext += "\n" + "HG: manifest hash %s\n" % hex(mn) - edittext += "".join(["HG: changed %s\n" % f for f in changed]) - edittext += "".join(["HG: removed %s\n" % f for f in remove]) + edittext.append("HG: branch merge") + edittext.extend(["HG: changed %s" % f for f in changed]) + edittext.extend(["HG: removed %s" % f for f in remove]) if not changed and not remove: - edittext += "HG: no files changed\n" - edittext = self.ui.edit(edittext) + edittext.append("HG: no files changed") + edittext.append("") + # run editor in the repository root + olddir = os.getcwd() + os.chdir(self.root) + edittext = self.ui.edit("\n".join(edittext)) + os.chdir(olddir) if not edittext.rstrip(): return None text = edittext user = user or self.ui.username() n = self.changelog.add(mn, changed + remove, text, tr, p1, p2, user, date) + self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1, + parent2=xp2) tr.close() self.dirstate.setparents(n) self.dirstate.update(new, "n") self.dirstate.forget(remove) - if not self.hook("commit", node=hex(n)): - return None + self.hook("commit", node=hex(n), parent1=xp1, parent2=xp2) return n def walk(self, node=None, files=[], match=util.always): @@ -476,7 +482,8 @@ for src, fn in self.dirstate.walk(files, match): yield src, fn - def changes(self, node1=None, node2=None, files=[], match=util.always): + def changes(self, node1=None, node2=None, files=[], match=util.always, + wlock=None): """return changes between two nodes or node and working directory If node1 is None, use the first dirstate parent instead. @@ -498,10 +505,11 @@ # are we comparing the working directory? if not node2: - try: - wlock = self.wlock(wait=0) - except lock.LockHeld: - wlock = None + if not wlock: + try: + wlock = self.wlock(wait=0) + except lock.LockException: + wlock = None lookup, modified, added, removed, deleted, unknown = ( self.dirstate.changes(files, match)) @@ -550,8 +558,9 @@ l.sort() return (modified, added, removed, deleted, unknown) - def add(self, list): - wlock = self.wlock() + def add(self, list, wlock=None): + if not wlock: + wlock = self.wlock() for f in list: p = self.wjoin(f) if not os.path.exists(p): @@ -564,15 +573,16 @@ else: self.dirstate.update([f], "a") - def forget(self, list): - wlock = self.wlock() + def forget(self, list, wlock=None): + if not wlock: + wlock = self.wlock() for f in list: if self.dirstate.state(f) not in 'ai': self.ui.warn(_("%s not added!\n") % f) else: self.dirstate.forget([f]) - def remove(self, list, unlink=False): + def remove(self, list, unlink=False, wlock=None): if unlink: for f in list: try: @@ -580,25 +590,26 @@ except OSError, inst: if inst.errno != errno.ENOENT: raise - wlock = self.wlock() + if not wlock: + wlock = self.wlock() for f in list: p = self.wjoin(f) if os.path.exists(p): self.ui.warn(_("%s still exists!\n") % f) elif self.dirstate.state(f) == 'a': - self.ui.warn(_("%s never committed!\n") % f) self.dirstate.forget([f]) elif f not in self.dirstate: self.ui.warn(_("%s not tracked!\n") % f) else: self.dirstate.update([f], "r") - def undelete(self, list): + def undelete(self, list, wlock=None): p = self.dirstate.parents()[0] mn = self.changelog.read(p)[0] mf = self.manifest.readflags(mn) m = self.manifest.read(mn) - wlock = self.wlock() + if not wlock: + wlock = self.wlock() for f in list: if self.dirstate.state(f) not in "r": self.ui.warn("%s not removed!\n" % f) @@ -608,14 +619,15 @@ util.set_exec(self.wjoin(f), mf[f]) self.dirstate.update([f], "n") - def copy(self, source, dest): + def copy(self, source, dest, wlock=None): p = self.wjoin(dest) if not os.path.exists(p): self.ui.warn(_("%s does not exist!\n") % dest) elif not os.path.isfile(p): self.ui.warn(_("copy failed: %s is not a file\n") % dest) else: - wlock = self.wlock() + if not wlock: + wlock = self.wlock() if self.dirstate.state(dest) == '?': self.dirstate.update([dest], "a") self.dirstate.copy(source, dest) @@ -919,7 +931,7 @@ return subset def pull(self, remote, heads=None): - lock = self.lock() + l = self.lock() # if we have an empty repo, fetch everything if self.changelog.tip() == nullid: @@ -933,13 +945,13 @@ return 1 if heads is None: - cg = remote.changegroup(fetch) + cg = remote.changegroup(fetch, 'pull') else: - cg = remote.changegroupsubset(fetch, heads) + cg = remote.changegroupsubset(fetch, heads, 'pull') return self.addchangegroup(cg) def push(self, remote, force=False): - lock = remote.lock() + l = remote.lock() base = {} heads = remote.heads() @@ -960,10 +972,10 @@ " use push -f to force)\n")) return 1 - cg = self.changegroup(update) + cg = self.changegroup(update, 'push') return remote.addchangegroup(cg) - def changegroupsubset(self, bases, heads): + def changegroupsubset(self, bases, heads, source): """This function generates a changegroup consisting of all the nodes that are descendents of any of the bases, and ancestors of any of the heads. @@ -975,6 +987,8 @@ Another wrinkle is doing the reverse, figuring out which changeset in the changegroup a particular filenode or manifestnode belongs to.""" + self.hook('preoutgoing', throw=True, source=source) + # Set up some initial variables # Make it easy to refer to self.changelog cl = self.changelog @@ -1227,14 +1241,19 @@ # Signal that no more groups are left. yield struct.pack(">l", 0) + self.hook('outgoing', node=hex(msng_cl_lst[0]), source=source) + return util.chunkbuffer(gengroup()) - def changegroup(self, basenodes): + def changegroup(self, basenodes, source): """Generate a changegroup of all nodes that we have that a recipient doesn't. This is much easier than the previous function as we can assume that the recipient has any changenode we aren't sending them.""" + + self.hook('preoutgoing', throw=True, source=source) + cl = self.changelog nodes = cl.nodesbetween(basenodes, None)[0] revset = dict.fromkeys([cl.rev(n) for n in nodes]) @@ -1286,6 +1305,7 @@ yield chnk yield struct.pack(">l", 0) + self.hook('outgoing', node=hex(nodes[0]), source=source) return util.chunkbuffer(gengroup()) @@ -1321,6 +1341,9 @@ if not source: return + + self.hook('prechangegroup', throw=True) + changesets = files = revisions = 0 tr = self.transaction() @@ -1363,21 +1386,19 @@ " with %d changes to %d files%s\n") % (changesets, revisions, files, heads)) + self.hook('pretxnchangegroup', throw=True, + node=hex(self.changelog.node(cor+1))) + tr.close() if changesets > 0: - if not self.hook("changegroup", - node=hex(self.changelog.node(cor+1))): - self.ui.warn(_("abort: changegroup hook returned failure!\n")) - return 1 + self.hook("changegroup", node=hex(self.changelog.node(cor+1))) for i in range(cor + 1, cnr + 1): - self.hook("commit", node=hex(self.changelog.node(i))) - - return + self.hook("incoming", node=hex(self.changelog.node(i))) def update(self, node, allow=False, force=False, choose=None, - moddirstate=True, forcemerge=False): + moddirstate=True, forcemerge=False, wlock=None): pl = self.dirstate.parents() if not force and pl[1] != nullid: self.ui.warn(_("aborting: outstanding uncommitted merges\n")) @@ -1399,6 +1420,13 @@ 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 +1439,6 @@ 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")) @@ -1436,7 +1460,7 @@ mw[f] = "" mfw[f] = util.is_exec(self.wjoin(f), mfw.get(f, False)) - if moddirstate: + if moddirstate and not wlock: wlock = self.wlock() for f in deleted + removed:
--- a/mercurial/lock.py Fri Feb 03 11:23:34 2006 +0100 +++ b/mercurial/lock.py Tue Feb 21 16:04:47 2006 +0100 @@ -5,10 +5,14 @@ # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. -import os, time +import errno, os, time import util -class LockHeld(Exception): +class LockException(Exception): + pass +class LockHeld(LockException): + pass +class LockUnavailable(LockException): pass class lock(object): @@ -38,8 +42,11 @@ try: util.makelock(str(pid), self.f) self.held = 1 - except (OSError, IOError): - raise LockHeld(util.readlock(self.f)) + except (OSError, IOError), why: + if why.errno == errno.EEXIST: + raise LockHeld(util.readlock(self.f)) + else: + raise LockUnavailable(why) def release(self): if self.held:
--- a/mercurial/mdiff.py Fri Feb 03 11:23:34 2006 +0100 +++ b/mercurial/mdiff.py Tue Feb 21 16:04:47 2006 +0100 @@ -18,16 +18,22 @@ if not text and (util.binary(a) or util.binary(b)): l = ['Binary file %s has changed\n' % fn] - elif a == None: + elif not a: b = b.splitlines(1) - l1 = "--- %s\t%s\n" % ("/dev/null", epoch) + if a is None: + l1 = "--- %s\t%s\n" % ("/dev/null", epoch) + else: + l1 = "--- %s\t%s\n" % ("a/" + fn, ad) l2 = "+++ %s\t%s\n" % ("b/" + fn, bd) l3 = "@@ -0,0 +1,%d @@\n" % len(b) l = [l1, l2, l3] + ["+" + e for e in b] - elif b == None: + elif not b: a = a.splitlines(1) l1 = "--- %s\t%s\n" % ("a/" + fn, ad) - l2 = "+++ %s\t%s\n" % ("/dev/null", epoch) + if b is None: + l2 = "+++ %s\t%s\n" % ("/dev/null", epoch) + else: + l2 = "+++ %s\t%s\n" % ("b/" + fn, bd) l3 = "@@ -1,%d +0,0 @@\n" % len(a) l = [l1, l2, l3] + ["-" + e for e in a] else:
--- a/mercurial/mpatch.c Fri Feb 03 11:23:34 2006 +0100 +++ b/mercurial/mpatch.c Tue Feb 21 16:04:47 2006 +0100 @@ -43,6 +43,7 @@ #endif static char mpatch_doc[] = "Efficient binary patching."; +static PyObject *mpatch_Error; struct frag { int start, end, len; @@ -65,8 +66,11 @@ a = NULL; } else a->head = a->tail = a->base; + return a; } - return a; + if (!PyErr_Occurred()) + PyErr_NoMemory(); + return NULL; } static void lfree(struct flist *a) @@ -215,6 +219,9 @@ /* assume worst case size, we won't have many of these lists */ l = lalloc(len / 12); + if (!l) + return NULL; + lt = l->tail; while (bin < end) { @@ -227,6 +234,13 @@ lt++; } + if (bin != end) { + if (!PyErr_Occurred()) + PyErr_SetString(mpatch_Error, "patch cannot be decoded"); + lfree(l); + return NULL; + } + l->tail = lt; return l; } @@ -238,6 +252,12 @@ struct frag *f = l->head; while (f != l->tail) { + if (f->start < last || f->end > len) { + if (!PyErr_Occurred()) + PyErr_SetString(mpatch_Error, + "invalid patch"); + return -1; + } outlen += f->start - last; last = f->end; outlen += f->len; @@ -248,13 +268,19 @@ return outlen; } -static void apply(char *buf, char *orig, int len, struct flist *l) +static int apply(char *buf, char *orig, int len, struct flist *l) { struct frag *f = l->head; int last = 0; char *p = buf; while (f != l->tail) { + if (f->start < last || f->end > len) { + if (!PyErr_Occurred()) + PyErr_SetString(mpatch_Error, + "invalid patch"); + return 0; + } memcpy(p, orig + last, f->start - last); p += f->start - last; memcpy(p, f->data, f->len); @@ -263,6 +289,7 @@ f++; } memcpy(p, orig + last, len - last); + return 1; } /* recursively generate a patch of all bins between start and end */ @@ -304,16 +331,25 @@ patch = fold(bins, 0, len); if (!patch) - return PyErr_NoMemory(); + return NULL; outlen = calcsize(PyString_Size(text), patch); + if (outlen < 0) { + result = NULL; + goto cleanup; + } result = PyString_FromStringAndSize(NULL, outlen); - if (result) { - in = PyString_AsString(text); - out = PyString_AsString(result); - apply(out, in, PyString_Size(text), patch); + if (!result) { + result = NULL; + goto cleanup; } - + in = PyString_AsString(text); + out = PyString_AsString(result); + if (!apply(out, in, PyString_Size(text), patch)) { + Py_DECREF(result); + result = NULL; + } +cleanup: lfree(patch); return result; } @@ -327,5 +363,6 @@ initmpatch(void) { Py_InitModule3("mpatch", methods, mpatch_doc); + mpatch_Error = PyErr_NewException("mpatch.mpatchError", NULL, NULL); }
--- a/mercurial/revlog.py Fri Feb 03 11:23:34 2006 +0100 +++ b/mercurial/revlog.py Tue Feb 21 16:04:47 2006 +0100 @@ -624,12 +624,10 @@ # we store negative distances because heap returns smallest member h = [(-dist[node], node)] seen = {} - earliest = self.count() while h: d, n = heapq.heappop(h) if n not in seen: seen[n] = 1 - r = self.rev(n) yield (-d, n) for p in self.parents(n): heapq.heappush(h, (-dist[p], p)) @@ -690,11 +688,6 @@ p = self.parents(self.node(revs[0]))[0] revs.insert(0, self.rev(p)) - # helper to reconstruct intermediate versions - def construct(text, base, rev): - bins = [self.chunk(r) for r in xrange(base + 1, rev + 1)] - return mdiff.patches(text, bins) - # build deltas for d in xrange(0, len(revs) - 1): a, b = revs[d], revs[d + 1] @@ -738,10 +731,10 @@ base = prev = -1 start = end = measure = 0 if r: - start = self.start(self.base(t)) + base = self.base(t) + start = self.start(base) end = self.end(t) - measure = self.length(self.base(t)) - base = self.base(t) + measure = self.length(base) prev = self.tip() transaction.add(self.datafile, end) @@ -793,14 +786,15 @@ raise RevlogError(_("consistency error adding group")) measure = len(text) else: - e = (end, len(cdelta), self.base(t), link, p1, p2, node) + e = (end, len(cdelta), base, link, p1, p2, node) self.index.append(e) self.nodemap[node] = r dfh.write(cdelta) ifh.write(struct.pack(indexformat, *e)) t, r, chain, prev = r, r + 1, node, node - start = self.start(self.base(t)) + base = self.base(t) + start = self.start(base) end = self.end(t) dfh.close() @@ -828,6 +822,7 @@ # then reset internal state in memory to forget those revisions self.cache = None + self.chunkcache = None for p in self.index[rev:]: del self.nodemap[p[6]] del self.index[rev:]
--- a/mercurial/sshrepo.py Fri Feb 03 11:23:34 2006 +0100 +++ b/mercurial/sshrepo.py Tue Feb 21 16:04:47 2006 +0100 @@ -110,7 +110,7 @@ except: raise hg.RepoError(_("unexpected response '%s'") % (d[:400] + "...")) - def changegroup(self, nodes): + def changegroup(self, nodes, kind): n = " ".join(map(hex, nodes)) f = self.do_cmd("changegroup", roots=n) return self.pipei
--- a/setup.py Fri Feb 03 11:23:34 2006 +0100 +++ b/setup.py Tue Feb 21 16:04:47 2006 +0100 @@ -81,7 +81,7 @@ 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 @@ 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()
--- a/templates/changelog-gitweb.tmpl Fri Feb 03 11:23:34 2006 +0100 +++ b/templates/changelog-gitweb.tmpl Tue Feb 21 16:04:47 2006 +0100 @@ -27,4 +27,8 @@ #entries%changelogentry# +<div class="page_nav"> +#changenav%naventry#<br/> +</div> + #footer#
--- a/templates/changelogentry-gitweb.tmpl Fri Feb 03 11:23:34 2006 +0100 +++ b/templates/changelogentry-gitweb.tmpl Tue Feb 21 16:04:47 2006 +0100 @@ -5,7 +5,7 @@ <div class="log_link"> <a href="?cmd=changeset;node=#node#;style=gitweb">changeset</a><br/> </div> -<i>#author|obfuscate# [#date|rfc822date#]</i><br/> +<i>#author|obfuscate# [#date|rfc822date#] rev #rev#</i><br/> </div> <div class="log_body"> #desc|escape|addbreaks#
--- a/templates/fileannotate-gitweb.tmpl Fri Feb 03 11:23:34 2006 +0100 +++ b/templates/fileannotate-gitweb.tmpl Tue Feb 21 16:04:47 2006 +0100 @@ -10,7 +10,7 @@ </div> <div class="page_nav"> -<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=#path|urlescape#;style=gitweb">manifest</a> | <a href="?cmd=changeset;node=#node#;style=gitweb">changeset</a> | <a href="?cmd=file;file=#file|urlescape#;filenode=#filenode#;style=gitweb">file</a> | <a href="?cmd=filelog;file=#file|urlescape#;filenode=#filenode#;style=gitweb">revisions</a> | annotate<br/> +<a href="?cmd=summary;style=gitweb">summary</a> | <a href="?cmd=changelog;style=gitweb">changelog</a> | <a href="?cmd=tags;style=gitweb">tags</a> | <a href="?cmd=manifest;manifest=#manifest#;path=#path|urlescape#;style=gitweb">manifest</a> | <a href="?cmd=changeset;node=#node#;style=gitweb">changeset</a> | <a href="?cmd=file;file=#file|urlescape#;filenode=#filenode#;style=gitweb">file</a> | <a href="?cmd=filelog;file=#file|urlescape#;filenode=#filenode#;style=gitweb">revisions</a> | annotate | <a href="?cmd=annotate;file=#file|urlescape#;filenode=#filenode#;style=raw">raw</a><br/> </div> <div class="title">#file|escape#</div> @@ -19,6 +19,7 @@ <tr> <td class="metatag">changeset #rev#:</td> <td><a href="?cs=#node|short#;style=gitweb">#node|short#</a></td></tr> +#rename%filerename# #parent%fileannotateparent# #child%fileannotatechild# <tr>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/fileannotate-raw.tmpl Tue Feb 21 16:04:47 2006 +0100 @@ -0,0 +1,5 @@ +#header# +#annotate%annotateline# +#footer# + +
--- a/templates/fileannotate.tmpl Fri Feb 03 11:23:34 2006 +0100 +++ b/templates/fileannotate.tmpl Tue Feb 21 16:04:47 2006 +0100 @@ -10,6 +10,7 @@ <a href="?mf=#manifest|short#;path=#path|urlescape#">manifest</a> <a href="?f=#filenode|short#;file=#file|urlescape#">file</a> <a href="?fl=#filenode|short#;file=#file|urlescape#">revisions</a> +<a href="?fa=#filenode|short#;file=#file|urlescape#;style=raw">raw</a> </div> <h2>Annotate #file|escape#</h2>
--- a/templates/filelog-gitweb.tmpl Fri Feb 03 11:23:34 2006 +0100 +++ b/templates/filelog-gitweb.tmpl Tue Feb 21 16:04:47 2006 +0100 @@ -1,12 +1,12 @@ #header# -<title>#repo|escape#: Manifest</title> +<title>#repo|escape#: File revisions</title> <link rel="alternate" type="application/rss+xml" href="?cmd=changelog;style=rss" title="RSS feed for #repo|escape#"> </head> <body> <div class="page_header"> -<a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="?cmd=summary;style=gitweb">#repo|escape#</a> / manifest +<a href="http://www.selenic.com/mercurial/" title="Mercurial"><div style="float:right;">Mercurial</div></a><a href="?cmd=summary;style=gitweb">#repo|escape#</a> / file revisions </div> <div class="page_nav">
--- a/templates/filerevision-gitweb.tmpl Fri Feb 03 11:23:34 2006 +0100 +++ b/templates/filerevision-gitweb.tmpl Tue Feb 21 16:04:47 2006 +0100 @@ -19,6 +19,7 @@ <tr> <td class="metatag">changeset #rev#:</td> <td><a href="?cs=#node|short#;style=gitweb">#node|short#</a></td></tr> +#rename%filerename# #parent%fileannotateparent# #child%fileannotatechild# <tr>
--- a/templates/map Fri Feb 03 11:23:34 2006 +0100 +++ b/templates/map Tue Feb 21 16:04:47 2006 +0100 @@ -43,7 +43,7 @@ filelogparent = "<tr><td align="right">parent #rev#: </td><td><a href="?f=#node|short#;file=#file|urlescape#">#node|short#</a></td></tr>" filediffchild = "<tr><th class="child">child #rev#:</th><td class="child"><a href="?cs=#node|short#">#node|short#</a></td></tr>" filelogchild = "<tr><td align="right">child #rev#: </td><td><a href="?f=#node|short#;file=#file|urlescape#">#node|short#</a></td></tr>" -indexentry = "<tr class="parity#parity#"><td><a href="#url#">#name|escape#</a></td><td>#shortdesc|escape#</td><td>#contact|obfuscate#</td><td>#lastupdate|age# ago</td><td><a href="#url#?cl=tip;style=rss">RSS</a></td></tr>" +indexentry = "<tr class="parity#parity#"><td><a href="#url#">#name|escape#</a></td><td>#shortdesc#</td><td>#contact|obfuscate#</td><td>#lastupdate|age# ago</td><td><a href="#url#?cl=tip;style=rss">RSS</a></td></tr>" index = index.tmpl archiveentry = "<a href="?ca=#node|short#;type=#type|urlescape#">#type|escape#</a> " notfound = notfound.tmpl
--- a/templates/map-gitweb Fri Feb 03 11:23:34 2006 +0100 +++ b/templates/map-gitweb Tue Feb 21 16:04:47 2006 +0100 @@ -20,7 +20,6 @@ fileannotate = fileannotate-gitweb.tmpl filelog = filelog-gitweb.tmpl fileline = "<div style="font-family:monospace; white-space: pre;" class="parity#parity#"><span class="linenr"> #linenumber#</span> #line|escape#</div>" -filelogentry = filelogentry-gitweb.tmpl annotateline = "<tr style="font-family:monospace; white-space: pre;" class="parity#parity#"><td class="linenr" style="text-align: right;"><a href="?cs=#node|short#;style=gitweb">#author|obfuscate#@#rev#</a></td><td>#line|escape#</td></tr>" difflineplus = "<div class="pre" style="color:#008800;">#line|escape#</div>" difflineminus = "<div class="pre" style="color:#cc0000;">#line|escape#</div>" @@ -29,6 +28,8 @@ changelogparent = "<tr><th class="parent">parent #rev#:</th><td class="parent"><a href="?cmd=changeset;node=#node#;style=gitweb">#node|short#</a></td></tr>" changesetparent = "<tr><td>parent</td><td style="font-family:monospace"><a class="list" href="?cmd=changeset;node=#node|short#;style=gitweb">#node|short#</a></td></tr>" filerevparent = "<tr><td class="metatag">parent:</td><td><a href="?cmd=file;file=#file|urlescape#;filenode=#node#;style=gitweb">#node|short#</a></td></tr>" +filerename = "<tr><td class="metatag">parent:</td><td><a href="?f=#node|short#;file=#file|urlescape#;style=gitweb">#file|escape#@#node|short#</a></td></tr>" +filelogrename = "| <a href="?f=#node|short#;file=#file|urlescape#;style=gitweb">base</a>" fileannotateparent = "<tr><td class="metatag">parent:</td><td><a href="?cmd=annotate;file=#file|urlescape#;filenode=#node#;style=gitweb">#node|short#</a></td></tr>" changelogchild = "<tr><th class="child">child #rev#:</th><td class="child"><a href="?cmd=changeset;node=#node#;style=gitweb">#node|short#</a></td></tr>" changesetchild = "<tr><td>child</td><td style="font-family:monospace"><a class="list" href="?cmd=changeset;node=#node|short#;style=gitweb">#node|short#</a></td></tr>" @@ -45,5 +46,5 @@ filelogchild = "<tr><td align="right">child #rev#: </td><td><a href="?cmd=file;file=#file|urlescape#;filenode=#node#;style=gitweb">#node|short#</a></td></tr>" shortlog = shortlog-gitweb.tmpl shortlogentry = "<tr class="parity#parity#"><td><i>#date|age# ago</i></td><td><a class="list" href="?cmd=changeset;node=#node|short#;style=gitweb"><b>#desc|firstline|escape#</b></a></td><td class="link"><a href="?cmd=changeset;node=#node|short#;style=gitweb">changeset</a> | <a href="?cmd=manifest;manifest=#manifest|short#;path=/;style=gitweb">manifest</a></td></tr>" -filelogentry = "<tr class="parity#parity#"><td><i>#date|age# ago</i></td><td><a class="list" href="?cmd=changeset;node=#node|short#;style=gitweb"><b>#desc|firstline|escape#</b></a></td><td class="link"><!-- FIXME: <a href="?fd=#node|short#;file=#file|urlescape#;style=gitweb">diff</a> | --> <a href="?fa=#filenode|short#;file=#file|urlescape#;style=gitweb">annotate</a></td></tr>" +filelogentry = "<tr class="parity#parity#"><td><i>#date|age# ago</i></td><td><a class="list" href="?cmd=changeset;node=#node|short#;style=gitweb"><b>#desc|firstline|escape#</b></a></td><td class="link"><!-- FIXME: <a href="?fd=#node|short#;file=#file|urlescape#;style=gitweb">diff</a> | --> <a href="?fa=#filenode|short#;file=#file|urlescape#;style=gitweb">annotate</a> #rename%filelogrename#</td></tr>" archiveentry = " | <a href="?ca=#node|short#;type=#type|urlescape#">#type|escape#</a> "
--- a/templates/map-raw Fri Feb 03 11:23:34 2006 +0100 +++ b/templates/map-raw Tue Feb 21 16:04:47 2006 +0100 @@ -1,15 +1,16 @@ header = header-raw.tmpl footer = "" changeset = changeset-raw.tmpl -annotateline = "<tr class="parity#parity#"><td class="annotate"><a href="?cmd=changeset;node=#node#">#author#@#rev#</a></td><td><pre>#line|escape#</pre></td></tr>" -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#"
--- a/tests/test-archive Fri Feb 03 11:23:34 2006 +0100 +++ b/tests/test-archive Tue Feb 21 16:04:47 2006 +0100 @@ -18,8 +18,8 @@ echo "allowzip = true" >> .hg/hgrc echo "allowgz = true" >> .hg/hgrc echo "allowbz2 = true" >> .hg/hgrc -hg serve -p 20059 > /dev/null & -sleep 1 # wait for server to be started +serverpid=`mktemp` +hg serve -p 20059 -d --pid-file=$serverpid TIP=`hg id -v | cut -f1 -d' '` QTIP=`hg id -q` @@ -35,4 +35,5 @@ http_proxy= python getarchive.py "$TIP" zip > archive.zip unzip -t archive.zip | sed "s/$QTIP/TIP/" -kill $! +kill `cat $serverpid` +rm $serverpid
--- a/tests/test-archive.out Fri Feb 03 11:23:34 2006 +0100 +++ b/tests/test-archive.out Tue Feb 21 16:04:47 2006 +0100 @@ -12,4 +12,3 @@ testing: test-archive-TIP/baz/bletch OK testing: test-archive-TIP/foo OK No errors detected in compressed data of archive.zip. -killed!
--- a/tests/test-diffdir Fri Feb 03 11:23:34 2006 +0100 +++ b/tests/test-diffdir Tue Feb 21 16:04:47 2006 +0100 @@ -12,3 +12,7 @@ hg diff -r tip | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/" + +echo foo > a +hg diff | sed -e "s/\(+++ [a-zA-Z0-9_/.-]*\).*/\1/" \ + -e "s/\(--- [a-zA-Z0-9_/.-]*\).*/\1/"
--- a/tests/test-diffdir.out Fri Feb 03 11:23:34 2006 +0100 +++ b/tests/test-diffdir.out Tue Feb 21 16:04:47 2006 +0100 @@ -8,3 +8,13 @@ +++ b/b @@ -0,0 +1,1 @@ +123 +diff -r 3903775176ed a +--- a/a ++++ b/a +@@ -0,0 +1,1 @@ ++foo +diff -r 3903775176ed b +--- /dev/null ++++ b/b +@@ -0,0 +1,1 @@ ++123
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-excessive-merge Tue Feb 21 16:04:47 2006 +0100 @@ -0,0 +1,46 @@ +#!/bin/sh + +hg init + +echo foo > a +echo foo > b +hg add a b + +hg ci -m "test" -d "0 0" + +echo blah > a + +hg ci -m "branch a" -d "0 0" + +hg co 0 + +echo blah > b + +hg ci -m "branch b" -d "0 0" +HGMERGE=true hg up -m 1 + +hg ci -m "merge b/a -> blah" -d "0 0" + +hg co 1 +HGMERGE=true hg up -m 2 +hg ci -m "merge a/b -> blah" -d "0 0" + +hg log +hg debugindex .hg/00changelog.i + +echo + +echo 1 +hg manifest 1 +echo 2 +hg manifest 2 +echo 3 +hg manifest 3 +echo 4 +hg manifest 4 + +echo + +hg debugindex .hg/data/a.i + +hg verify \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-excessive-merge.out Tue Feb 21 16:04:47 2006 +0100 @@ -0,0 +1,59 @@ +changeset: 4:2ee31f665a86 +tag: tip +parent: 1:96155394af80 +parent: 2:92cc4c306b19 +user: test +date: Thu Jan 1 00:00:00 1970 +0000 +summary: merge a/b -> blah + +changeset: 3:e16a66a37edd +parent: 2:92cc4c306b19 +parent: 1:96155394af80 +user: test +date: Thu Jan 1 00:00:00 1970 +0000 +summary: merge b/a -> blah + +changeset: 2:92cc4c306b19 +parent: 0:5e0375449e74 +user: test +date: Thu Jan 1 00:00:00 1970 +0000 +summary: branch b + +changeset: 1:96155394af80 +user: test +date: Thu Jan 1 00:00:00 1970 +0000 +summary: branch a + +changeset: 0:5e0375449e74 +user: test +date: Thu Jan 1 00:00:00 1970 +0000 +summary: test + + rev offset length base linkrev nodeid p1 p2 + 0 0 60 0 0 5e0375449e74 000000000000 000000000000 + 1 60 62 1 1 96155394af80 5e0375449e74 000000000000 + 2 122 62 2 2 92cc4c306b19 5e0375449e74 000000000000 + 3 184 69 3 3 e16a66a37edd 92cc4c306b19 96155394af80 + 4 253 29 3 4 2ee31f665a86 96155394af80 92cc4c306b19 + +1 +79d7492df40aa0fa093ec4209be78043c181f094 644 a +2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 b +2 +2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 a +79d7492df40aa0fa093ec4209be78043c181f094 644 b +3 +79d7492df40aa0fa093ec4209be78043c181f094 644 a +79d7492df40aa0fa093ec4209be78043c181f094 644 b +4 +79d7492df40aa0fa093ec4209be78043c181f094 644 a +79d7492df40aa0fa093ec4209be78043c181f094 644 b + + rev offset length base linkrev nodeid p1 p2 + 0 0 5 0 0 2ed2a3912a0b 000000000000 000000000000 + 1 5 6 1 1 79d7492df40a 2ed2a3912a0b 000000000000 +checking changesets +checking manifests +crosschecking files in changesets and manifests +checking files +2 files, 5 changesets, 4 total revisions
--- a/tests/test-help.out Fri Feb 03 11:23:34 2006 +0100 +++ b/tests/test-help.out Tue Feb 21 16:04:47 2006 +0100 @@ -171,10 +171,12 @@ options: - -r --rev revision - -a --text treat all files as text - -I --include include names matching the given patterns - -X --exclude exclude names matching the given patterns + -r --rev revision + -a --text treat all files as text + -I --include include names matching the given patterns + -p --show-function show which function each change is in + -w --ignore-all-space ignore white space when comparing lines + -X --exclude exclude names matching the given patterns hg status [OPTION]... [FILE]... show changed files in the working directory
--- a/tests/test-hook Fri Feb 03 11:23:34 2006 +0100 +++ b/tests/test-hook Tue Feb 21 16:04:47 2006 +0100 @@ -1,10 +1,90 @@ #!/bin/sh -hg init +# commit hooks can see env vars +hg init a +cd a echo "[hooks]" > .hg/hgrc -echo 'precommit = echo precommit hook' >> .hg/hgrc -echo 'commit = echo commit hook: $NODE' >> .hg/hgrc +echo 'commit = echo commit hook: n=$HG_NODE p1=$HG_PARENT1 p2=$HG_PARENT2' >> .hg/hgrc echo 'commit.b = echo commit hook b' >> .hg/hgrc +echo 'precommit = echo precommit hook: p1=$HG_PARENT1 p2=$HG_PARENT2' >> .hg/hgrc +echo 'pretxncommit = echo pretxncommit hook: n=$HG_NODE p1=$HG_PARENT1 p2=$HG_PARENT2; hg -q tip' >> .hg/hgrc echo a > a hg add a -hg commit -m "test" -d "0 0" +hg commit -m a -d "0 0" + +hg clone . ../b +cd ../b + +# changegroup hooks can see env vars +echo '[hooks]' > .hg/hgrc +echo 'prechangegroup = echo prechangegroup hook' >> .hg/hgrc +echo 'changegroup = echo changegroup hook: n=$HG_NODE' >> .hg/hgrc +echo 'incoming = echo incoming hook: n=$HG_NODE' >> .hg/hgrc + +# pretxncommit and commit hooks can see both parents of merge +cd ../a +echo b >> a +hg commit -m a1 -d "1 0" +hg update -C 0 +echo b > b +hg add b +hg commit -m b -d '1 0' +hg update -m 1 +hg commit -m merge -d '2 0' + +cd ../b +hg pull ../a + +# tag hooks can see env vars +cd ../a +echo 'pretag = echo pretag hook: t=$HG_TAG n=$HG_NODE l=$HG_LOCAL' >> .hg/hgrc +echo 'tag = echo tag hook: t=$HG_TAG n=$HG_NODE l=$HG_LOCAL' >> .hg/hgrc +hg tag -d '3 0' a +hg tag -l la + +# pretag hook can forbid tagging +echo 'pretag.forbid = echo pretag.forbid hook; exit 1' >> .hg/hgrc +hg tag -d '4 0' fa +hg tag -l fla + +# pretxncommit hook can see changeset, can roll back txn, changeset +# no more there after +echo 'pretxncommit.forbid = echo pretxncommit.forbid hook: tip=`hg -q tip`; exit 1' >> .hg/hgrc +echo z > z +hg add z +hg -q tip +hg commit -m 'fail' -d '4 0' +hg -q tip + +# precommit hook can prevent commit +echo 'precommit.forbid = echo precommit.forbid hook; exit 1' >> .hg/hgrc +hg commit -m 'fail' -d '4 0' +hg -q tip + +# prechangegroup hook can prevent incoming changes +cd ../b +hg -q tip +echo '[hooks]' > .hg/hgrc +echo 'prechangegroup.forbid = echo prechangegroup.forbid hook; exit 1' >> .hg/hgrc +hg pull ../a + +# pretxnchangegroup hook can see incoming changes, can roll back txn, +# incoming changes no longer there after +echo '[hooks]' > .hg/hgrc +echo 'pretxnchangegroup.forbid = echo pretxnchangegroup.forbid hook: tip=`hg -q tip`; exit 1' >> .hg/hgrc +hg pull ../a +hg -q tip + +# outgoing hooks can see env vars +rm .hg/hgrc +echo '[hooks]' > ../a/.hg/hgrc +echo 'preoutgoing = echo preoutgoing hook: s=$HG_SOURCE' >> ../a/.hg/hgrc +echo 'outgoing = echo outgoing hook: n=$HG_NODE s=$HG_SOURCE' >> ../a/.hg/hgrc +hg pull ../a +hg undo + +# preoutgoing hook can prevent outgoing changes +echo 'preoutgoing.forbid = echo preoutgoing.forbid hook; exit 1' >> ../a/.hg/hgrc +hg pull ../a + +exit 0
--- a/tests/test-hook.out Fri Feb 03 11:23:34 2006 +0100 +++ b/tests/test-hook.out Tue Feb 21 16:04:47 2006 +0100 @@ -1,3 +1,88 @@ -precommit hook +precommit hook: p1=0000000000000000000000000000000000000000 p2= +pretxncommit hook: n=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b p1=0000000000000000000000000000000000000000 p2= +0:cb9a9f314b8b +commit hook b +commit hook: n=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b p1=0000000000000000000000000000000000000000 p2= +precommit hook: p1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b p2= +pretxncommit hook: n=ab228980c14deea8b9555d91c9581127383e40fd p1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b p2= +1:ab228980c14d +commit hook b +commit hook: n=ab228980c14deea8b9555d91c9581127383e40fd p1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b p2= +precommit hook: p1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b p2= +pretxncommit hook: n=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 p1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b p2= +2:ee9deb46ab31 +commit hook b +commit hook: n=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 p1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b p2= +precommit hook: p1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 p2=ab228980c14deea8b9555d91c9581127383e40fd +pretxncommit hook: n=07f3376c1e655977439df2a814e3cc14b27abac2 p1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 p2=ab228980c14deea8b9555d91c9581127383e40fd +3:07f3376c1e65 +commit hook b +commit hook: n=07f3376c1e655977439df2a814e3cc14b27abac2 p1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 p2=ab228980c14deea8b9555d91c9581127383e40fd +prechangegroup hook +changegroup hook: n=ab228980c14deea8b9555d91c9581127383e40fd +incoming hook: n=ab228980c14deea8b9555d91c9581127383e40fd +incoming hook: n=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 +incoming hook: n=07f3376c1e655977439df2a814e3cc14b27abac2 +pulling from ../a +searching for changes +adding changesets +adding manifests +adding file changes +added 3 changesets with 2 changes to 2 files +(run 'hg update' to get a working copy) +pretag hook: t=a n=07f3376c1e655977439df2a814e3cc14b27abac2 l=0 +precommit hook: p1=07f3376c1e655977439df2a814e3cc14b27abac2 p2= +pretxncommit hook: n=3cd2c6a5a36c5908aad3bc0d717c29873a05dfc2 p1=07f3376c1e655977439df2a814e3cc14b27abac2 p2= +4:3cd2c6a5a36c commit hook b -commit hook: acb14030fe0a21b60322c440ad2d20cf7685a376 +commit hook: n=3cd2c6a5a36c5908aad3bc0d717c29873a05dfc2 p1=07f3376c1e655977439df2a814e3cc14b27abac2 p2= +tag hook: t=a n=07f3376c1e655977439df2a814e3cc14b27abac2 l=0 +pretag hook: t=la n=3cd2c6a5a36c5908aad3bc0d717c29873a05dfc2 l=1 +tag hook: t=la n=3cd2c6a5a36c5908aad3bc0d717c29873a05dfc2 l=1 +pretag hook: t=fa n=3cd2c6a5a36c5908aad3bc0d717c29873a05dfc2 l=0 +pretag.forbid hook +abort: pretag.forbid hook exited with status 1 +pretag hook: t=fla n=3cd2c6a5a36c5908aad3bc0d717c29873a05dfc2 l=1 +pretag.forbid hook +abort: pretag.forbid hook exited with status 1 +4:3cd2c6a5a36c +precommit hook: p1=3cd2c6a5a36c5908aad3bc0d717c29873a05dfc2 p2= +pretxncommit.forbid hook: tip=5:469a61fe67d6 +abort: pretxncommit.forbid hook exited with status 1 +transaction abort! +rollback completed +4:3cd2c6a5a36c +precommit.forbid hook +abort: precommit.forbid hook exited with status 1 +4:3cd2c6a5a36c +3:07f3376c1e65 +prechangegroup.forbid hook +pulling from ../a +searching for changes +abort: prechangegroup.forbid hook exited with status 1 +pretxnchangegroup.forbid hook: tip=4:3cd2c6a5a36c +pulling from ../a +searching for changes +adding changesets +adding manifests +adding file changes +added 1 changesets with 1 changes to 1 files +abort: pretxnchangegroup.forbid hook exited with status 1 +transaction abort! +rollback completed +3:07f3376c1e65 +preoutgoing hook: s=pull +outgoing hook: n=3cd2c6a5a36c5908aad3bc0d717c29873a05dfc2 s=pull +pulling from ../a +searching for changes +adding changesets +adding manifests +adding file changes +added 1 changesets with 1 changes to 1 files +(run 'hg update' to get a working copy) +rolling back last transaction +preoutgoing hook: s=pull +preoutgoing.forbid hook +pulling from ../a +searching for changes +abort: preoutgoing.forbid hook exited with status 1
--- a/tests/test-merge3.out Fri Feb 03 11:23:34 2006 +0100 +++ b/tests/test-merge3.out Tue Feb 21 16:04:47 2006 +0100 @@ -1,3 +1,2 @@ removing b -b never committed! nothing changed
--- a/tests/test-pull Fri Feb 03 11:23:34 2006 +0100 +++ b/tests/test-pull Tue Feb 21 16:04:47 2006 +0100 @@ -7,8 +7,8 @@ hg addremove hg commit -m 1 hg verify -hg serve -p 20059 > /dev/null & -sleep 1 # wait for server to be started +serverpid=`mktemp` +hg serve -p 20059 -d --pid-file=$serverpid cd .. hg clone http://localhost:20059/ copy @@ -19,4 +19,5 @@ hg manifest hg pull -kill $! +kill `cat $serverpid` +rm $serverpid
--- a/tests/test-pull-permission Fri Feb 03 11:23:34 2006 +0100 +++ b/tests/test-pull-permission Tue Feb 21 16:04:47 2006 +0100 @@ -12,9 +12,8 @@ cd .. hg clone a b + +chmod +w a/.hg # let test clean up + cd b hg verify - -cd .. - -chmod +w a/.hg # let test clean up
--- a/tests/test-pull.out Fri Feb 03 11:23:34 2006 +0100 +++ b/tests/test-pull.out Tue Feb 21 16:04:47 2006 +0100 @@ -19,4 +19,3 @@ pulling from http://localhost:20059/ searching for changes no changes found -killed!
--- a/tests/test-rename Fri Feb 03 11:23:34 2006 +0100 +++ b/tests/test-rename Tue Feb 21 16:04:47 2006 +0100 @@ -158,3 +158,16 @@ hg rename d1 d3 hg status hg update -C + +echo "# transitive rename" +hg rename d1/b d1/bb +hg rename d1/bb d1/bc +hg status +hg update -C + +echo "# transitive rename --after" +hg rename d1/b d1/bb +mv d1/bb d1/bc +hg rename --after d1/bb d1/bc +hg status +hg update -C
--- a/tests/test-rename.out Fri Feb 03 11:23:34 2006 +0100 +++ b/tests/test-rename.out Tue Feb 21 16:04:47 2006 +0100 @@ -246,3 +246,9 @@ R d1/b R d1/ba R d1/d11/a1 +# transitive rename +A d1/bc +R d1/b +# transitive rename --after +A d1/bc +R d1/b
--- a/tests/test-ro-message Fri Feb 03 11:23:34 2006 +0100 +++ b/tests/test-ro-message Tue Feb 21 16:04:47 2006 +0100 @@ -14,4 +14,4 @@ "$HG" commit -m 'Clarifying the vehicle.' "$HG" update -C 1 chmod a-w b/vehicle -"$HG" update -m 2 2>&1 | sed 's|^\(.*[ ]\)/tmp/[^/]*/\(.*\)$|\1\2|g' +"$HG" update -m 2 2>&1 | sed 's|^\(.*[ ]\).*/\([^/]*/[^/]*/[^/]*\)$|\1\2|g'
--- a/tests/test-up-local-change Fri Feb 03 11:23:34 2006 +0100 +++ b/tests/test-up-local-change Tue Feb 21 16:04:47 2006 +0100 @@ -24,11 +24,34 @@ 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/"
--- a/tests/test-up-local-change.out Fri Feb 03 11:23:34 2006 +0100 +++ b/tests/test-up-local-change.out Tue Feb 21 16:04:47 2006 +0100 @@ -7,6 +7,11 @@ +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 @@ 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 @@ @@ -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