# HG changeset patch # User Vadim Gelfer # Date 1154028977 25200 # Node ID 030d0abdf91b16d2c74d22f70a080786b2179d90 # Parent 99e7cf6bd2f7e0a6c2fde4298effcc2b8de79572# Parent f12d2e5b97fe54382ff085d4f06070f5d491985f merge with crew. diff --git a/MANIFEST.in b/MANIFEST.in --- a/MANIFEST.in +++ b/MANIFEST.in @@ -2,7 +2,7 @@ include hg recursive-include mercurial *.py include hgweb.cgi hgwebdir.cgi include hgeditor rewrite-log -include tests/README tests/coverage.py tests/run-tests.py tests/md5sum.py tests/test-*[a-z0-9] tests/*.out +include tests/README tests/*.py tests/test-*[a-z0-9] tests/*.out prune tests/*.err include *.txt include templates/map templates/map-*[a-z0-9] @@ -10,8 +10,10 @@ include templates/*.tmpl include templates/static/* include doc/README doc/Makefile doc/gendoc.py doc/*.txt doc/*.html doc/*.[0-9] recursive-include contrib * +recursive-include hgext * include README include CONTRIBUTORS include COPYING include Makefile include MANIFEST.in +prune *.elc *.orig *.rej *~ *.o *.so *.pyc *.swp *.prof diff --git a/contrib/bash_completion b/contrib/bash_completion --- a/contrib/bash_completion +++ b/contrib/bash_completion @@ -288,7 +288,7 @@ complete -o bashdefault -o default -F _h _hg_cmd_qdelete() { - _hg_ext_mq_patchlist qseries + _hg_ext_mq_patchlist qunapplied } _hg_cmd_qsave() @@ -313,6 +313,11 @@ complete -o bashdefault -o default -F _h COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$files' -- "$cur")) } +_hg_cmd_export() +{ + _hg_ext_mq_patchlist qapplied +} + # hbisect _hg_cmd_bisect() diff --git a/contrib/macosx/Welcome.html b/contrib/macosx/Welcome.html --- a/contrib/macosx/Welcome.html +++ b/contrib/macosx/Welcome.html @@ -5,13 +5,73 @@

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


-

It is based on Mercurial 0.9.

+

It is based on Mercurial 0.9.1

+
+
+Release Notes
+-------------
+
+2006-07-24  v0.9.1
+
+Major changes between Mercurial 0.9 and 0.9.1:
+
+ New features:
+ - You can now configure your 'hgweb' server to let remote users
+   'push' changes over http.
+ - You can now 'import' a patch in a mail message by saving the mail
+   message, and importing it.  This works for patches sent either
+   inline or as attachments.
+ - The 'diff' command now accepts '-rA:B' syntax as a synonym for
+   '-r A -r B', and adds '-b' and '-B' options.
+
+ New contributions and extensions:
+ - The 'acl' extension lets you lock down parts of a repository
+   against incoming changes
+ - The 'extdiff' extension lets you run your favourite graphical
+   change viewer
+ - Comprehensive integration with the 'vim' editor
+ - A restricted shell for 'ssh'-hosted repositories
+ - An importer for 'darcs' repositories
+
+ New hooks added:
+ - 'preupdate' is run before an update or merge in the working
+   directory.
+ - 'update' is run after an update or merge in the working
+   directory.
+
+ Behaviour changes:
+ - NOTE: Mercurial as installed by the Windows binary
+   installer no longer performs automatic line-ending conversion for
+   Unix/Linux compatibility.  To re-enable this feature, edit your
+   'mercurial.ini' file after you upgrade.
+ - The Windows binary installer now automatically adds 'hg' to your
+   '%PATH%'.
+ - The 'backout' command now runs an editor by default, to let you
+   modify the commit message for a backed-out changeset.
+ - An earlier problem with parsing of tags has been fixed.
+   This makes tag parsing slower but more reliable.
+
+ Memory usage and performance improvements:
+ - The 'remove' command has been rewritten to be hundreds of times
+   faster in large repositories.
+ - It is now possible to 'clone' a repository very quickly over a
+   LAN, if the server is configured to allow it.  See the new 'server'
+   section in the 'hgrc' documentation.
+
+ Other changes of note:
+ - Mercurial will now print help for an extension if you type 'hg
+   help EXT_NAME'.
+ - The usual array of bug fixes and documentation improvements.
+ - The integrated web server is now more WSGI-compliant.
+ - Work has begun to solidify Mercurial's API for use by third-party
+   packages.
+
diff --git a/contrib/mercurial.el b/contrib/mercurial.el --- a/contrib/mercurial.el +++ b/contrib/mercurial.el @@ -380,7 +380,9 @@ Handle frickin' frackin' gratuitous even (save-excursion (while hg-prev-buffer (set-buffer hg-prev-buffer)) - (let ((path (or default (buffer-file-name) default-directory))) + (let ((path (or default + (buffer-file-name) + (expand-file-name default-directory)))) (if (or (not path) current-prefix-arg) (expand-file-name (eval (list* 'read-file-name @@ -972,7 +974,8 @@ With a prefix argument, prompt for the p (cd (hg-root path))) (when update (with-current-buffer buf - (set (make-local-variable 'backup-inhibited) nil) + (when (local-variable-p 'backup-inhibited) + (kill-local-variable 'backup-inhibited)) (hg-mode-line))))) (defun hg-incoming (&optional repo) diff --git a/contrib/win32/ReadMe.html b/contrib/win32/ReadMe.html --- a/contrib/win32/ReadMe.html +++ b/contrib/win32/ReadMe.html @@ -14,7 +14,7 @@ -

Mercurial version 0.9 for Windows

+

Mercurial version 0.9.1 for Windows

Welcome to Mercurial for Windows!

diff --git a/contrib/win32/mercurial.iss b/contrib/win32/mercurial.iss --- a/contrib/win32/mercurial.iss +++ b/contrib/win32/mercurial.iss @@ -4,7 +4,7 @@ [Setup] AppCopyright=Copyright 2005, 2006 Matt Mackall and others AppName=Mercurial -AppVerName=Mercurial version 0.9 +AppVerName=Mercurial version 0.9.1 InfoAfterFile=contrib/win32/postinstall.txt LicenseFile=COPYING ShowLanguageDialog=yes @@ -14,10 +14,10 @@ AppSupportURL=http://www.selenic.com/mer AppUpdatesURL=http://www.selenic.com/mercurial AppID={{4B95A5F1-EF59-4B08-BED8-C891C46121B3} AppContact=mercurial@selenic.com -OutputBaseFilename=Mercurial-0.9 +OutputBaseFilename=Mercurial-0.9.1 DefaultDirName={sd}\Mercurial SourceDir=C:\hg\hg-release -VersionInfoVersion=0.9 +VersionInfoVersion=0.9.1 VersionInfoDescription=Mercurial distributed SCM VersionInfoCopyright=Copyright 2005, 2006 Matt Mackall and others VersionInfoCompany=Matt Mackall and others diff --git a/contrib/win32/postinstall.txt b/contrib/win32/postinstall.txt --- a/contrib/win32/postinstall.txt +++ b/contrib/win32/postinstall.txt @@ -7,6 +7,62 @@ file that comes with this package. Release Notes ------------- +2006-07-24 v0.9.1 + +Major changes between Mercurial 0.9 and 0.9.1: + + New features: + - You can now configure your 'hgweb' server to let remote users + 'push' changes over http. + - You can now 'import' a patch in a mail message by saving the mail + message, and importing it. This works for patches sent either + inline or as attachments. + - The 'diff' command now accepts '-rA:B' syntax as a synonym for + '-r A -r B', and adds '-b' and '-B' options. + + New contributions and extensions: + - The 'acl' extension lets you lock down parts of a repository + against incoming changes + - The 'extdiff' extension lets you run your favourite graphical + change viewer + - Comprehensive integration with the 'vim' editor + - A restricted shell for 'ssh'-hosted repositories + - An importer for 'darcs' repositories + + New hooks added: + - 'preupdate' is run before an update or merge in the working + directory. + - 'update' is run after an update or merge in the working + directory. + + Behaviour changes: + - NOTE: Mercurial as installed by the Windows binary + installer no longer performs automatic line-ending conversion for + Unix/Linux compatibility. To re-enable this feature, edit your + 'mercurial.ini' file after you upgrade. + - The Windows binary installer now automatically adds 'hg' to your + '%PATH%'. + - The 'backout' command now runs an editor by default, to let you + modify the commit message for a backed-out changeset. + - An earlier problem with parsing of tags has been fixed. + This makes tag parsing slower but more reliable. + + Memory usage and performance improvements: + - The 'remove' command has been rewritten to be hundreds of times + faster in large repositories. + - It is now possible to 'clone' a repository very quickly over a + LAN, if the server is configured to allow it. See the new 'server' + section in the 'hgrc' documentation. + + Other changes of note: + - Mercurial will now print help for an extension if you type 'hg + help EXT_NAME'. + - The usual array of bug fixes and documentation improvements. + - The integrated web server is now more WSGI-compliant. + - Work has begun to solidify Mercurial's API for use by third-party + packages. + + 2006-05-10 v0.9 * Major changes between Mercurial 0.8.1 and 0.9: diff --git a/doc/hgrc.5.txt b/doc/hgrc.5.txt --- a/doc/hgrc.5.txt +++ b/doc/hgrc.5.txt @@ -138,9 +138,17 @@ email:: from;; Optional. Email address to use in "From" header and SMTP envelope of outgoing messages. + to;; + Optional. Comma-separated list of recipients' email addresses. + cc;; + Optional. Comma-separated list of carbon copy recipients' + email addresses. + bcc;; + Optional. Comma-separated list of blind carbon copy + recipients' email addresses. Cannot be set interactively. method;; Optional. Method to use to send email messages. If value is - "smtp" (default), use SMTP (see section "[mail]" for + "smtp" (default), use SMTP (see section "[smtp]" for configuration). Otherwise, use as name of program to run that acts like sendmail (takes "-f" option for sender, list of recipients on command line, message on stdin). Normally, setting @@ -194,7 +202,8 @@ hooks:: changegroup;; Run after a changegroup has been added via push, pull or - unbundle. ID of the first new changeset is in $HG_NODE. + unbundle. ID of the first new changeset is in $HG_NODE. URL from + which changes came is in $HG_URL. commit;; Run after a changeset has been created in the local repository. ID of the newly created changeset is in $HG_NODE. Parent @@ -202,7 +211,7 @@ hooks:: 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. + $HG_NODE. URL that was source of changes came is in $HG_URL. outgoing;; Run after sending changes from local repository to another. ID of first changeset sent is in $HG_NODE. Source of operation is in @@ -210,7 +219,8 @@ hooks:: 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. + will cause the push, pull or unbundle to fail. URL from which + changes will come is in $HG_URL. precommit;; Run before starting a local commit. Exit status 0 allows the commit to proceed. Non-zero status will cause the commit to fail. @@ -236,7 +246,8 @@ hooks:: 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. + the push, pull or unbundle will fail. URL that was source of + changes is in $HG_URL. pretxncommit;; Run after a changeset has been created but the transaction not yet committed. Changeset is visible to hook program. This lets you @@ -440,6 +451,9 @@ web:: push_ssl;; Whether to require that inbound pushes be transported over SSL to prevent password sniffing. Default is true. + stripes;; + How many lines a "zebra stripe" should span in multiline output. + Default is 1; set to 0 to disable. style;; Which template map style to use. templates;; diff --git a/hgext/extdiff.py b/hgext/extdiff.py --- a/hgext/extdiff.py +++ b/hgext/extdiff.py @@ -22,6 +22,9 @@ # cmd.vdiff = kdiff3 # # add new command called meld, runs meld (no need to name twice) # cmd.meld = +# # add new command called vimdiff, runs gvimdiff with DirDiff plugin +# #(see http://www.vim.org/scripts/script.php?script_id=102) +# cmd.vimdiff = LC_ALL=C gvim -f '+bdel 1 2' '+ execute "DirDiff ".argv(0)." ".argv(1)' # # you can use -I/-X and list of file or directory names like normal # "hg diff" command. extdiff makes snapshots of only needed files, so diff --git a/hgext/mq.py b/hgext/mq.py --- a/hgext/mq.py +++ b/hgext/mq.py @@ -257,7 +257,7 @@ class queue: head = self.qparents(repo) for patch in series: - patch = mergeq.lookup(patch) + patch = mergeq.lookup(patch, strict=True) if not patch: self.ui.warn("patch %s does not exist\n" % patch) return (1, None) @@ -380,7 +380,7 @@ class queue: return (err, n) def delete(self, repo, patch): - patch = self.lookup(patch) + patch = self.lookup(patch, strict=True) info = self.isapplied(patch) if info: self.ui.warn("cannot delete applied patch %s\n" % patch) @@ -418,7 +418,7 @@ class queue: commitfiles = c + a + r self.check_toppatch(repo) wlock = repo.wlock() - insert = self.series_end() + insert = self.full_series_end() if msg: n = repo.commit(commitfiles, "[mq]: %s" % msg, force=True, wlock=wlock) @@ -442,7 +442,7 @@ class queue: r = self.qrepo() if r: r.add([patch]) if commitfiles: - self.refresh(repo, short=True) + self.refresh(repo, msg=None, short=True) def strip(self, repo, rev, update=True, backup="all", wlock=None): def limitheads(chlog, stop): @@ -530,6 +530,9 @@ class queue: revnum = chlog.rev(rev) if update: + (c, a, r, d, u) = repo.changes(None, None) + if c or a or d or r: + raise util.Abort(_("Local changes found")) urev = self.qparents(repo, rev) repo.update(urev, allow=False, force=True, wlock=wlock) repo.dirstate.write() @@ -598,25 +601,79 @@ class queue: return (i, a[0], a[1]) return None - def lookup(self, patch): + # if the exact patch name does not exist, we try a few + # variations. If strict is passed, we try only #1 + # + # 1) a number to indicate an offset in the series file + # 2) a unique substring of the patch name was given + # 3) patchname[-+]num to indicate an offset in the series file + def lookup(self, patch, strict=False): + def partial_name(s): + count = 0 + if s in self.series: + return s + for x in self.series: + if s in x: + count += 1 + last = x + if count > 1: + return None + if count: + return last + if len(self.series) > 0 and len(self.applied) > 0: + if s == 'qtip': + return self.series[self.series_end()-1] + if s == 'qbase': + return self.series[0] + return None if patch == None: return None - if patch in self.series: - return patch + + # we don't want to return a partial match until we make + # sure the file name passed in does not exist (checked below) + res = partial_name(patch) + if res and res == patch: + return res + if not os.path.isfile(os.path.join(self.path, patch)): try: sno = int(patch) except(ValueError, OverflowError): - self.ui.warn("patch %s not in series\n" % patch) - sys.exit(1) - if sno >= len(self.series): - self.ui.warn("patch number %d is out of range\n" % sno) - sys.exit(1) - patch = self.series[sno] - else: - self.ui.warn("patch %s not in series\n" % patch) - sys.exit(1) - return patch + pass + else: + if sno < len(self.series): + patch = self.series[sno] + return patch + if not strict: + # return any partial match made above + if res: + return res + minus = patch.rsplit('-', 1) + if len(minus) > 1: + res = partial_name(minus[0]) + if res: + i = self.series.index(res) + try: + off = int(minus[1] or 1) + except(ValueError, OverflowError): + pass + else: + if i - off >= 0: + return self.series[i - off] + plus = patch.rsplit('+', 1) + if len(plus) > 1: + res = partial_name(plus[0]) + if res: + i = self.series.index(res) + try: + off = int(plus[1] or 1) + except(ValueError, OverflowError): + pass + else: + if i + off < len(self.series): + return self.series[i + off] + self.ui.warn("patch %s not in series\n" % patch) + sys.exit(1) def push(self, repo, patch=None, force=False, list=False, mergeq=None, wlock=None): @@ -654,7 +711,8 @@ class queue: self.ui.write("Now at: %s\n" % top) return ret[0] - def pop(self, repo, patch=None, force=False, update=True, wlock=None): + def pop(self, repo, patch=None, force=False, update=True, all=False, + wlock=None): def getfile(f, rev): t = repo.file(f).read(rev) try: @@ -695,7 +753,17 @@ class queue: self.applied_dirty = 1; end = len(self.applied) if not patch: - info = [len(self.applied) - 1] + self.applied[-1].split(':') + if all: + popi = 0 + else: + popi = len(self.applied) - 1 + else: + popi = info[0] + 1 + if popi >= end: + self.ui.warn("qpop: %s is already at the top\n" % patch) + return + info = [ popi ] + self.applied[popi].split(':') + start = info[0] rev = revlog.bin(info[1]) @@ -739,7 +807,7 @@ class queue: qp = self.qparents(repo, top) commands.dodiff(sys.stdout, self.ui, repo, qp, None, files) - def refresh(self, repo, short=False): + def refresh(self, repo, msg=None, short=False): if len(self.applied) == 0: self.ui.write("No patches applied\n") return @@ -822,10 +890,14 @@ class queue: repo.dirstate.update(c, 'n') repo.dirstate.forget(forget) - if not message: - message = "patch queue: %s\n" % patch + if not msg: + if not message: + message = "patch queue: %s\n" % patch + else: + message = "\n".join(message) else: - message = "\n".join(message) + message = msg + self.strip(repo, top, update=False, backup='strip', wlock=wlock) n = repo.commit(filelist, message, changes[1], force=1, wlock=wlock) self.applied[-1] = revlog.hex(n) + ':' + patch @@ -852,6 +924,8 @@ class queue: else: start = self.series.index(patch) + 1 for p in self.series[start:]: + if self.ui.verbose: + self.ui.write("%d " % self.series.index(p)) self.ui.write("%s\n" % p) def qseries(self, repo, missing=None): @@ -974,6 +1048,15 @@ class queue: self.applied.append(revlog.hex(n) + ":" + '.hg.patches.save.line') self.applied_dirty = 1 + def full_series_end(self): + if len(self.applied) > 0: + (top, p) = self.applied[-1].split(':') + end = self.find_series(p) + if end == None: + return len(self.full_series) + return end + 1 + return 0 + def series_end(self): end = 0 if len(self.applied) > 0: @@ -999,8 +1082,11 @@ class queue: def appliedname(self, index): p = self.applied[index] + pname = p.split(':')[1] if not self.ui.verbose: - p = p.split(':')[1] + p = pname + else: + p = str(self.series.index(pname)) + " " + p return p def top(self, repo): @@ -1015,7 +1101,10 @@ class queue: if end == len(self.series): self.ui.write("All patches applied\n") else: - self.ui.write(self.series[end] + '\n') + p = self.series[end] + if self.ui.verbose: + self.ui.write("%d " % self.series.index(p)) + self.ui.write(p + '\n') def prev(self, repo): if len(self.applied) > 1: @@ -1055,7 +1144,7 @@ class queue: if patch in self.series: self.ui.warn("patch %s is already in the series file\n" % patch) sys.exit(1) - index = self.series_end() + i + index = self.full_series_end() + i self.full_series[index:index] = [patch] self.read_series(self.full_series) self.ui.warn("adding %s to series file\n" % patch) @@ -1136,14 +1225,16 @@ def prev(ui, repo, **opts): def new(ui, repo, patch, **opts): """create a new patch""" q = repomap[repo] - q.new(repo, patch, msg=opts['message'], force=opts['force']) + message=commands.logmessage(**opts) + q.new(repo, patch, msg=message, force=opts['force']) q.save_dirty() return 0 def refresh(ui, repo, **opts): """update the current patch""" q = repomap[repo] - q.refresh(repo, short=opts['short']) + message=commands.logmessage(**opts) + q.refresh(repo, msg=message, short=opts['short']) q.save_dirty() return 0 @@ -1208,9 +1299,7 @@ def pop(ui, repo, patch=None, **opts): localupdate = False else: q = repomap[repo] - if opts['all'] and len(q.applied) > 0: - patch = q.applied[0].split(':')[1] - q.pop(repo, patch, force=opts['force'], update=localupdate) + q.pop(repo, patch, force=opts['force'], update=localupdate, all=opts['all']) q.save_dirty() return 0 @@ -1226,7 +1315,8 @@ def restore(ui, repo, rev, **opts): def save(ui, repo, **opts): """save current queue state""" q = repomap[repo] - ret = q.save(repo, msg=opts['message']) + message=commands.logmessage(**opts) + ret = q.save(repo, msg=message) if ret: return ret q.save_dirty() @@ -1272,28 +1362,30 @@ def version(ui, q=None): def reposetup(ui, repo): repomap[repo] = queue(ui, repo.join("")) - oldlookup = repo.lookup + oldtags = repo.tags + + def qtags(): + if repo.tagscache: + return repo.tagscache - def qlookup(key): - try: - return oldlookup(key) - except hg.RepoError: - q = repomap[repo] + tagscache = oldtags() + + q = repomap[repo] + if len(q.applied) == 0: + return tagscache - qpatchnames = { 'qtip': -1, 'qbase': 0 } - if key in qpatchnames: - if len(q.applied) == 0: - self.ui.warn('No patches applied\n') - raise - patch = q.applied[qpatchnames[key]].split(':')[0] - return revlog.bin(patch) + mqtags = [patch.split(':') for patch in q.applied] + mqtags.append((mqtags[-1][0], 'qtip')) + mqtags.append((mqtags[0][0], 'qbase')) + for patch in mqtags: + if patch[1] in tagscache: + repo.ui.warn('Tag %s overrides mq patch of the same name\n' % patch[1]) + else: + tagscache[patch[1]] = revlog.bin(patch[0]) - patch = q.isapplied(key) - if not patch: - raise - return revlog.bin(patch[1]) + return tagscache - repo.lookup = qlookup + repo.tags = qtags cmdtable = { "qapplied": (applied, [], 'hg qapplied [PATCH]'), @@ -1315,9 +1407,10 @@ cmdtable = { 'hg qinit [-c]'), "qnew": (new, - [('m', 'message', '', 'commit message'), + [('m', 'message', '', _('use as commit message')), + ('l', 'logfile', '', _('read the commit message from ')), ('f', 'force', None, 'force')], - 'hg qnew [-m TEXT] [-f] PATCH'), + 'hg qnew [-m TEXT] [-l FILE] [-f] PATCH'), "qnext": (next, [], 'hg qnext'), "qprev": (prev, [], 'hg qprev'), "^qpop": @@ -1336,8 +1429,10 @@ cmdtable = { 'hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]'), "^qrefresh": (refresh, - [('s', 'short', None, 'short refresh')], - 'hg qrefresh [-s]'), + [('m', 'message', '', _('change commit message with ')), + ('l', 'logfile', '', _('change commit message with content')), + ('s', 'short', None, 'short refresh')], + 'hg qrefresh [-m TEXT] [-l FILE] [-s]'), "qrestore": (restore, [('d', 'delete', None, 'delete save entry'), @@ -1345,12 +1440,13 @@ cmdtable = { 'hg qrestore [-d] [-u] REV'), "qsave": (save, - [('m', 'message', '', 'commit message'), + [('m', 'message', '', _('use as commit message')), + ('l', 'logfile', '', _('read the commit message from ')), ('c', 'copy', None, 'copy patch directory'), ('n', 'name', '', 'copy directory name'), ('e', 'empty', None, 'clear queue status file'), ('f', 'force', None, 'force copy')], - 'hg qsave [-m TEXT] [-c] [-n NAME] [-e] [-f]'), + 'hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'), "qseries": (series, [('m', 'missing', None, 'print patches not in series')], diff --git a/hgext/patchbomb.py b/hgext/patchbomb.py --- a/hgext/patchbomb.py +++ b/hgext/patchbomb.py @@ -38,6 +38,7 @@ # from = My Name # to = recipient1, recipient2, ... # cc = cc1, cc2, ... +# bcc = bcc1, bcc2, ... from mercurial.demandload import * demandload(globals(), '''email.MIMEMultipart email.MIMEText email.Utils @@ -185,6 +186,10 @@ def patchbomb(ui, repo, *revs, **opts): to = getaddrs('to', 'To') cc = getaddrs('cc', 'Cc', '') + bcc = opts['bcc'] or (ui.config('email', 'bcc') or + ui.config('patchbomb', 'bcc') or '').split(',') + bcc = [a.strip() for a in bcc if a.strip()] + if len(patches) > 1: ui.write(_('\nWrite the introductory message for the patch series.\n\n')) @@ -242,7 +247,8 @@ def patchbomb(ui, repo, *revs, **opts): start_time += 1 m['From'] = sender m['To'] = ', '.join(to) - if cc: m['Cc'] = ', '.join(cc) + if cc: m['Cc'] = ', '.join(cc) + if bcc: m['Bcc'] = ', '.join(bcc) if opts['test']: ui.status('Displaying ', m['Subject'], ' ...\n') fp = os.popen(os.getenv('PAGER', 'more'), 'w') @@ -263,12 +269,13 @@ def patchbomb(ui, repo, *revs, **opts): fp.close() else: ui.status('Sending ', m['Subject'], ' ...\n') - mail.sendmail(sender, to + cc, m.as_string(0)) + mail.sendmail(sender, to + bcc + cc, m.as_string(0)) cmdtable = { 'email': (patchbomb, - [('c', 'cc', [], 'email addresses of copy recipients'), + [('', 'bcc', [], 'email addresses of blind copy recipients'), + ('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'), diff --git a/mercurial/bundlerepo.py b/mercurial/bundlerepo.py --- a/mercurial/bundlerepo.py +++ b/mercurial/bundlerepo.py @@ -159,6 +159,10 @@ class bundlefilelog(bundlerevlog, filelo class bundlerepository(localrepo.localrepository): def __init__(self, ui, path, bundlename): localrepo.localrepository.__init__(self, ui, path) + + self._url = 'bundle:' + bundlename + if path: self._url += '+' + path + self.tempfile = None self.bundlefile = open(bundlename, "rb") header = self.bundlefile.read(6) @@ -208,6 +212,9 @@ class bundlerepository(localrepo.localre for c in changegroup.chunkiter(self.bundlefile): pass + def url(self): + return self._url + def dev(self): return -1 diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -40,6 +40,25 @@ def relpath(repo, args): return [util.normpath(os.path.join(cwd, x)) for x in args] return args +def logmessage(**opts): + """ get the log message according to -m and -l option """ + message = opts['message'] + logfile = opts['logfile'] + + if message and logfile: + raise util.Abort(_('options --message and --logfile are mutually ' + 'exclusive')) + if not message and logfile: + try: + if logfile == '-': + message = sys.stdin.read() + else: + message = open(logfile).read() + except IOError, inst: + raise util.Abort(_("can't read commit message '%s': %s") % + (logfile, inst.strerror)) + return message + def matchpats(repo, pats=[], opts={}, head=''): cwd = repo.getcwd() if not pats and cwd: @@ -989,21 +1008,7 @@ def commit(ui, repo, *pats, **opts): If no commit message is specified, the editor configured in your hgrc or in the EDITOR environment variable is started to enter a message. """ - message = opts['message'] - logfile = opts['logfile'] - - if message and logfile: - raise util.Abort(_('options --message and --logfile are mutually ' - 'exclusive')) - if not message and logfile: - try: - if logfile == '-': - message = sys.stdin.read() - else: - message = open(logfile).read() - except IOError, inst: - raise util.Abort(_("can't read commit message '%s': %s") % - (logfile, inst.strerror)) + message = logmessage(**opts) if opts['addremove']: addremove_lock(ui, repo, pats, opts) @@ -2763,7 +2768,8 @@ def unbundle(ui, repo, fname, **opts): raise util.Abort(_("%s: unknown bundle compression type") % fname) gen = generator(util.filechunkiter(f, 4096)) - modheads = repo.addchangegroup(util.chunkbuffer(gen), 'unbundle') + modheads = repo.addchangegroup(util.chunkbuffer(gen), 'unbundle', + 'bundle:' + fname) return postincoming(ui, repo, modheads, opts['update']) def undo(ui, repo): diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py --- a/mercurial/dirstate.py +++ b/mercurial/dirstate.py @@ -344,6 +344,10 @@ class dirstate(object): # directly by this function, but might be modified by your statmatch call. # def walkhelper(self, files, statmatch, dc, badmatch=None): + # self.root may end with a path separator when self.root == '/' + common_prefix_len = len(self.root) + if not self.root.endswith('/'): + common_prefix_len += 1 # recursion free walker, faster than os.walk. def findfiles(s): work = [s] @@ -352,7 +356,7 @@ class dirstate(object): names = os.listdir(top) names.sort() # nd is the top of the repository dir tree - nd = util.normpath(top[len(self.root) + 1:]) + nd = util.normpath(top[common_prefix_len:]) if nd == '.': nd = '' else: diff --git a/mercurial/hgweb/hgweb_mod.py b/mercurial/hgweb/hgweb_mod.py --- a/mercurial/hgweb/hgweb_mod.py +++ b/mercurial/hgweb/hgweb_mod.py @@ -37,6 +37,7 @@ class hgweb(object): self.mtime = -1 self.reponame = name self.archives = 'zip', 'gz', 'bz2' + self.stripecount = 1 self.templatepath = self.repo.ui.config("web", "templates", templater.templatepath()) @@ -46,6 +47,8 @@ class hgweb(object): self.mtime = mtime self.repo = hg.repository(self.repo.ui, self.repo.root) self.maxchanges = int(self.repo.ui.config("web", "maxchanges", 10)) + self.stripecount = int(self.repo.ui.config("web", "stripes", 1)) + self.maxshortchanges = int(self.repo.ui.config("web", "maxshortchanges", 60)) self.maxfiles = int(self.repo.ui.config("web", "maxfiles", 10)) self.allowpull = self.repo.ui.configbool("web", "allowpull", True) @@ -158,7 +161,7 @@ class hgweb(object): ignorewsamount=ignorewsamount, ignoreblanklines=ignoreblanklines), f, tn) - def changelog(self, pos): + def changelog(self, pos, shortlog=False): def changenav(**map): def seq(factor, maxchanges=None): if maxchanges: @@ -173,8 +176,9 @@ class hgweb(object): l = [] last = 0 - for f in seq(1, self.maxchanges): - if f < self.maxchanges or f <= last: + maxchanges = shortlog and self.maxshortchanges or self.maxchanges + for f in seq(1, maxchanges): + if f < maxchanges or f <= last: continue if f > count: break @@ -219,14 +223,15 @@ class hgweb(object): for e in l: yield e + maxchanges = shortlog and self.maxshortchanges or self.maxchanges cl = self.repo.changelog mf = cl.read(cl.tip())[0] count = cl.count() - start = max(0, pos - self.maxchanges + 1) - end = min(count, start + self.maxchanges) + start = max(0, pos - maxchanges + 1) + end = min(count, start + maxchanges) pos = end - 1 - yield self.t('changelog', + yield self.t(shortlog and 'shortlog' or 'changelog', changenav=changenav, manifest=hex(mf), rev=pos, changesets=count, entries=changelist, @@ -265,7 +270,7 @@ class hgweb(object): hn = hex(n) yield self.t('searchentry', - parity=count & 1, + parity=self.stripes(count), author=changes[1], parent=self.siblings(cl.parents(n), cl.rev), child=self.siblings(cl.children(n), cl.rev), @@ -376,7 +381,7 @@ class hgweb(object): for l, t in enumerate(text.splitlines(1)): yield {"line": t, "linenumber": "% 6d" % (l + 1), - "parity": l & 1} + "parity": self.stripes(l)} yield self.t("filerevision", file=f, @@ -409,7 +414,7 @@ class hgweb(object): mfn = cs[0] def annotate(**map): - parity = 1 + parity = 0 last = None for r, l in fl.annotate(n): try: @@ -489,10 +494,10 @@ class hgweb(object): yield {"file": full, "manifest": mnode, "filenode": hex(fnode), - "parity": parity, + "parity": self.stripes(parity), "basename": f, "permissions": mff[full]} - parity = 1 - parity + parity += 1 def dirlist(**map): parity = 0 @@ -503,11 +508,11 @@ class hgweb(object): if fnode: continue - yield {"parity": parity, + yield {"parity": self.stripes(parity), "path": os.path.join(path, f), "manifest": mnode, "basename": f[:-1]} - parity = 1 - parity + parity += 1 yield self.t("manifest", manifest=mnode, @@ -530,12 +535,12 @@ class hgweb(object): parity = 0 for k,n in i: if notip and k == "tip": continue - yield {"parity": parity, + yield {"parity": self.stripes(parity), "tag": k, "tagmanifest": hex(cl.read(n)[0]), "date": cl.read(n)[2], "node": hex(n)} - parity = 1 - parity + parity += 1 yield self.t("tags", manifest=hex(mf), @@ -565,12 +570,12 @@ class hgweb(object): t = c[2] yield self.t("tagentry", - parity = parity, + parity = self.stripes(parity), tag = k, node = hex(n), date = t, tagmanifest = hex(m)) - parity = 1 - parity + parity += 1 def changelist(**map): parity = 0 @@ -609,7 +614,8 @@ class hgweb(object): lastchange = (0, 0), # FIXME manifest = hex(mf), tags = tagentries, - shortlog = changelist) + shortlog = changelist, + archives=self.archivelist("tip")) def filediff(self, file, changeset): cl = self.repo.changelog @@ -689,6 +695,7 @@ class hgweb(object): def expand_form(form): shortcuts = { 'cl': [('cmd', ['changelog']), ('rev', None)], + 'sl': [('cmd', ['shortlog']), ('rev', None)], 'cs': [('cmd', ['changeset']), ('node', None)], 'f': [('cmd', ['file']), ('filenode', None)], 'fl': [('cmd', ['filelog']), ('filenode', None)], @@ -752,6 +759,13 @@ class hgweb(object): else: req.write(self.t("error")) + def stripes(self, parity): + "make horizontal stripes for easier reading" + if self.stripecount: + return (1 + parity / self.stripecount) & 1 + else: + return 0 + def do_changelog(self, req): hi = self.repo.changelog.count() - 1 if req.form.has_key('rev'): @@ -764,6 +778,18 @@ class hgweb(object): req.write(self.changelog(hi)) + def do_shortlog(self, req): + hi = self.repo.changelog.count() - 1 + if req.form.has_key('rev'): + hi = req.form['rev'][0] + try: + hi = self.repo.changelog.rev(self.repo.lookup(hi)) + except hg.RepoError: + req.write(self.search(hi)) # XXX redirect to 404 page? + return + + req.write(self.changelog(hi, shortlog = True)) + def do_changeset(self, req): req.write(self.changeset(req.form['node'][0])) @@ -895,9 +921,13 @@ class hgweb(object): # require ssl by default, auth info cannot be sniffed and # replayed ssl_req = self.repo.ui.configbool('web', 'push_ssl', True) - if ssl_req and not req.env.get('HTTPS'): - bail(_('ssl required\n')) - return + if ssl_req: + if not req.env.get('HTTPS'): + bail(_('ssl required\n')) + return + proto = 'https' + else: + proto = 'http' # do not allow push unless explicitly allowed if not self.check_perm(req, 'push', False): @@ -943,7 +973,9 @@ class hgweb(object): sys.stdout = cStringIO.StringIO() try: - ret = self.repo.addchangegroup(fp, 'serve') + url = 'remote:%s:%s' % (proto, + req.env.get('REMOTE_HOST', '')) + ret = self.repo.addchangegroup(fp, 'serve', url) finally: val = sys.stdout.getvalue() sys.stdout = old_stdout diff --git a/mercurial/httprepo.py b/mercurial/httprepo.py --- a/mercurial/httprepo.py +++ b/mercurial/httprepo.py @@ -115,6 +115,7 @@ else: class httprepository(remoterepository): def __init__(self, ui, path): + self.path = path self.caps = None scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path) if query or frag: @@ -124,8 +125,8 @@ class httprepository(remoterepository): host, port, user, passwd = netlocsplit(netloc) # urllib cannot handle URLs with embedded user or passwd - self.url = urlparse.urlunsplit((scheme, netlocunsplit(host, port), - urlpath, '', '')) + self._url = urlparse.urlunsplit((scheme, netlocunsplit(host, port), + urlpath, '', '')) self.ui = ui proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy') @@ -189,6 +190,9 @@ class httprepository(remoterepository): opener.addheaders = [('User-agent', 'mercurial/proto-1.0')] urllib2.install_opener(opener) + def url(self): + return self.path + # look up capabilities only when needed def get_caps(self): @@ -213,7 +217,7 @@ class httprepository(remoterepository): q = {"cmd": cmd} q.update(args) qs = urllib.urlencode(q) - cu = "%s?%s" % (self.url, qs) + cu = "%s?%s" % (self._url, qs) try: resp = urllib2.urlopen(urllib2.Request(cu, data, headers)) except urllib2.HTTPError, inst: @@ -234,13 +238,13 @@ class httprepository(remoterepository): not proto.startswith('text/plain') and \ not proto.startswith('application/hg-changegroup'): raise hg.RepoError(_("'%s' does not appear to be an hg repository") % - self.url) + self._url) if proto.startswith('application/mercurial'): version = proto[22:] if float(version) > 0.1: raise hg.RepoError(_("'%s' uses newer protocol %s") % - (self.url, version)) + (self._url, version)) return resp diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -83,6 +83,9 @@ class localrepository(repo.repository): self.dirstate = dirstate.dirstate(self.opener, self.ui, self.root) + def url(self): + return 'file:' + self.root + def hook(self, name, throw=False, **args): def callhook(hname, funcname): '''call python hook. hook is callable object, looked up as @@ -1185,7 +1188,7 @@ class localrepository(repo.repository): cg = remote.changegroup(fetch, 'pull') else: cg = remote.changegroupsubset(fetch, heads, 'pull') - return self.addchangegroup(cg, 'pull') + return self.addchangegroup(cg, 'pull', remote.url()) def push(self, remote, force=False, revs=None): # there are two ways to push to remote repo: @@ -1241,7 +1244,7 @@ class localrepository(repo.repository): ret = self.prepush(remote, force, revs) if ret[0] is not None: cg, remote_heads = ret - return remote.addchangegroup(cg, 'push') + return remote.addchangegroup(cg, 'push', self.url()) return ret[1] def push_unbundle(self, remote, force, revs): @@ -1594,7 +1597,7 @@ class localrepository(repo.repository): return util.chunkbuffer(gengroup()) - def addchangegroup(self, source, srctype): + def addchangegroup(self, source, srctype, url): """add changegroup to repo. returns number of heads modified or added + 1.""" @@ -1608,7 +1611,7 @@ class localrepository(repo.repository): if not source: return 0 - self.hook('prechangegroup', throw=True, source=srctype) + self.hook('prechangegroup', throw=True, source=srctype, url=url) changesets = files = revisions = 0 @@ -1675,17 +1678,18 @@ class localrepository(repo.repository): if changesets > 0: self.hook('pretxnchangegroup', throw=True, - node=hex(self.changelog.node(cor+1)), source=srctype) + node=hex(self.changelog.node(cor+1)), source=srctype, + url=url) tr.close() if changesets > 0: self.hook("changegroup", node=hex(self.changelog.node(cor+1)), - source=srctype) + source=srctype, url=url) for i in range(cor + 1, cnr + 1): self.hook("incoming", node=hex(self.changelog.node(i)), - source=srctype) + source=srctype, url=url) return newheads - oldheads + 1 diff --git a/mercurial/sshrepo.py b/mercurial/sshrepo.py --- a/mercurial/sshrepo.py +++ b/mercurial/sshrepo.py @@ -13,7 +13,7 @@ demandload(globals(), "hg os re stat uti class sshrepository(remoterepository): def __init__(self, ui, path, create=0): - self.url = path + self._url = path self.ui = ui m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', path) @@ -48,6 +48,9 @@ class sshrepository(remoterepository): self.validate_repo(ui, sshcmd, args, remotecmd) + def url(self): + return self._url + def validate_repo(self, ui, sshcmd, args, remotecmd): cmd = '%s %s "%s -R %s serve --stdio"' cmd = cmd % (sshcmd, args, remotecmd, self.path) @@ -180,7 +183,7 @@ class sshrepository(remoterepository): return 1 return int(r) - def addchangegroup(self, cg, source): + def addchangegroup(self, cg, source, url): d = self.call("addchangegroup") if d: raise hg.RepoError(_("push refused: %s") % d) diff --git a/mercurial/sshserver.py b/mercurial/sshserver.py --- a/mercurial/sshserver.py +++ b/mercurial/sshserver.py @@ -117,9 +117,13 @@ class sshserver(object): return self.respond("") - r = self.repo.addchangegroup(self.fin, 'serve') + r = self.repo.addchangegroup(self.fin, 'serve', self.client_url()) self.respond(str(r)) + def client_url(self): + client = os.environ.get('SSH_CLIENT', '').split(' ', 1)[0] + return 'remote:ssh:' + client + def do_unbundle(self): their_heads = self.getarg()[1].split() @@ -159,7 +163,7 @@ class sshserver(object): # push can proceed fp.seek(0) - r = self.repo.addchangegroup(fp, 'serve') + r = self.repo.addchangegroup(fp, 'serve', self.client_url()) self.respond(str(r)) finally: if not was_locked: diff --git a/mercurial/statichttprepo.py b/mercurial/statichttprepo.py --- a/mercurial/statichttprepo.py +++ b/mercurial/statichttprepo.py @@ -30,6 +30,7 @@ def opener(base): class statichttprepository(localrepo.localrepository): def __init__(self, ui, path): + self._url = path self.path = (path + "/.hg") self.ui = ui self.revlogversion = 0 @@ -41,6 +42,9 @@ class statichttprepository(localrepo.loc self.encodepats = None self.decodepats = None + def url(self): + return 'static-' + self._url + def dev(self): return -1 diff --git a/templates/changelog-gitweb.tmpl b/templates/changelog-gitweb.tmpl --- a/templates/changelog-gitweb.tmpl +++ b/templates/changelog-gitweb.tmpl @@ -20,7 +20,7 @@ diff --git a/templates/changelog.tmpl b/templates/changelog.tmpl --- a/templates/changelog.tmpl +++ b/templates/changelog.tmpl @@ -6,6 +6,7 @@
+shortlog tags manifest #archives%archiveentry# diff --git a/templates/changeset-gitweb.tmpl b/templates/changeset-gitweb.tmpl --- a/templates/changeset-gitweb.tmpl +++ b/templates/changeset-gitweb.tmpl @@ -10,7 +10,7 @@
diff --git a/templates/changeset.tmpl b/templates/changeset.tmpl --- a/templates/changeset.tmpl +++ b/templates/changeset.tmpl @@ -5,6 +5,7 @@
changelog +shortlog tags manifest raw diff --git a/templates/error-gitweb.tmpl b/templates/error-gitweb.tmpl --- a/templates/error-gitweb.tmpl +++ b/templates/error-gitweb.tmpl @@ -10,7 +10,7 @@
diff --git a/templates/fileannotate-gitweb.tmpl b/templates/fileannotate-gitweb.tmpl --- a/templates/fileannotate-gitweb.tmpl +++ b/templates/fileannotate-gitweb.tmpl @@ -10,7 +10,7 @@
#file|escape#
diff --git a/templates/fileannotate.tmpl b/templates/fileannotate.tmpl --- a/templates/fileannotate.tmpl +++ b/templates/fileannotate.tmpl @@ -5,6 +5,7 @@
changelog +shortlog tags changeset manifest diff --git a/templates/filediff.tmpl b/templates/filediff.tmpl --- a/templates/filediff.tmpl +++ b/templates/filediff.tmpl @@ -5,6 +5,7 @@
changelog +shortlog tags changeset file diff --git a/templates/filelog-gitweb.tmpl b/templates/filelog-gitweb.tmpl --- a/templates/filelog-gitweb.tmpl +++ b/templates/filelog-gitweb.tmpl @@ -10,7 +10,7 @@
#file|urlescape#
diff --git a/templates/filelog.tmpl b/templates/filelog.tmpl --- a/templates/filelog.tmpl +++ b/templates/filelog.tmpl @@ -8,6 +8,7 @@
changelog +shortlog tags file annotate diff --git a/templates/filerevision-gitweb.tmpl b/templates/filerevision-gitweb.tmpl --- a/templates/filerevision-gitweb.tmpl +++ b/templates/filerevision-gitweb.tmpl @@ -10,7 +10,7 @@
#file|escape#
diff --git a/templates/filerevision.tmpl b/templates/filerevision.tmpl --- a/templates/filerevision.tmpl +++ b/templates/filerevision.tmpl @@ -5,6 +5,7 @@
changelog +shortlog tags changeset manifest diff --git a/templates/manifest-gitweb.tmpl b/templates/manifest-gitweb.tmpl --- a/templates/manifest-gitweb.tmpl +++ b/templates/manifest-gitweb.tmpl @@ -10,7 +10,7 @@
#path|escape#
diff --git a/templates/manifest.tmpl b/templates/manifest.tmpl --- a/templates/manifest.tmpl +++ b/templates/manifest.tmpl @@ -5,6 +5,7 @@
changelog +shortlog tags changeset #archives%archiveentry# diff --git a/templates/map b/templates/map --- a/templates/map +++ b/templates/map @@ -3,7 +3,10 @@ header = header.tmpl footer = footer.tmpl search = search.tmpl changelog = changelog.tmpl +shortlog = shortlog.tmpl +shortlogentry = shortlogentry.tmpl naventry = '#label|escape# ' +navshortentry = '#label|escape# ' filedifflink = '#file|escape# ' filenodelink = '#file|escape# ' fileellipses = '...' diff --git a/templates/search-gitweb.tmpl b/templates/search-gitweb.tmpl --- a/templates/search-gitweb.tmpl +++ b/templates/search-gitweb.tmpl @@ -1,6 +1,6 @@ #header#

searching for #query|escape#

diff --git a/templates/search.tmpl b/templates/search.tmpl --- a/templates/search.tmpl +++ b/templates/search.tmpl @@ -5,6 +5,7 @@ diff --git a/templates/shortlog-gitweb.tmpl b/templates/shortlog-gitweb.tmpl --- a/templates/shortlog-gitweb.tmpl +++ b/templates/shortlog-gitweb.tmpl @@ -1,13 +1,32 @@ #header# +#repo|escape#: Shortlog + + + + + +
+ +
+
-#entries# +#entries%shortlogentry#
#footer# diff --git a/templates/shortlog.tmpl b/templates/shortlog.tmpl new file mode 100644 --- /dev/null +++ b/templates/shortlog.tmpl @@ -0,0 +1,38 @@ +#header# +#repo|escape#: shortlog + + + + +
+changelog +tags +manifest +#archives%archiveentry# +rss +
+ +

shortlog for #repo|escape#

+ +
+

+ + + +navigate: #changenav%navshortentry# +

+
+ +#entries%shortlogentry# + +
+

+ + + +navigate: #changenav%navshortentry# +

+
+ +#footer# diff --git a/templates/shortlogentry.tmpl b/templates/shortlogentry.tmpl new file mode 100644 --- /dev/null +++ b/templates/shortlogentry.tmpl @@ -0,0 +1,7 @@ + + + + + + +
#date|age##author|obfuscate##desc|strip|firstline|escape#
diff --git a/templates/static/style.css b/templates/static/style.css --- a/templates/static/style.css +++ b/templates/static/style.css @@ -57,6 +57,12 @@ pre { margin: 0; } .logEntry th.age, .logEntry th.firstline { font-weight: bold; } .logEntry th.firstline { text-align: left; width: inherit; } +/* Shortlog entries */ +.slogEntry { width: 100%; font-size: smaller; } +.slogEntry .age { width: 7%; } +.slogEntry td { font-weight: normal; text-align: left; vertical-align: top; } +.slogEntry td.author { width: 35%; } + /* Tag entries */ #tagEntries { list-style: none; margin: 0; padding: 0; } #tagEntries .tagEntry { list-style: none; margin: 0; padding: 0; } diff --git a/templates/summary-gitweb.tmpl b/templates/summary-gitweb.tmpl --- a/templates/summary-gitweb.tmpl +++ b/templates/summary-gitweb.tmpl @@ -9,7 +9,8 @@
Mercurial
#repo|escape# / summary
 
diff --git a/templates/tags-gitweb.tmpl b/templates/tags-gitweb.tmpl --- a/templates/tags-gitweb.tmpl +++ b/templates/tags-gitweb.tmpl @@ -10,7 +10,7 @@
diff --git a/templates/tags.tmpl b/templates/tags.tmpl --- a/templates/tags.tmpl +++ b/templates/tags.tmpl @@ -7,6 +7,7 @@ diff --git a/tests/run-tests.py b/tests/run-tests.py --- a/tests/run-tests.py +++ b/tests/run-tests.py @@ -25,7 +25,7 @@ parser = optparse.OptionParser("%prog [o parser.add_option("-v", "--verbose", action="store_true", help="output verbose messages") parser.add_option("-t", "--timeout", type="int", - help="output verbose messages") + help="kill errant tests after TIMEOUT seconds") parser.add_option("-c", "--cover", action="store_true", help="print a test coverage report") parser.add_option("-s", "--cover_stdlib", action="store_true", diff --git a/tests/test-bundle b/tests/test-bundle --- a/tests/test-bundle +++ b/tests/test-bundle @@ -38,6 +38,8 @@ rm -rf empty hg init empty cd empty hg -R bundle://../full.hg log +echo '[hooks]' >> .hg/hgrc +echo 'changegroup = echo changegroup: u=$HG_URL' >> .hg/hgrc #doesn't work (yet ?) #hg -R bundle://../full.hg verify hg pull bundle://../full.hg diff --git a/tests/test-bundle.out b/tests/test-bundle.out --- a/tests/test-bundle.out +++ b/tests/test-bundle.out @@ -81,6 +81,7 @@ user: test date: Mon Jan 12 13:46:40 1970 +0000 summary: 0.0 +changegroup: u=bundle:../full.hg pulling from bundle://../full.hg requesting all changes adding changesets diff --git a/tests/test-hook b/tests/test-hook --- a/tests/test-hook +++ b/tests/test-hook @@ -17,9 +17,9 @@ 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 +echo 'prechangegroup = echo prechangegroup hook: u=`echo $HG_URL | sed s,file:.*,file:,`' >> .hg/hgrc +echo 'changegroup = echo changegroup hook: n=$HG_NODE u=`echo $HG_URL | sed s,file:.*,file:,`' >> .hg/hgrc +echo 'incoming = echo incoming hook: n=$HG_NODE u=`echo $HG_URL | sed s,file:.*,file:,`' >> .hg/hgrc # pretxncommit and commit hooks can see both parents of merge cd ../a diff --git a/tests/test-hook.out b/tests/test-hook.out --- a/tests/test-hook.out +++ b/tests/test-hook.out @@ -22,11 +22,11 @@ pretxncommit hook: n=4c52fb2e402287dd5dc 3:4c52fb2e4022 commit hook: n=4c52fb2e402287dd5dc052090682536c8406c321 p1=1324a5531bac09b329c3845d35ae6a7526874edb p2=b702efe9688826e3a91283852b328b84dbf37bc2 commit hook b -prechangegroup hook -changegroup hook: n=b702efe9688826e3a91283852b328b84dbf37bc2 -incoming hook: n=b702efe9688826e3a91283852b328b84dbf37bc2 -incoming hook: n=1324a5531bac09b329c3845d35ae6a7526874edb -incoming hook: n=4c52fb2e402287dd5dc052090682536c8406c321 +prechangegroup hook: u=file: +changegroup hook: n=b702efe9688826e3a91283852b328b84dbf37bc2 u=file: +incoming hook: n=b702efe9688826e3a91283852b328b84dbf37bc2 u=file: +incoming hook: n=1324a5531bac09b329c3845d35ae6a7526874edb u=file: +incoming hook: n=4c52fb2e402287dd5dc052090682536c8406c321 u=file: pulling from ../a searching for changes adding changesets diff --git a/tests/test-http b/tests/test-http --- a/tests/test-http +++ b/tests/test-http @@ -4,22 +4,31 @@ hg init test cd test echo foo>foo hg commit -A -d '0 0' -m 1 -hg --config server.uncompressed=True serve -p 20059 -d --pid-file=hg1.pid -cat hg1.pid >> $DAEMON_PIDS -hg serve -p 20060 -d --pid-file=hg2.pid -cat hg2.pid >> $DAEMON_PIDS +hg --config server.uncompressed=True serve -p 20059 -d --pid-file=../hg1.pid +hg serve -p 20060 -d --pid-file=../hg2.pid cd .. +cat hg1.pid hg2.pid >> $DAEMON_PIDS echo % clone via stream http_proxy= hg clone --uncompressed http://localhost:20059/ copy 2>&1 | \ sed -e 's/[0-9][0-9.]*/XXX/g' -cd copy -hg verify +hg verify -R copy echo % try to clone via stream, should use pull instead http_proxy= hg clone --uncompressed http://localhost:20060/ copy2 echo % clone via pull http_proxy= hg clone http://localhost:20059/ copy-pull +hg verify -R copy-pull + +cd test +echo bar > bar +hg commit -A -d '1 0' -m 2 +cd .. + +echo % pull cd copy-pull -hg verify +echo '[hooks]' >> .hg/hgrc +echo 'changegroup = echo changegroup: u=$HG_URL' >> .hg/hgrc +hg pull +cd .. diff --git a/tests/test-http.out b/tests/test-http.out --- a/tests/test-http.out +++ b/tests/test-http.out @@ -28,3 +28,13 @@ checking manifests crosschecking files in changesets and manifests checking files 1 files, 1 changesets, 1 total revisions +adding bar +% pull +changegroup: u=http://localhost:20059/ +pulling from http://localhost:20059/ +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) diff --git a/tests/test-mq-qrefresh-replace-log-message b/tests/test-mq-qrefresh-replace-log-message new file mode 100644 --- /dev/null +++ b/tests/test-mq-qrefresh-replace-log-message @@ -0,0 +1,51 @@ +#!/bin/sh + +# Environement setup for MQ +export HGRCPATH=./hgrc +echo "[extensions]" >> ./hgrc +echo "mq=" >> ./hgrc + +#Repo init +hg init +hg qinit + +hg qnew -m "First commit message" first-patch +echo aaaa > file +hg add file +hg qrefresh +echo ======================= +echo "Should display 'First commit message'" +hg log -l1 -v | sed -n '/description/,$p' +echo + +# Testing changing message with -m +echo bbbb > file +hg qrefresh -m "Second commit message" +echo ======================= +echo "Should display 'Second commit message'" +hg log -l1 -v | sed -n '/description/,$p' +echo + + +# Testing changing message with -l +echo "Third commit message" > logfile +echo " This is the 3rd log message" >> logfile +echo bbbb > file +hg qrefresh -l logfile +echo ======================= +echo "Should display 'Third commit message\n This is the 3rd log message'" +hg log -l1 -v | sed -n '/description/,$p' +echo + +# Testing changing message with -l- +hg qnew -m "First commit message" second-patch +echo aaaa > file2 +hg add file2 +echo bbbb > file2 +(echo "Fifth commit message" +echo " This is the 5th log message" >> logfile) |\ +hg qrefresh -l- +echo ======================= +echo "Should display 'Fifth commit message\n This is the 5th log message'" +hg log -l1 -v | sed -n '/description/,$p' +echo diff --git a/tests/test-mq-qrefresh-replace-log-message.out b/tests/test-mq-qrefresh-replace-log-message.out new file mode 100644 --- /dev/null +++ b/tests/test-mq-qrefresh-replace-log-message.out @@ -0,0 +1,29 @@ +======================= +Should display 'First commit message' +description: +First commit message + + + +======================= +Should display 'Second commit message' +description: +Second commit message + + + +======================= +Should display 'Third commit message\n This is the 3rd log message' +description: +Third commit message + This is the 3rd log message + + + +======================= +Should display 'Fifth commit message\n This is the 5th log message' +description: +Fifth commit message + + + diff --git a/tests/test-push-http b/tests/test-push-http --- a/tests/test-push-http +++ b/tests/test-push-http @@ -36,13 +36,19 @@ kill `cat hg.pid` echo % expect success echo 'allow_push = *' >> .hg/hgrc +echo '[hooks]' >> .hg/hgrc +echo 'changegroup = echo changegroup: u=$HG_URL >> $HGTMP/urls' >> .hg/hgrc hg serve -p 20059 -d --pid-file=hg.pid cat hg.pid >> $DAEMON_PIDS hg --cwd ../test2 push http://localhost:20059/ kill `cat hg.pid` hg rollback +sed 's/\(remote:http.*\):.*/\1/' $HGTMP/urls + echo % expect authorization error: all users denied +echo '[web]' > .hg/hgrc +echo 'push_ssl = false' >> .hg/hgrc echo 'deny_push = *' >> .hg/hgrc hg serve -p 20059 -d --pid-file=hg.pid cat hg.pid >> $DAEMON_PIDS diff --git a/tests/test-push-http.out b/tests/test-push-http.out --- a/tests/test-push-http.out +++ b/tests/test-push-http.out @@ -20,6 +20,7 @@ adding manifests adding file changes added 1 changesets with 1 changes to 1 files rolling back last transaction +changegroup: u=remote:http % expect authorization error: all users denied pushing to http://localhost:20059/ searching for changes diff --git a/tests/test-ssh b/tests/test-ssh --- a/tests/test-ssh +++ b/tests/test-ssh @@ -17,6 +17,8 @@ if [ ! -x dummyssh ] ; then exit -1 fi +SSH_CLIENT='127.0.0.1 1 2' +export SSH_CLIENT echo Got arguments 1:$1 2:$2 3:$3 4:$4 5:$5 >> dummylog $2 EOF @@ -29,6 +31,8 @@ echo this > foo hg ci -A -m "init" -d "1000000 0" foo echo '[server]' > .hg/hgrc echo 'uncompressed = True' >> .hg/hgrc +echo '[hooks]' >> .hg/hgrc +echo 'changegroup = echo changegroup in remote: u=$HG_URL >> ../dummylog' >> .hg/hgrc cd .. @@ -46,6 +50,9 @@ echo "# verify" cd local hg verify +echo '[hooks]' >> .hg/hgrc +echo 'changegroup = echo changegroup in local: u=$HG_URL >> ../dummylog' >> .hg/hgrc + echo "# empty default pull" hg paths hg pull -e ../dummyssh diff --git a/tests/test-ssh.out b/tests/test-ssh.out --- a/tests/test-ssh.out +++ b/tests/test-ssh.out @@ -83,5 +83,7 @@ Got arguments 1:user@dummy 2:hg -R remot Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5: Got arguments 1:user@dummy 2:hg -R local serve --stdio 3: 4: 5: Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5: +changegroup in remote: u=remote:ssh:127.0.0.1 Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5: Got arguments 1:user@dummy 2:hg -R remote serve --stdio 3: 4: 5: +changegroup in remote: u=remote:ssh:127.0.0.1 diff --git a/tests/test-static-http b/tests/test-static-http --- a/tests/test-static-http +++ b/tests/test-static-http @@ -37,6 +37,14 @@ http_proxy= hg clone static-http://local cd local hg verify cat bar + +cd ../remote +echo baz > quux +hg commit -A -mtest2 -d '100000000 0' + +cd ../local +echo '[hooks]' >> .hg/hgrc +echo 'changegroup = echo changegroup: u=$HG_URL' >> .hg/hgrc http_proxy= hg pull kill $! diff --git a/tests/test-static-http.out b/tests/test-static-http.out --- a/tests/test-static-http.out +++ b/tests/test-static-http.out @@ -19,6 +19,12 @@ crosschecking files in changesets and ma checking files 1 files, 1 changesets, 1 total revisions foo +adding quux +changegroup: u=static-http://localhost:20059/remote pulling from static-http://localhost:20059/remote searching for changes -no changes found +adding changesets +adding manifests +adding file changes +added 1 changesets with 1 changes to 1 files +(run 'hg update' to get a working copy)