--- a/.hgignore Sat Feb 12 16:08:41 2011 +0800
+++ b/.hgignore Wed Feb 16 14:13:22 2011 -0600
@@ -9,6 +9,8 @@
*.so
*.pyd
*.pyc
+*.pyo
+*$py.class
*.swp
*.prof
\#*\#
--- a/Makefile Sat Feb 12 16:08:41 2011 +0800
+++ b/Makefile Wed Feb 16 14:13:22 2011 -0600
@@ -45,7 +45,7 @@
clean:
-$(PYTHON) setup.py clean --all # ignore errors from this command
find . \( -name '*.py[cdo]' -o -name '*.so' \) -exec rm -f '{}' ';'
- rm -f MANIFEST mercurial/__version__.py tests/*.err
+ rm -f MANIFEST tests/*.err
rm -rf build mercurial/locale
$(MAKE) -C doc clean
--- a/contrib/bash_completion Sat Feb 12 16:08:41 2011 +0800
+++ b/contrib/bash_completion Wed Feb 16 14:13:22 2011 -0600
@@ -241,7 +241,7 @@
_hg_tags
_hg_branches
;;
- commit)
+ commit|record)
_hg_status "mar"
;;
remove)
--- a/contrib/check-code.py Sat Feb 12 16:08:41 2011 +0800
+++ b/contrib/check-code.py Wed Feb 16 14:13:22 2011 -0600
@@ -8,6 +8,7 @@
# GNU General Public License version 2 or any later version.
import re, glob, os, sys
+import keyword
import optparse
def repquote(m):
@@ -64,6 +65,7 @@
('^([^"\']|("[^"]*")|(\'[^\']*\'))*\\^', "^ must be quoted"),
(r'^source\b', "don't use 'source', use '.'"),
(r'touch -d', "don't use 'touch -d', use 'touch -t' instead"),
+ (r'ls\s+[^|-]+\s+-', "options to 'ls' must come before filenames"),
]
testfilters = [
@@ -117,8 +119,8 @@
(r'^\s*(if|while|def|class|except|try)\s[^[]*:\s*[^\]#\s]+',
"linebreak after :"),
(r'class\s[^(]:', "old-style class, use class foo(object)"),
- (r'^\s+del\(', "del isn't a function"),
- (r'^\s+except\(', "except isn't a function"),
+ (r'\b(%s)\(' % '|'.join(keyword.kwlist),
+ "Python keyword is not a function"),
(r',]', "unneeded trailing ',' in list"),
# (r'class\s[A-Z][^\(]*\((?!Exception)',
# "don't capitalize non-exception classes"),
@@ -127,11 +129,15 @@
(r'[\x80-\xff]', "non-ASCII character literal"),
(r'("\')\.format\(', "str.format() not available in Python 2.4"),
(r'^\s*with\s+', "with not available in Python 2.4"),
+ (r'^\s*except.* as .*:', "except as not available in Python 2.4"),
+ (r'^\s*os\.path\.relpath', "relpath not available in Python 2.4"),
(r'(?<!def)\s+(any|all|format)\(',
"any/all/format not available in Python 2.4"),
(r'(?<!def)\s+(callable)\(',
"callable not available in Python 3, use hasattr(f, '__call__')"),
(r'if\s.*\selse', "if ... else form not available in Python 2.4"),
+ (r'^\s*(%s)\s\s' % '|'.join(keyword.kwlist),
+ "gratuitous whitespace after Python keyword"),
(r'([\(\[]\s\S)|(\S\s[\)\]])', "gratuitous whitespace in () or []"),
# (r'\s\s=', "gratuitous whitespace before ="),
(r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=)\S',
@@ -145,6 +151,9 @@
(r'raise Exception', "don't raise generic exceptions"),
(r'ui\.(status|progress|write|note|warn)\([\'\"]x',
"warning: unwrapped ui message"),
+ (r' is\s+(not\s+)?["\'0-9-]', "object comparison with literal"),
+ (r' [=!]=\s+(True|False|None)',
+ "comparison with singleton, use 'is' or 'is not' instead"),
]
pyfilters = [
@@ -239,7 +248,9 @@
fc = 0
if not re.match(match, f):
continue
- pre = post = open(f).read()
+ fp = open(f)
+ pre = post = fp.read()
+ fp.close()
if "no-" + "check-code" in pre:
break
for p, r in filters:
--- a/contrib/hgk Sat Feb 12 16:08:41 2011 +0800
+++ b/contrib/hgk Wed Feb 16 14:13:22 2011 -0600
@@ -482,7 +482,7 @@
.bar.file add command -label "Quit" -command doquit
menu .bar.help
.bar add cascade -label "Help" -menu .bar.help
- .bar.help add command -label "About gitk" -command about
+ .bar.help add command -label "About hgk" -command about
. configure -menu .bar
if {![info exists geometry(canv1)]} {
@@ -867,9 +867,9 @@
return
}
toplevel $w
- wm title $w "About gitk"
+ wm title $w "About hgk"
message $w.m -text {
-Gitk version 1.2
+Hgk version 1.2
Copyright © 2005 Paul Mackerras
--- a/contrib/perf.py Sat Feb 12 16:08:41 2011 +0800
+++ b/contrib/perf.py Wed Feb 16 14:13:22 2011 -0600
@@ -80,11 +80,12 @@
timer(d)
def perfindex(ui, repo):
- import mercurial.changelog
+ import mercurial.revlog
+ mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
+ n = repo["tip"].node()
def d():
- t = repo.changelog.tip()
- repo.changelog = mercurial.changelog.changelog(repo.sopener)
- repo.changelog._loadindexmap()
+ repo.invalidate()
+ repo[n]
timer(d)
def perfstartup(ui, repo):
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/win32/buildlocal.bat Wed Feb 16 14:13:22 2011 -0600
@@ -0,0 +1,9 @@
+@echo off
+rem Double-click this file to (re)build Mercurial for Windows in place.
+rem Useful for testing and development.
+cd ..\..
+del /Q mercurial\*.pyd
+del /Q mercurial\*.pyc
+rmdir /Q /S mercurial\locale
+python setup.py build_py -c -d . build_ext -i build_mo
+pause
--- a/contrib/wix/dist.wxs Sat Feb 12 16:08:41 2011 +0800
+++ b/contrib/wix/dist.wxs Wed Feb 16 14:13:22 2011 -0600
@@ -16,23 +16,14 @@
<File Name="mercurial.parsers.pyd" />
<File Name="pyexpat.pyd" />
<File Name="python26.dll" />
- <File Name="pythoncom26.dll" />
- <File Name="pywintypes26.dll" />
<File Name="bz2.pyd" />
<File Name="select.pyd" />
<File Name="unicodedata.pyd" />
- <File Name="win32api.pyd" />
- <File Name="win32com.shell.shell.pyd" />
- <File Name="win32console.pyd" />
- <File Name="win32file.pyd" />
- <File Name="win32gui.pyd" />
- <File Name="win32pipe.pyd" />
- <File Name="win32process.pyd" />
+ <File Name="_ctypes.pyd" />
<File Name="_elementtree.pyd" />
<File Name="_hashlib.pyd" />
<File Name="_socket.pyd" />
<File Name="_ssl.pyd" />
- <File Name="_win32sysloader.pyd" />
</Component>
</DirectoryRef>
</Fragment>
--- a/contrib/wix/guids.wxi Sat Feb 12 16:08:41 2011 +0800
+++ b/contrib/wix/guids.wxi Wed Feb 16 14:13:22 2011 -0600
@@ -9,7 +9,7 @@
<?define contrib.vim.guid = {BB04903A-652D-4C4F-9590-2BD07A2304F2} ?>
<!-- dist.wxs -->
- <?define dist.guid = {0F63D160-0740-4BAF-BF25-0C6930310F51} ?>
+ <?define dist.guid = {C3B634A4-1B05-4A40-94A9-38EE853CF693} ?>
<!-- doc.wxs -->
<?define doc.hg.1.html.guid = {AAAA3FDA-EDC5-4220-B59D-D342722358A2} ?>
--- a/doc/Makefile Sat Feb 12 16:08:41 2011 +0800
+++ b/doc/Makefile Wed Feb 16 14:13:22 2011 -0600
@@ -1,11 +1,13 @@
SOURCES=$(wildcard *.[0-9].txt)
MAN=$(SOURCES:%.txt=%)
HTML=$(SOURCES:%.txt=%.html)
-GENDOC=gendoc.py ../mercurial/commands.py ../mercurial/help.py ../mercurial/help/*.txt
+GENDOC=gendoc.py ../mercurial/commands.py ../mercurial/help.py \
+ ../mercurial/help/*.txt ../hgext/*.py ../hgext/*/__init__.py
PREFIX=/usr/local
MANDIR=$(PREFIX)/share/man
INSTALL=install -c -m 644
PYTHON=python
+RSTARGS=
export LANGUAGE=C
export LC_ALL=C
@@ -24,11 +26,11 @@
mv $@.tmp $@
%: %.txt common.txt
- $(PYTHON) runrst hgmanpage --halt warning \
+ $(PYTHON) runrst hgmanpage $(RSTARGS) --halt warning \
--strip-elements-with-class htmlonly $*.txt $*
%.html: %.txt common.txt
- $(PYTHON) runrst html --halt warning \
+ $(PYTHON) runrst html $(RSTARGS) --halt warning \
--link-stylesheet --stylesheet-path style.css $*.txt $*.html
MANIFEST: man html
--- a/doc/gendoc.py Sat Feb 12 16:08:41 2011 +0800
+++ b/doc/gendoc.py Wed Feb 16 14:13:22 2011 -0600
@@ -40,7 +40,7 @@
if longopt:
allopts.append("--%s" % longopt)
desc += default and _(" (default: %s)") % default or ""
- yield(", ".join(allopts), desc)
+ yield (", ".join(allopts), desc)
def get_cmd(cmd, cmdtable):
d = {}
@@ -143,7 +143,7 @@
opt_output = list(d['opts'])
if opt_output:
opts_len = max([len(line[0]) for line in opt_output])
- ui.write(_("options:\n\n"))
+ ui.write(_("Options:\n\n"))
for optstr, desc in opt_output:
if desc:
s = "%-*s %s" % (opts_len, optstr, desc)
--- a/doc/hgrc.5.txt Sat Feb 12 16:08:41 2011 +0800
+++ b/doc/hgrc.5.txt Wed Feb 16 14:13:22 2011 -0600
@@ -330,8 +330,8 @@
``diff``
""""""""
-Settings used when displaying diffs. They are all Boolean and
-defaults to False.
+Settings used when displaying diffs. Everything except for ``unified`` is a
+Boolean and defaults to False.
``git``
Use git extended diff format.
@@ -345,6 +345,8 @@
Ignore changes in the amount of white space.
``ignoreblanklines``
Ignore changes whose lines are all blank.
+``unified``
+ Number of lines of context to show.
``email``
"""""""""
@@ -727,8 +729,8 @@
``port``
Optional. Port to connect to on mail server. Default: 25.
``tls``
- Optional. Whether to connect to mail server using TLS. True or
- False. Default: False.
+ Optional. Method to enable TLS when connecting to mail server: starttls,
+ smtps or none. Default: none.
``username``
Optional. User name for authenticating with the SMTP server.
Default: none.
@@ -876,6 +878,11 @@
be prompted to enter a username. If no username is entered, the
default ``USER@HOST`` is used instead.
Default is False.
+``commitsubrepos``
+ Whether to commit modified subrepositories when committing the
+ parent repository. If False and one subrepository has uncommitted
+ changes, abort the commit.
+ Default is True.
``debug``
Print debugging information. True or False. Default is False.
``editor``
--- a/hgext/bookmarks.py Sat Feb 12 16:08:41 2011 +0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,582 +0,0 @@
-# Mercurial extension to provide the 'hg bookmark' command
-#
-# Copyright 2008 David Soria Parra <dsp@php.net>
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2 or any later version.
-
-'''track a line of development with movable markers
-
-Bookmarks are local movable markers to changesets. Every bookmark
-points to a changeset identified by its hash. If you commit a
-changeset that is based on a changeset that has a bookmark on it, the
-bookmark shifts to the new changeset.
-
-It is possible to use bookmark names in every revision lookup (e.g.
-:hg:`merge`, :hg:`update`).
-
-By default, when several bookmarks point to the same changeset, they
-will all move forward together. It is possible to obtain a more
-git-like experience by adding the following configuration option to
-your configuration file::
-
- [bookmarks]
- track.current = True
-
-This will cause Mercurial to track the bookmark that you are currently
-using, and only update it. This is similar to git's approach to
-branching.
-'''
-
-from mercurial.i18n import _
-from mercurial.node import nullid, nullrev, bin, hex, short
-from mercurial import util, commands, repair, extensions, pushkey, hg, url
-from mercurial import revset
-import os
-
-def write(repo):
- '''Write bookmarks
-
- Write the given bookmark => hash dictionary to the .hg/bookmarks file
- in a format equal to those of localtags.
-
- We also store a backup of the previous state in undo.bookmarks that
- can be copied back on rollback.
- '''
- refs = repo._bookmarks
-
- try:
- bms = repo.opener('bookmarks').read()
- except IOError:
- bms = ''
- repo.opener('undo.bookmarks', 'w').write(bms)
-
- if repo._bookmarkcurrent not in refs:
- setcurrent(repo, None)
- wlock = repo.wlock()
- try:
- file = repo.opener('bookmarks', 'w', atomictemp=True)
- for refspec, node in refs.iteritems():
- file.write("%s %s\n" % (hex(node), refspec))
- file.rename()
-
- # touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
- try:
- os.utime(repo.sjoin('00changelog.i'), None)
- except OSError:
- pass
-
- finally:
- wlock.release()
-
-def setcurrent(repo, mark):
- '''Set the name of the bookmark that we are currently on
-
- Set the name of the bookmark that we are on (hg update <bookmark>).
- The name is recorded in .hg/bookmarks.current
- '''
- current = repo._bookmarkcurrent
- if current == mark:
- return
-
- refs = repo._bookmarks
-
- # do not update if we do update to a rev equal to the current bookmark
- if (mark and mark not in refs and
- current and refs[current] == repo.changectx('.').node()):
- return
- if mark not in refs:
- mark = ''
- wlock = repo.wlock()
- try:
- file = repo.opener('bookmarks.current', 'w', atomictemp=True)
- file.write(mark)
- file.rename()
- finally:
- wlock.release()
- repo._bookmarkcurrent = mark
-
-def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False, rename=None):
- '''track a line of development with movable markers
-
- Bookmarks are pointers to certain commits that move when
- committing. Bookmarks are local. They can be renamed, copied and
- deleted. It is possible to use bookmark names in :hg:`merge` and
- :hg:`update` to merge and update respectively to a given bookmark.
-
- You can use :hg:`bookmark NAME` to set a bookmark on the working
- directory's parent revision with the given name. If you specify
- a revision using -r REV (where REV may be an existing bookmark),
- the bookmark is assigned to that revision.
-
- Bookmarks can be pushed and pulled between repositories (see :hg:`help
- push` and :hg:`help pull`). This requires the bookmark extension to be
- enabled for both the local and remote repositories.
- '''
- hexfn = ui.debugflag and hex or short
- marks = repo._bookmarks
- cur = repo.changectx('.').node()
-
- if rename:
- if rename not in marks:
- raise util.Abort(_("a bookmark of this name does not exist"))
- if mark in marks and not force:
- raise util.Abort(_("a bookmark of the same name already exists"))
- if mark is None:
- raise util.Abort(_("new bookmark name required"))
- marks[mark] = marks[rename]
- del marks[rename]
- if repo._bookmarkcurrent == rename:
- setcurrent(repo, mark)
- write(repo)
- return
-
- if delete:
- if mark is None:
- raise util.Abort(_("bookmark name required"))
- if mark not in marks:
- raise util.Abort(_("a bookmark of this name does not exist"))
- if mark == repo._bookmarkcurrent:
- setcurrent(repo, None)
- del marks[mark]
- write(repo)
- return
-
- if mark != None:
- if "\n" in mark:
- raise util.Abort(_("bookmark name cannot contain newlines"))
- mark = mark.strip()
- if not mark:
- raise util.Abort(_("bookmark names cannot consist entirely of "
- "whitespace"))
- if mark in marks and not force:
- raise util.Abort(_("a bookmark of the same name already exists"))
- if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
- and not force):
- raise util.Abort(
- _("a bookmark cannot have the name of an existing branch"))
- if rev:
- marks[mark] = repo.lookup(rev)
- else:
- marks[mark] = repo.changectx('.').node()
- setcurrent(repo, mark)
- write(repo)
- return
-
- if mark is None:
- if rev:
- raise util.Abort(_("bookmark name required"))
- if len(marks) == 0:
- ui.status(_("no bookmarks set\n"))
- else:
- for bmark, n in marks.iteritems():
- if ui.configbool('bookmarks', 'track.current'):
- current = repo._bookmarkcurrent
- if bmark == current and n == cur:
- prefix, label = '*', 'bookmarks.current'
- else:
- prefix, label = ' ', ''
- else:
- if n == cur:
- prefix, label = '*', 'bookmarks.current'
- else:
- prefix, label = ' ', ''
-
- if ui.quiet:
- ui.write("%s\n" % bmark, label=label)
- else:
- ui.write(" %s %-25s %d:%s\n" % (
- prefix, bmark, repo.changelog.rev(n), hexfn(n)),
- label=label)
- return
-
-def _revstostrip(changelog, node):
- srev = changelog.rev(node)
- tostrip = [srev]
- saveheads = []
- for r in xrange(srev, len(changelog)):
- parents = changelog.parentrevs(r)
- if parents[0] in tostrip or parents[1] in tostrip:
- tostrip.append(r)
- if parents[1] != nullrev:
- for p in parents:
- if p not in tostrip and p > srev:
- saveheads.append(p)
- return [r for r in tostrip if r not in saveheads]
-
-def strip(oldstrip, ui, repo, node, backup="all"):
- """Strip bookmarks if revisions are stripped using
- the mercurial.strip method. This usually happens during
- qpush and qpop"""
- revisions = _revstostrip(repo.changelog, node)
- marks = repo._bookmarks
- update = []
- for mark, n in marks.iteritems():
- if repo.changelog.rev(n) in revisions:
- update.append(mark)
- oldstrip(ui, repo, node, backup)
- if len(update) > 0:
- for m in update:
- marks[m] = repo.changectx('.').node()
- write(repo)
-
-def reposetup(ui, repo):
- if not repo.local():
- return
-
- class bookmark_repo(repo.__class__):
-
- @util.propertycache
- def _bookmarks(self):
- '''Parse .hg/bookmarks file and return a dictionary
-
- Bookmarks are stored as {HASH}\\s{NAME}\\n (localtags format) values
- in the .hg/bookmarks file.
- Read the file and return a (name=>nodeid) dictionary
- '''
- try:
- bookmarks = {}
- for line in self.opener('bookmarks'):
- sha, refspec = line.strip().split(' ', 1)
- bookmarks[refspec] = self.changelog.lookup(sha)
- except:
- pass
- return bookmarks
-
- @util.propertycache
- def _bookmarkcurrent(self):
- '''Get the current bookmark
-
- If we use gittishsh branches we have a current bookmark that
- we are on. This function returns the name of the bookmark. It
- is stored in .hg/bookmarks.current
- '''
- mark = None
- if os.path.exists(self.join('bookmarks.current')):
- file = self.opener('bookmarks.current')
- # No readline() in posixfile_nt, reading everything is cheap
- mark = (file.readlines() or [''])[0]
- if mark == '':
- mark = None
- file.close()
- return mark
-
- def rollback(self, dryrun=False):
- if os.path.exists(self.join('undo.bookmarks')):
- if not dryrun:
- util.rename(self.join('undo.bookmarks'), self.join('bookmarks'))
- elif not os.path.exists(self.sjoin("undo")):
- # avoid "no rollback information available" message
- return 0
- return super(bookmark_repo, self).rollback(dryrun)
-
- def lookup(self, key):
- if key in self._bookmarks:
- key = self._bookmarks[key]
- return super(bookmark_repo, self).lookup(key)
-
- def _bookmarksupdate(self, parents, node):
- marks = self._bookmarks
- update = False
- if ui.configbool('bookmarks', 'track.current'):
- mark = self._bookmarkcurrent
- if mark and marks[mark] in parents:
- marks[mark] = node
- update = True
- else:
- for mark, n in marks.items():
- if n in parents:
- marks[mark] = node
- update = True
- if update:
- write(self)
-
- def commitctx(self, ctx, error=False):
- """Add a revision to the repository and
- move the bookmark"""
- wlock = self.wlock() # do both commit and bookmark with lock held
- try:
- node = super(bookmark_repo, self).commitctx(ctx, error)
- if node is None:
- return None
- parents = self.changelog.parents(node)
- if parents[1] == nullid:
- parents = (parents[0],)
-
- self._bookmarksupdate(parents, node)
- return node
- finally:
- wlock.release()
-
- def pull(self, remote, heads=None, force=False):
- result = super(bookmark_repo, self).pull(remote, heads, force)
-
- self.ui.debug("checking for updated bookmarks\n")
- rb = remote.listkeys('bookmarks')
- changed = False
- for k in rb.keys():
- if k in self._bookmarks:
- nr, nl = rb[k], self._bookmarks[k]
- if nr in self:
- cr = self[nr]
- cl = self[nl]
- if cl.rev() >= cr.rev():
- continue
- if cr in cl.descendants():
- self._bookmarks[k] = cr.node()
- changed = True
- self.ui.status(_("updating bookmark %s\n") % k)
- else:
- self.ui.warn(_("not updating divergent"
- " bookmark %s\n") % k)
- if changed:
- write(repo)
-
- return result
-
- def push(self, remote, force=False, revs=None, newbranch=False):
- result = super(bookmark_repo, self).push(remote, force, revs,
- newbranch)
-
- self.ui.debug("checking for updated bookmarks\n")
- rb = remote.listkeys('bookmarks')
- for k in rb.keys():
- if k in self._bookmarks:
- nr, nl = rb[k], self._bookmarks[k]
- if nr in self:
- cr = self[nr]
- cl = self[nl]
- if cl in cr.descendants():
- r = remote.pushkey('bookmarks', k, nr, nl)
- if r:
- self.ui.status(_("updating bookmark %s\n") % k)
- else:
- self.ui.warn(_('updating bookmark %s'
- ' failed!\n') % k)
-
- return result
-
- def addchangegroup(self, *args, **kwargs):
- parents = self.dirstate.parents()
-
- result = super(bookmark_repo, self).addchangegroup(*args, **kwargs)
- if result > 1:
- # We have more heads than before
- return result
- node = self.changelog.tip()
-
- self._bookmarksupdate(parents, node)
- return result
-
- def _findtags(self):
- """Merge bookmarks with normal tags"""
- (tags, tagtypes) = super(bookmark_repo, self)._findtags()
- tags.update(self._bookmarks)
- return (tags, tagtypes)
-
- if hasattr(repo, 'invalidate'):
- def invalidate(self):
- super(bookmark_repo, self).invalidate()
- for attr in ('_bookmarks', '_bookmarkcurrent'):
- if attr in self.__dict__:
- delattr(self, attr)
-
- repo.__class__ = bookmark_repo
-
-def listbookmarks(repo):
- # We may try to list bookmarks on a repo type that does not
- # support it (e.g., statichttprepository).
- if not hasattr(repo, '_bookmarks'):
- return {}
-
- d = {}
- for k, v in repo._bookmarks.iteritems():
- d[k] = hex(v)
- return d
-
-def pushbookmark(repo, key, old, new):
- w = repo.wlock()
- try:
- marks = repo._bookmarks
- if hex(marks.get(key, '')) != old:
- return False
- if new == '':
- del marks[key]
- else:
- if new not in repo:
- return False
- marks[key] = repo[new].node()
- write(repo)
- return True
- finally:
- w.release()
-
-def pull(oldpull, ui, repo, source="default", **opts):
- # translate bookmark args to rev args for actual pull
- if opts.get('bookmark'):
- # this is an unpleasant hack as pull will do this internally
- source, branches = hg.parseurl(ui.expandpath(source),
- opts.get('branch'))
- other = hg.repository(hg.remoteui(repo, opts), source)
- rb = other.listkeys('bookmarks')
-
- for b in opts['bookmark']:
- if b not in rb:
- raise util.Abort(_('remote bookmark %s not found!') % b)
- opts.setdefault('rev', []).append(b)
-
- result = oldpull(ui, repo, source, **opts)
-
- # update specified bookmarks
- if opts.get('bookmark'):
- for b in opts['bookmark']:
- # explicit pull overrides local bookmark if any
- ui.status(_("importing bookmark %s\n") % b)
- repo._bookmarks[b] = repo[rb[b]].node()
- write(repo)
-
- return result
-
-def push(oldpush, ui, repo, dest=None, **opts):
- dopush = True
- if opts.get('bookmark'):
- dopush = False
- for b in opts['bookmark']:
- if b in repo._bookmarks:
- dopush = True
- opts.setdefault('rev', []).append(b)
-
- result = 0
- if dopush:
- result = oldpush(ui, repo, dest, **opts)
-
- if opts.get('bookmark'):
- # this is an unpleasant hack as push will do this internally
- dest = ui.expandpath(dest or 'default-push', dest or 'default')
- dest, branches = hg.parseurl(dest, opts.get('branch'))
- other = hg.repository(hg.remoteui(repo, opts), dest)
- rb = other.listkeys('bookmarks')
- for b in opts['bookmark']:
- # explicit push overrides remote bookmark if any
- if b in repo._bookmarks:
- ui.status(_("exporting bookmark %s\n") % b)
- new = repo[b].hex()
- elif b in rb:
- ui.status(_("deleting remote bookmark %s\n") % b)
- new = '' # delete
- else:
- ui.warn(_('bookmark %s does not exist on the local '
- 'or remote repository!\n') % b)
- return 2
- old = rb.get(b, '')
- r = other.pushkey('bookmarks', b, old, new)
- if not r:
- ui.warn(_('updating bookmark %s failed!\n') % b)
- if not result:
- result = 2
-
- return result
-
-def diffbookmarks(ui, repo, remote):
- ui.status(_("searching for changed bookmarks\n"))
-
- lmarks = repo.listkeys('bookmarks')
- rmarks = remote.listkeys('bookmarks')
-
- diff = sorted(set(rmarks) - set(lmarks))
- for k in diff:
- ui.write(" %-25s %s\n" % (k, rmarks[k][:12]))
-
- if len(diff) <= 0:
- ui.status(_("no changed bookmarks found\n"))
- return 1
- return 0
-
-def incoming(oldincoming, ui, repo, source="default", **opts):
- if opts.get('bookmarks'):
- source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
- other = hg.repository(hg.remoteui(repo, opts), source)
- ui.status(_('comparing with %s\n') % url.hidepassword(source))
- return diffbookmarks(ui, repo, other)
- else:
- return oldincoming(ui, repo, source, **opts)
-
-def outgoing(oldoutgoing, ui, repo, dest=None, **opts):
- if opts.get('bookmarks'):
- dest = ui.expandpath(dest or 'default-push', dest or 'default')
- dest, branches = hg.parseurl(dest, opts.get('branch'))
- other = hg.repository(hg.remoteui(repo, opts), dest)
- ui.status(_('comparing with %s\n') % url.hidepassword(dest))
- return diffbookmarks(ui, other, repo)
- else:
- return oldoutgoing(ui, repo, dest, **opts)
-
-def uisetup(ui):
- extensions.wrapfunction(repair, "strip", strip)
- if ui.configbool('bookmarks', 'track.current'):
- extensions.wrapcommand(commands.table, 'update', updatecurbookmark)
-
- entry = extensions.wrapcommand(commands.table, 'pull', pull)
- entry[1].append(('B', 'bookmark', [],
- _("bookmark to import"),
- _('BOOKMARK')))
- entry = extensions.wrapcommand(commands.table, 'push', push)
- entry[1].append(('B', 'bookmark', [],
- _("bookmark to export"),
- _('BOOKMARK')))
- entry = extensions.wrapcommand(commands.table, 'incoming', incoming)
- entry[1].append(('B', 'bookmarks', False,
- _("compare bookmark")))
- entry = extensions.wrapcommand(commands.table, 'outgoing', outgoing)
- entry[1].append(('B', 'bookmarks', False,
- _("compare bookmark")))
-
- pushkey.register('bookmarks', pushbookmark, listbookmarks)
-
-def updatecurbookmark(orig, ui, repo, *args, **opts):
- '''Set the current bookmark
-
- If the user updates to a bookmark we update the .hg/bookmarks.current
- file.
- '''
- res = orig(ui, repo, *args, **opts)
- rev = opts['rev']
- if not rev and len(args) > 0:
- rev = args[0]
- setcurrent(repo, rev)
- return res
-
-def bmrevset(repo, subset, x):
- """``bookmark([name])``
- The named bookmark or all bookmarks.
- """
- # i18n: "bookmark" is a keyword
- args = revset.getargs(x, 0, 1, _('bookmark takes one or no arguments'))
- if args:
- bm = revset.getstring(args[0],
- # i18n: "bookmark" is a keyword
- _('the argument to bookmark must be a string'))
- bmrev = listbookmarks(repo).get(bm, None)
- if bmrev:
- bmrev = repo.changelog.rev(bin(bmrev))
- return [r for r in subset if r == bmrev]
- bms = set([repo.changelog.rev(bin(r)) for r in listbookmarks(repo).values()])
- return [r for r in subset if r in bms]
-
-def extsetup(ui):
- revset.symbols['bookmark'] = bmrevset
-
-cmdtable = {
- "bookmarks":
- (bookmark,
- [('f', 'force', False, _('force')),
- ('r', 'rev', '', _('revision'), _('REV')),
- ('d', 'delete', False, _('delete a given bookmark')),
- ('m', 'rename', '', _('rename a given bookmark'), _('NAME'))],
- _('hg bookmarks [-f] [-d] [-m NAME] [-r REV] [NAME]')),
-}
-
-colortable = {'bookmarks.current': 'green'}
-
-# tell hggettext to extract docstrings from these functions:
-i18nfunctions = [bmrevset]
--- a/hgext/color.py Sat Feb 12 16:08:41 2011 +0800
+++ b/hgext/color.py Wed Feb 16 14:13:22 2011 -0600
@@ -92,6 +92,7 @@
'cyan_background': 46, 'white_background': 47}
_styles = {'grep.match': 'red bold',
+ 'bookmarks.current': 'green',
'branches.active': 'none',
'branches.closed': 'black bold',
'branches.current': 'green',
--- a/hgext/convert/__init__.py Sat Feb 12 16:08:41 2011 +0800
+++ b/hgext/convert/__init__.py Wed Feb 16 14:13:22 2011 -0600
@@ -59,10 +59,10 @@
--sourcesort try to preserve source revisions order, only
supported by Mercurial sources.
- If <REVMAP> isn't given, it will be put in a default location
- (<dest>/.hg/shamap by default). The <REVMAP> is a simple text file
- that maps each source commit ID to the destination ID for that
- revision, like so::
+ If ``REVMAP`` isn't given, it will be put in a default location
+ (``<dest>/.hg/shamap`` by default). The ``REVMAP`` is a simple
+ text file that maps each source commit ID to the destination ID
+ for that revision, like so::
<source ID> <destination ID>
@@ -138,15 +138,19 @@
Mercurial Source
''''''''''''''''
- --config convert.hg.ignoreerrors=False (boolean)
- ignore integrity errors when reading. Use it to fix Mercurial
- repositories with missing revlogs, by converting from and to
- Mercurial.
- --config convert.hg.saverev=False (boolean)
- store original revision ID in changeset (forces target IDs to
- change)
- --config convert.hg.startrev=0 (hg revision identifier)
- convert start revision and its descendants
+ The Mercurial source recognizes the following configuration
+ options, which you can set on the command line with ``--config``:
+
+ :convert.hg.ignoreerrors: ignore integrity errors when reading.
+ Use it to fix Mercurial repositories with missing revlogs, by
+ converting from and to Mercurial. Default is False.
+
+ :convert.hg.saverev: store original. revision ID in changeset
+ (forces target IDs to change). It takes and boolean argument
+ and defaults to False.
+
+ :convert.hg.startrev: convert start revision and its descendants.
+ It takes a hg revision identifier and defaults to 0.
CVS Source
''''''''''
@@ -154,42 +158,46 @@
CVS source will use a sandbox (i.e. a checked-out copy) from CVS
to indicate the starting point of what will be converted. Direct
access to the repository files is not needed, unless of course the
- repository is :local:. The conversion uses the top level directory
- in the sandbox to find the CVS repository, and then uses CVS rlog
- commands to find files to convert. This means that unless a
- filemap is given, all files under the starting directory will be
+ repository is ``:local:``. The conversion uses the top level
+ directory in the sandbox to find the CVS repository, and then uses
+ CVS rlog commands to find files to convert. This means that unless
+ a filemap is given, all files under the starting directory will be
converted, and that any directory reorganization in the CVS
sandbox is ignored.
- The options shown are the defaults.
+ The following options can be used with ``--config``:
+
+ :convert.cvsps.cache: Set to False to disable remote log caching,
+ for testing and debugging purposes. Default is True.
+
+ :convert.cvsps.fuzz: Specify the maximum time (in seconds) that is
+ allowed between commits with identical user and log message in
+ a single changeset. When very large files were checked in as
+ part of a changeset then the default may not be long enough.
+ The default is 60.
- --config convert.cvsps.cache=True (boolean)
- Set to False to disable remote log caching, for testing and
- debugging purposes.
- --config convert.cvsps.fuzz=60 (integer)
- Specify the maximum time (in seconds) that is allowed between
- commits with identical user and log message in a single
- changeset. When very large files were checked in as part of a
- changeset then the default may not be long enough.
- --config convert.cvsps.mergeto='{{mergetobranch ([-\\w]+)}}'
- Specify a regular expression to which commit log messages are
- matched. If a match occurs, then the conversion process will
- insert a dummy revision merging the branch on which this log
- message occurs to the branch indicated in the regex.
- --config convert.cvsps.mergefrom='{{mergefrombranch ([-\\w]+)}}'
- Specify a regular expression to which commit log messages are
- matched. If a match occurs, then the conversion process will
- add the most recent revision on the branch indicated in the
- regex as the second parent of the changeset.
- --config hook.cvslog
- Specify a Python function to be called at the end of gathering
- the CVS log. The function is passed a list with the log entries,
- and can modify the entries in-place, or add or delete them.
- --config hook.cvschangesets
- Specify a Python function to be called after the changesets
- are calculated from the the CVS log. The function is passed
- a list with the changeset entries, and can modify the changesets
- in-place, or add or delete them.
+ :convert.cvsps.mergeto: Specify a regular expression to which
+ commit log messages are matched. If a match occurs, then the
+ conversion process will insert a dummy revision merging the
+ branch on which this log message occurs to the branch
+ indicated in the regex. Default is ``{{mergetobranch
+ ([-\\w]+)}}``
+
+ :convert.cvsps.mergefrom: Specify a regular expression to which
+ commit log messages are matched. If a match occurs, then the
+ conversion process will add the most recent revision on the
+ branch indicated in the regex as the second parent of the
+ changeset. Default is ``{{mergefrombranch ([-\\w]+)}}``
+
+ :hook.cvslog: Specify a Python function to be called at the end of
+ gathering the CVS log. The function is passed a list with the
+ log entries, and can modify the entries in-place, or add or
+ delete them.
+
+ :hook.cvschangesets: Specify a Python function to be called after
+ the changesets are calculated from the the CVS log. The
+ function is passed a list with the changeset entries, and can
+ modify the changesets in-place, or add or delete them.
An additional "debugcvsps" Mercurial command allows the builtin
changeset merging code to be run without doing a conversion. Its
@@ -200,29 +208,33 @@
'''''''''''''''''
Subversion source detects classical trunk/branches/tags layouts.
- By default, the supplied "svn://repo/path/" source URL is
- converted as a single branch. If "svn://repo/path/trunk" exists it
- replaces the default branch. If "svn://repo/path/branches" exists,
- its subdirectories are listed as possible branches. If
- "svn://repo/path/tags" exists, it is looked for tags referencing
- converted branches. Default "trunk", "branches" and "tags" values
- can be overridden with following options. Set them to paths
+ By default, the supplied ``svn://repo/path/`` source URL is
+ converted as a single branch. If ``svn://repo/path/trunk`` exists
+ it replaces the default branch. If ``svn://repo/path/branches``
+ exists, its subdirectories are listed as possible branches. If
+ ``svn://repo/path/tags`` exists, it is looked for tags referencing
+ converted branches. Default ``trunk``, ``branches`` and ``tags``
+ values can be overridden with following options. Set them to paths
relative to the source URL, or leave them blank to disable auto
detection.
- --config convert.svn.branches=branches (directory name)
- specify the directory containing branches
- --config convert.svn.tags=tags (directory name)
- specify the directory containing tags
- --config convert.svn.trunk=trunk (directory name)
- specify the name of the trunk branch
+ The following options can be set with ``--config``:
+
+ :convert.svn.branches: specify the directory containing branches.
+ The defaults is ``branches``.
+
+ :convert.svn.tags: specify the directory containing tags. The
+ default is ``tags``.
+
+ :convert.svn.trunk: specify the name of the trunk branch The
+ defauls is ``trunk``.
Source history can be retrieved starting at a specific revision,
instead of being integrally converted. Only single branch
conversions are supported.
- --config convert.svn.startrev=0 (svn revision number)
- specify start Subversion revision.
+ :convert.svn.startrev: specify start Subversion revision number.
+ The default is 0.
Perforce Source
'''''''''''''''
@@ -232,24 +244,27 @@
source to a flat Mercurial repository, ignoring labels, branches
and integrations. Note that when a depot path is given you then
usually should specify a target directory, because otherwise the
- target may be named ...-hg.
+ target may be named ``...-hg``.
It is possible to limit the amount of source history to be
- converted by specifying an initial Perforce revision.
+ converted by specifying an initial Perforce revision:
- --config convert.p4.startrev=0 (perforce changelist number)
- specify initial Perforce revision.
+ :convert.p4.startrev: specify initial Perforce revision, a
+ Perforce changelist number).
Mercurial Destination
'''''''''''''''''''''
- --config convert.hg.clonebranches=False (boolean)
- dispatch source branches in separate clones.
- --config convert.hg.tagsbranch=default (branch name)
- tag revisions branch name
- --config convert.hg.usebranchnames=True (boolean)
- preserve branch names
+ The following options are supported:
+
+ :convert.hg.clonebranches: dispatch source branches in separate
+ clones. The default is False.
+ :convert.hg.tagsbranch: branch name for tag revisions, defaults to
+ ``default``.
+
+ :convert.hg.usebranchnames: preserve branch names. The default is
+ True
"""
return convcmd.convert(ui, src, dest, revmapfile, **opts)
--- a/hgext/convert/subversion.py Sat Feb 12 16:08:41 2011 +0800
+++ b/hgext/convert/subversion.py Wed Feb 16 14:13:22 2011 -0600
@@ -914,7 +914,7 @@
arg = encodeargs(args)
hgexe = util.hgexecutable()
cmd = '%s debugsvnlog' % util.shellquote(hgexe)
- stdin, stdout = util.popen2(cmd)
+ stdin, stdout = util.popen2(util.quotecommand(cmd))
stdin.write(arg)
try:
stdin.close()
--- a/hgext/eol.py Sat Feb 12 16:08:41 2011 +0800
+++ b/hgext/eol.py Wed Feb 16 14:13:22 2011 -0600
@@ -67,6 +67,11 @@
Such files are normally not touched under the assumption that they
have mixed EOLs on purpose.
+The extension provides ``cleverencode:`` and ``cleverdecode:`` filters
+like the deprecated win32text extension does. This means that you can
+disable win32text and enable eol and your filters will still work. You
+only need to these filters until you have prepared a ``.hgeol`` file.
+
The ``win32text.forbid*`` hooks provided by the win32text extension
have been unified into a single hook named ``eol.hook``. The hook will
lookup the expected line endings from the ``.hgeol`` file, which means
@@ -115,6 +120,9 @@
'to-lf': tolf,
'to-crlf': tocrlf,
'is-binary': isbinary,
+ # The following provide backwards compatibility with win32text
+ 'cleverencode:': tolf,
+ 'cleverdecode:': tocrlf
}
--- a/hgext/gpg.py Sat Feb 12 16:08:41 2011 +0800
+++ b/hgext/gpg.py Wed Feb 16 14:13:22 2011 -0600
@@ -244,7 +244,9 @@
"(please commit .hgsigs manually "
"or use --force)"))
- repo.wfile(".hgsigs", "ab").write(sigmessage)
+ sigsfile = repo.wfile(".hgsigs", "ab")
+ sigsfile.write(sigmessage)
+ sigsfile.close()
if '.hgsigs' not in repo.dirstate:
repo[None].add([".hgsigs"])
--- a/hgext/hgk.py Sat Feb 12 16:08:41 2011 +0800
+++ b/hgext/hgk.py Wed Feb 16 14:13:22 2011 -0600
@@ -181,14 +181,14 @@
if i + x >= count:
l[chunk - x:] = [0] * (chunk - x)
break
- if full != None:
+ if full is not None:
l[x] = repo[i + x]
l[x].changeset() # force reading
else:
l[x] = 1
for x in xrange(chunk - 1, -1, -1):
if l[x] != 0:
- yield (i + x, full != None and l[x] or None)
+ yield (i + x, full is not None and l[x] or None)
if i == 0:
break
--- a/hgext/inotify/linux/__init__.py Sat Feb 12 16:08:41 2011 +0800
+++ b/hgext/inotify/linux/__init__.py Wed Feb 16 14:13:22 2011 -0600
@@ -26,7 +26,10 @@
def _read_procfs_value(name):
def read_value():
try:
- return int(open(procfs_path + '/' + name).read())
+ fp = open(procfs_path + '/' + name)
+ r = int(fp.read())
+ fp.close()
+ return r
except OSError:
return None
--- a/hgext/keyword.py Sat Feb 12 16:08:41 2011 +0800
+++ b/hgext/keyword.py Wed Feb 16 14:13:22 2011 -0600
@@ -70,9 +70,8 @@
replaced with customized keywords and templates. Again, run
:hg:`kwdemo` to control the results of your configuration changes.
-Before changing/disabling active keywords, run :hg:`kwshrink` to avoid
-the risk of inadvertently storing expanded keywords in the change
-history.
+Before changing/disabling active keywords, you must run :hg:`kwshrink`
+to avoid storing expanded keywords in the change history.
To force expansion after enabling it, or a configuration change, run
:hg:`kwexpand`.
@@ -101,6 +100,14 @@
# names of extensions using dorecord
recordextensions = 'record'
+colortable = {
+ 'kwfiles.enabled': 'green bold',
+ 'kwfiles.deleted': 'cyan bold underline',
+ 'kwfiles.enabledunknown': 'green',
+ 'kwfiles.ignored': 'bold',
+ 'kwfiles.ignoredunknown': 'none'
+}
+
# date like in cvs' $Date
utcdate = lambda x: util.datestr((x[0], 0), '%Y/%m/%d %H:%M:%S')
# date like in svn's $Date
@@ -111,7 +118,6 @@
# make keyword tools accessible
kwtools = {'templater': None, 'hgcmd': ''}
-
def _defaultkwmaps(ui):
'''Returns default keywordmaps according to keywordset configuration.'''
templates = {
@@ -170,14 +176,25 @@
for k, v in kwmaps)
else:
self.templates = _defaultkwmaps(self.ui)
- escaped = '|'.join(map(re.escape, self.templates.keys()))
- self.re_kw = re.compile(r'\$(%s)\$' % escaped)
- self.re_kwexp = re.compile(r'\$(%s): [^$\n\r]*? \$' % escaped)
-
templatefilters.filters.update({'utcdate': utcdate,
'svnisodate': svnisodate,
'svnutcdate': svnutcdate})
+ @util.propertycache
+ def escape(self):
+ '''Returns bar-separated and escaped keywords.'''
+ return '|'.join(map(re.escape, self.templates.keys()))
+
+ @util.propertycache
+ def rekw(self):
+ '''Returns regex for unexpanded keywords.'''
+ return re.compile(r'\$(%s)\$' % self.escape)
+
+ @util.propertycache
+ def rekwexp(self):
+ '''Returns regex for expanded keywords.'''
+ return re.compile(r'\$(%s): [^$\n\r]*? \$' % self.escape)
+
def substitute(self, data, path, ctx, subfunc):
'''Replaces keywords in data with expanded template.'''
def kwsub(mobj):
@@ -191,11 +208,15 @@
return '$%s: %s $' % (kw, ekw)
return subfunc(kwsub, data)
+ def linkctx(self, path, fileid):
+ '''Similar to filelog.linkrev, but returns a changectx.'''
+ return self.repo.filectx(path, fileid=fileid).changectx()
+
def expand(self, path, node, data):
'''Returns data with keywords expanded.'''
if not self.restrict and self.match(path) and not util.binary(data):
- ctx = self.repo.filectx(path, fileid=node).changectx()
- return self.substitute(data, path, ctx, self.re_kw.sub)
+ ctx = self.linkctx(path, node)
+ return self.substitute(data, path, ctx, self.rekw.sub)
return data
def iskwfile(self, cand, ctx):
@@ -212,8 +233,8 @@
kwcmd = self.restrict and lookup # kwexpand/kwshrink
if self.restrict or expand and lookup:
mf = ctx.manifest()
- fctx = ctx
- subn = (self.restrict or rekw) and self.re_kw.subn or self.re_kwexp.subn
+ lctx = ctx
+ re_kw = (self.restrict or rekw) and self.rekw or self.rekwexp
msg = (expand and _('overwriting %s expanding keywords\n')
or _('overwriting %s shrinking keywords\n'))
for f in candidates:
@@ -225,12 +246,12 @@
continue
if expand:
if lookup:
- fctx = self.repo.filectx(f, fileid=mf[f]).changectx()
- data, found = self.substitute(data, f, fctx, subn)
+ lctx = self.linkctx(f, mf[f])
+ data, found = self.substitute(data, f, lctx, re_kw.subn)
elif self.restrict:
- found = self.re_kw.search(data)
+ found = re_kw.search(data)
else:
- data, found = _shrinktext(data, subn)
+ data, found = _shrinktext(data, re_kw.subn)
if found:
self.ui.note(msg % f)
self.repo.wwrite(f, data, ctx.flags(f))
@@ -242,7 +263,7 @@
def shrink(self, fname, text):
'''Returns text with all keyword substitutions removed.'''
if self.match(fname) and not util.binary(text):
- return _shrinktext(text, self.re_kwexp.sub)
+ return _shrinktext(text, self.rekwexp.sub)
return text
def shrinklines(self, fname, lines):
@@ -250,7 +271,7 @@
if self.match(fname):
text = ''.join(lines)
if not util.binary(text):
- return _shrinktext(text, self.re_kwexp.sub).splitlines(True)
+ return _shrinktext(text, self.rekwexp.sub).splitlines(True)
return lines
def wread(self, fname, data):
@@ -334,6 +355,9 @@
ui.note(_('creating temporary repository at %s\n') % tmpdir)
repo = localrepo.localrepository(ui, tmpdir, True)
ui.setconfig('keyword', fn, '')
+ svn = ui.configbool('keywordset', 'svn')
+ # explicitly set keywordset for demo output
+ ui.setconfig('keywordset', 'svn', svn)
uikwmaps = ui.configitems('keywordmaps')
if args or opts.get('rcfile'):
@@ -341,7 +365,10 @@
if uikwmaps:
ui.status(_('\textending current template maps\n'))
if opts.get('default') or not uikwmaps:
- ui.status(_('\toverriding default template maps\n'))
+ if svn:
+ ui.status(_('\toverriding default svn keywordset\n'))
+ else:
+ ui.status(_('\toverriding default cvs keywordset\n'))
if opts.get('rcfile'):
ui.readconfig(opts.get('rcfile'))
if args:
@@ -353,7 +380,10 @@
ui.readconfig(repo.join('hgrc'))
kwmaps = dict(ui.configitems('keywordmaps'))
elif opts.get('default'):
- ui.status(_('\n\tconfiguration using default keyword template maps\n'))
+ if svn:
+ ui.status(_('\n\tconfiguration using default svn keywordset\n'))
+ else:
+ ui.status(_('\n\tconfiguration using default cvs keywordset\n'))
kwmaps = _defaultkwmaps(ui)
if uikwmaps:
ui.status(_('\tdisabling current template maps\n'))
@@ -367,6 +397,7 @@
reposetup(ui, repo)
ui.write('[extensions]\nkeyword =\n')
demoitems('keyword', ui.configitems('keyword'))
+ demoitems('keywordset', ui.configitems('keywordset'))
demoitems('keywordmaps', kwmaps.iteritems())
keywords = '$' + '$\n$'.join(sorted(kwmaps.keys())) + '$\n'
repo.wopener(fn, 'w').write(keywords)
@@ -424,24 +455,26 @@
files = sorted(modified + added + clean)
wctx = repo[None]
kwfiles = kwt.iskwfile(files, wctx)
+ kwdeleted = kwt.iskwfile(deleted, wctx)
kwunknown = kwt.iskwfile(unknown, wctx)
if not opts.get('ignore') or opts.get('all'):
- showfiles = kwfiles, kwunknown
+ showfiles = kwfiles, kwdeleted, kwunknown
else:
- showfiles = [], []
+ showfiles = [], [], []
if opts.get('all') or opts.get('ignore'):
showfiles += ([f for f in files if f not in kwfiles],
[f for f in unknown if f not in kwunknown])
- for char, filenames in zip('KkIi', showfiles):
+ kwlabels = 'enabled deleted enabledunknown ignored ignoredunknown'.split()
+ kwstates = zip('K!kIi', showfiles, kwlabels)
+ for char, filenames, kwstate in kwstates:
fmt = (opts.get('all') or ui.verbose) and '%s %%s\n' % char or '%s\n'
for f in filenames:
- ui.write(fmt % repo.pathto(f, cwd))
+ ui.write(fmt % repo.pathto(f, cwd), label='kwfiles.' + kwstate)
def shrink(ui, repo, *pats, **opts):
'''revert expanded keywords in the working directory
- Run before changing/disabling active keywords or if you experience
- problems with :hg:`import` or :hg:`merge`.
+ Must be run before changing/disabling active keywords.
kwshrink refuses to run if given files contain local changes.
'''
@@ -603,8 +636,6 @@
finally:
wlock.release()
- repo.__class__ = kwrepo
-
def kwfilectx_cmp(orig, self, fctx):
# keyword affects data size, comparing wdir and filelog size does
# not make sense
@@ -628,6 +659,8 @@
except KeyError:
pass
+ repo.__class__ = kwrepo
+
cmdtable = {
'kwdemo':
(demo,
--- a/hgext/mq.py Sat Feb 12 16:08:41 2011 +0800
+++ b/hgext/mq.py Wed Feb 16 14:13:22 2011 -0600
@@ -86,6 +86,8 @@
parent = None
format = None
subject = None
+ branch = None
+ nodeid = None
diffstart = 0
for line in file(pf):
@@ -106,6 +108,10 @@
date = line[7:]
elif line.startswith("# Parent "):
parent = line[9:]
+ elif line.startswith("# Branch "):
+ branch = line[9:]
+ elif line.startswith("# Node ID "):
+ nodeid = line[10:]
elif not line.startswith("# ") and line:
message.append(line)
format = None
@@ -134,6 +140,9 @@
eatdiff(message)
eatdiff(comments)
+ # Remember the exact starting line of the patch diffs before consuming
+ # empty lines, for external use by TortoiseHg and others
+ self.diffstartline = len(comments)
eatempty(message)
eatempty(comments)
@@ -147,6 +156,9 @@
self.user = user
self.date = date
self.parent = parent
+ # nodeid and branch are for external use by TortoiseHg and others
+ self.nodeid = nodeid
+ self.branch = branch
self.haspatch = diffstart > 1
self.plainmode = plainmode
@@ -239,6 +251,7 @@
try:
fh = open(os.path.join(path, 'patches.queue'))
cur = fh.read().rstrip()
+ fh.close()
if not cur:
curpath = os.path.join(path, 'patches')
else:
@@ -793,6 +806,19 @@
return top, patch
return None, None
+ def check_substate(self, repo):
+ '''return list of subrepos at a different revision than substate.
+ Abort if any subrepos have uncommitted changes.'''
+ inclsubs = []
+ wctx = repo[None]
+ for s in wctx.substate:
+ if wctx.sub(s).dirty(True):
+ raise util.Abort(
+ _("uncommitted changes in subrepository %s") % s)
+ elif wctx.sub(s).dirty():
+ inclsubs.append(s)
+ return inclsubs
+
def check_localchanges(self, repo, force=False, refresh=True):
m, a, r, d = repo.status()[:4]
if (m or a or r or d) and not force:
@@ -826,16 +852,23 @@
% patchfn)
else:
raise util.Abort(_('patch "%s" already exists') % patchfn)
+
+ inclsubs = self.check_substate(repo)
+ if inclsubs:
+ inclsubs.append('.hgsubstate')
if opts.get('include') or opts.get('exclude') or pats:
+ if inclsubs:
+ pats = list(pats or []) + inclsubs
match = cmdutil.match(repo, pats, opts)
# detect missing files in pats
def badfn(f, msg):
- raise util.Abort('%s: %s' % (f, msg))
+ if f != '.hgsubstate': # .hgsubstate is auto-created
+ raise util.Abort('%s: %s' % (f, msg))
match.bad = badfn
m, a, r, d = repo.status(match=match)[:4]
else:
m, a, r, d = self.check_localchanges(repo, force=True)
- match = cmdutil.matchfiles(repo, m + a + r)
+ match = cmdutil.matchfiles(repo, m + a + r + inclsubs)
if len(repo[None].parents()) > 1:
raise util.Abort(_('cannot manage merge changesets'))
commitfiles = m + a + r
@@ -1006,7 +1039,7 @@
raise util.Abort(_("patch %s not in series") % patch)
def push(self, repo, patch=None, force=False, list=False,
- mergeq=None, all=False, move=False):
+ mergeq=None, all=False, move=False, exact=False):
diffopts = self.diffopts()
wlock = repo.wlock()
try:
@@ -1015,7 +1048,7 @@
heads += ls
if not heads:
heads = [nullid]
- if repo.dirstate.parents()[0] not in heads:
+ if repo.dirstate.parents()[0] not in heads and not exact:
self.ui.status(_("(working directory not at a head)\n"))
if not self.series:
@@ -1064,9 +1097,21 @@
if not force:
self.check_localchanges(repo)
+ if exact:
+ if move:
+ raise util.Abort(_("cannot use --exact and --move together"))
+ if self.applied:
+ raise util.Abort(_("cannot push --exact with applied patches"))
+ root = self.series[start]
+ target = patchheader(self.join(root), self.plainmode).parent
+ if not target:
+ raise util.Abort(_("%s does not have a parent recorded" % root))
+ if not repo[target] == repo['.']:
+ hg.update(repo, target)
+
if move:
if not patch:
- raise util.Abort(_("please specify the patch to move"))
+ raise util.Abort(_("please specify the patch to move"))
for i, rpn in enumerate(self.full_series[start:]):
# strip markers for patch guards
if self.guard_re.split(rpn, 1)[0] == patch:
@@ -1104,7 +1149,7 @@
for f in all_files:
if f not in repo.dirstate:
try:
- util.unlink(repo.wjoin(f))
+ util.unlinkpath(repo.wjoin(f))
except OSError, inst:
if inst.errno != errno.ENOENT:
raise
@@ -1198,7 +1243,7 @@
raise util.Abort(_("deletions found between repo revs"))
for f in a:
try:
- util.unlink(repo.wjoin(f))
+ util.unlinkpath(repo.wjoin(f))
except OSError, e:
if e.errno != errno.ENOENT:
raise
@@ -1249,6 +1294,8 @@
if repo.changelog.heads(top) != [top]:
raise util.Abort(_("cannot refresh a revision with children"))
+ inclsubs = self.check_substate(repo)
+
cparents = repo.changelog.parents(top)
patchparent = self.qparents(repo, top)
ph = patchheader(self.join(patchfn), self.plainmode)
@@ -1272,10 +1319,10 @@
# and then commit.
#
# this should really read:
- # mm, dd, aa, aa2 = repo.status(tip, patchparent)[:4]
+ # mm, dd, aa = repo.status(top, patchparent)[:3]
# but we do it backwards to take advantage of manifest/chlog
# caching against the next repo.status call
- mm, aa, dd, aa2 = repo.status(patchparent, top)[:4]
+ mm, aa, dd = repo.status(patchparent, top)[:3]
changes = repo.changelog.read(top)
man = repo.manifest.read(changes[0])
aaa = aa[:]
@@ -1291,49 +1338,43 @@
else:
match = cmdutil.matchall(repo)
m, a, r, d = repo.status(match=match)[:4]
+ mm = set(mm)
+ aa = set(aa)
+ dd = set(dd)
# we might end up with files that were added between
# qtip and the dirstate parent, but then changed in the
# local dirstate. in this case, we want them to only
# show up in the added section
for x in m:
- if x == '.hgsub' or x == '.hgsubstate':
- self.ui.warn(_('warning: not refreshing %s\n') % x)
- continue
if x not in aa:
- mm.append(x)
+ mm.add(x)
# we might end up with files added by the local dirstate that
# were deleted by the patch. In this case, they should only
# show up in the changed section.
for x in a:
- if x == '.hgsub' or x == '.hgsubstate':
- self.ui.warn(_('warning: not adding %s\n') % x)
- continue
if x in dd:
- del dd[dd.index(x)]
- mm.append(x)
+ dd.remove(x)
+ mm.add(x)
else:
- aa.append(x)
+ aa.add(x)
# make sure any files deleted in the local dirstate
# are not in the add or change column of the patch
forget = []
for x in d + r:
- if x == '.hgsub' or x == '.hgsubstate':
- self.ui.warn(_('warning: not removing %s\n') % x)
- continue
if x in aa:
- del aa[aa.index(x)]
+ aa.remove(x)
forget.append(x)
continue
- elif x in mm:
- del mm[mm.index(x)]
- dd.append(x)
-
- m = list(set(mm))
- r = list(set(dd))
- a = list(set(aa))
+ else:
+ mm.discard(x)
+ dd.add(x)
+
+ m = list(mm)
+ r = list(dd)
+ a = list(aa)
c = [filter(matchfn, l) for l in (m, a, r)]
- match = cmdutil.matchfiles(repo, set(c[0] + c[1] + c[2]))
+ match = cmdutil.matchfiles(repo, set(c[0] + c[1] + c[2] + inclsubs))
chunks = patch.diff(repo, patchparent, match=match,
changes=c, opts=diffopts)
for chunk in chunks:
@@ -1531,7 +1572,7 @@
l = line.rstrip()
l = l[10:].split(' ')
qpp = [bin(x) for x in l]
- elif datastart != None:
+ elif datastart is not None:
l = line.rstrip()
n, name = l.split(':', 1)
if n:
@@ -1741,7 +1782,9 @@
_('need --name to import a patch from -'))
text = sys.stdin.read()
else:
- text = url.open(self.ui, filename).read()
+ fp = url.open(self.ui, filename)
+ text = fp.read()
+ fp.close()
except (OSError, IOError):
raise util.Abort(_("unable to read file %s") % filename)
if not patchname:
@@ -1750,6 +1793,7 @@
checkfile(patchname)
patchf = self.opener(patchname, "w")
patchf.write(text)
+ patchf.close()
if not force:
checkseries(patchname)
if patchname not in self.series:
@@ -1761,6 +1805,8 @@
self.added.append(patchname)
patchname = None
+ self.removeundo(repo)
+
def delete(ui, repo, *patches, **opts):
"""remove patches from queue
@@ -2346,7 +2392,8 @@
mergeq = queue(ui, repo.join(""), newpath)
ui.warn(_("merging with queue at: %s\n") % mergeq.path)
ret = q.push(repo, patch, force=opts.get('force'), list=opts.get('list'),
- mergeq=mergeq, all=opts.get('all'), move=opts.get('move'))
+ mergeq=mergeq, all=opts.get('all'), move=opts.get('move'),
+ exact=opts.get('exact'))
return ret
def pop(ui, repo, patch=None, **opts):
@@ -2746,6 +2793,7 @@
try:
fh = repo.opener(_allqueues, 'r')
queues = [queue.strip() for queue in fh if queue.strip()]
+ fh.close()
if current not in queues:
queues.append(current)
except IOError:
@@ -2880,7 +2928,7 @@
return super(mqrepo, self).commit(text, user, date, match, force,
editor, extra)
- def push(self, remote, force=False, revs=None, newbranch=False):
+ def checkpush(self, force, revs):
if self.mq.applied and not force:
haspatches = True
if revs:
@@ -2891,7 +2939,7 @@
haspatches = bool([n for n in revs if n in applied])
if haspatches:
raise util.Abort(_('source has mq patches applied'))
- return super(mqrepo, self).push(remote, force, revs, newbranch)
+ super(mqrepo, self).checkpush(force, revs)
def _findtags(self):
'''augment tags from base class with patch tags'''
@@ -2903,7 +2951,7 @@
mqtags = [(patch.node, patch.name) for patch in q.applied]
- if mqtags[-1][0] not in self.changelog.nodemap:
+ if mqtags[-1][0] not in self:
self.ui.warn(_('mq status file refers to unknown node %s\n')
% short(mqtags[-1][0]))
return result
@@ -2928,7 +2976,7 @@
cl = self.changelog
qbasenode = q.applied[0].node
- if qbasenode not in cl.nodemap:
+ if qbasenode not in self:
self.ui.warn(_('mq status file refers to unknown node %s\n')
% short(qbasenode))
return super(mqrepo, self)._branchtags(partial, lrev)
@@ -3122,6 +3170,7 @@
"^qpush":
(push,
[('f', 'force', None, _('apply on top of local changes')),
+ ('e', 'exact', None, _('apply the target patch to its recorded parent')),
('l', 'list', None, _('list patch name in commit text')),
('a', 'all', None, _('apply all patches')),
('m', 'merge', None, _('merge from another queue (DEPRECATED)')),
--- a/hgext/patchbomb.py Sat Feb 12 16:08:41 2011 +0800
+++ b/hgext/patchbomb.py Wed Feb 16 14:13:22 2011 -0600
@@ -193,6 +193,9 @@
PAGER environment variable is set, your pager will be fired up once
for each patchbomb message, so you can verify everything is alright.
+ In case email sending fails, you will find a backup of your series
+ introductory message in ``.hg/last-email.txt``.
+
Examples::
hg email -r 3000 # send patch 3000 only
@@ -258,7 +261,10 @@
tmpfn = os.path.join(tmpdir, 'bundle')
try:
commands.bundle(ui, repo, tmpfn, dest, **opts)
- return open(tmpfn, 'rb').read()
+ fp = open(tmpfn, 'rb')
+ data = fp.read()
+ fp.close()
+ return data
finally:
try:
os.unlink(tmpfn)
@@ -309,6 +315,10 @@
ui.write(_('\nWrite the introductory message for the '
'patch series.\n\n'))
body = ui.edit(body, sender)
+ # Save serie description in case sendmail fails
+ msgfile = repo.opener('last-email.txt', 'wb')
+ msgfile.write(body)
+ msgfile.close()
return body
def getpatchmsgs(patches, patchnames=None):
--- a/hgext/progress.py Sat Feb 12 16:08:41 2011 +0800
+++ b/hgext/progress.py Wed Feb 16 14:13:22 2011 -0600
@@ -28,7 +28,7 @@
[progress]
delay = 3 # number of seconds (float) before showing the progress bar
refresh = 0.1 # time in seconds between refreshes of the progress bar
- format = topic bar number # format of the progress bar
+ format = topic bar number estimate # format of the progress bar
width = <none> # if set, the maximum width of the progress information
# (that is, min(width, term width) will be used)
clear-complete = True # clear the progress bar after it's done
@@ -36,15 +36,17 @@
assume-tty = False # if true, ALWAYS show a progress bar, unless
# disable is given
-Valid entries for the format field are topic, bar, number, unit, and
-item. item defaults to the last 20 characters of the item, but this
-can be changed by adding either ``-<num>`` which would take the last
-num characters, or ``+<num>`` for the first num characters.
+Valid entries for the format field are topic, bar, number, unit,
+estimate, and item. item defaults to the last 20 characters of the
+item, but this can be changed by adding either ``-<num>`` which would
+take the last num characters, or ``+<num>`` for the first num
+characters.
"""
import sys
import time
+from mercurial.i18n import _
from mercurial import util
def spacejoin(*args):
@@ -54,6 +56,43 @@
return (getattr(sys.stderr, 'isatty', None) and
(sys.stderr.isatty() or ui.configbool('progress', 'assume-tty')))
+def fmtremaining(seconds):
+ if seconds < 60:
+ # i18n: format XX seconds as "XXs"
+ return _("%02ds") % (seconds)
+ minutes = seconds // 60
+ if minutes < 60:
+ seconds -= minutes * 60
+ # i18n: format X minutes and YY seconds as "XmYYs"
+ return _("%dm%02ds") % (minutes, seconds)
+ # we're going to ignore seconds in this case
+ minutes += 1
+ hours = minutes // 60
+ minutes -= hours * 60
+ if hours < 30:
+ # i18n: format X hours and YY minutes as "XhYYm"
+ return _("%dh%02dm") % (hours, minutes)
+ # we're going to ignore minutes in this case
+ hours += 1
+ days = hours // 24
+ hours -= days * 24
+ if days < 15:
+ # i18n: format X days and YY hours as "XdYYh"
+ return _("%dd%02dh") % (days, hours)
+ # we're going to ignore hours in this case
+ days += 1
+ weeks = days // 7
+ days -= weeks * 7
+ if weeks < 55:
+ # i18n: format X weeks and YY days as "XwYYd"
+ return _("%dw%02dd") % (weeks, days)
+ # we're going to ignore days and treat a year as 52 weeks
+ weeks += 1
+ years = weeks // 52
+ weeks -= years * 52
+ # i18n: format X years and YY weeks as "XyYYw"
+ return _("%dy%02dw") % (years, weeks)
+
class progbar(object):
def __init__(self, ui):
self.ui = ui
@@ -61,6 +100,9 @@
def resetstate(self):
self.topics = []
+ self.topicstates = {}
+ self.starttimes = {}
+ self.startvals = {}
self.printed = False
self.lastprint = time.time() + float(self.ui.config(
'progress', 'delay', default=3))
@@ -69,9 +111,9 @@
'progress', 'refresh', default=0.1))
self.order = self.ui.configlist(
'progress', 'format',
- default=['topic', 'bar', 'number'])
+ default=['topic', 'bar', 'number', 'estimate'])
- def show(self, topic, pos, item, unit, total):
+ def show(self, now, topic, pos, item, unit, total):
if not shouldprint(self.ui):
return
termwidth = self.width()
@@ -108,10 +150,12 @@
needprogress = True
elif indicator == 'unit' and unit:
add = unit
+ elif indicator == 'estimate':
+ add = self.estimate(topic, pos, total, now)
if not needprogress:
head = spacejoin(head, add)
else:
- tail = spacejoin(add, tail)
+ tail = spacejoin(tail, add)
if needprogress:
used = 0
if head:
@@ -159,19 +203,44 @@
tw = self.ui.termwidth()
return min(int(self.ui.config('progress', 'width', default=tw)), tw)
+ def estimate(self, topic, pos, total, now):
+ if total is None:
+ return ''
+ initialpos = self.startvals[topic]
+ target = total - initialpos
+ delta = pos - initialpos
+ if delta > 0:
+ elapsed = now - self.starttimes[topic]
+ if elapsed > float(
+ self.ui.config('progress', 'estimate', default=2)):
+ seconds = (elapsed * (target - delta)) // delta + 1
+ return fmtremaining(seconds)
+ return ''
+
def progress(self, topic, pos, item='', unit='', total=None):
+ now = time.time()
if pos is None:
- if self.topics and self.topics[-1] == topic and self.printed:
+ self.starttimes.pop(topic, None)
+ self.startvals.pop(topic, None)
+ self.topicstates.pop(topic, None)
+ # reset the progress bar if this is the outermost topic
+ if self.topics and self.topics[0] == topic and self.printed:
self.complete()
self.resetstate()
+ # truncate the list of topics assuming all topics within
+ # this one are also closed
+ if topic in self.topics:
+ self.topics = self.topics[:self.topics.index(topic)]
else:
if topic not in self.topics:
+ self.starttimes[topic] = now
+ self.startvals[topic] = pos
self.topics.append(topic)
- now = time.time()
- if (now - self.lastprint >= self.refresh
- and topic == self.topics[-1]):
+ self.topicstates[topic] = pos, item, unit, total
+ if now - self.lastprint >= self.refresh and self.topics:
self.lastprint = now
- self.show(topic, pos, item, unit, total)
+ current = self.topics[-1]
+ self.show(now, topic, *self.topicstates[topic])
def uisetup(ui):
class progressui(ui.__class__):
--- a/hgext/rebase.py Sat Feb 12 16:08:41 2011 +0800
+++ b/hgext/rebase.py Wed Feb 16 14:13:22 2011 -0600
@@ -215,7 +215,7 @@
clearstatus(repo)
ui.note(_("rebase completed\n"))
if os.path.exists(repo.sjoin('undo')):
- util.unlink(repo.sjoin('undo'))
+ util.unlinkpath(repo.sjoin('undo'))
if skipped:
ui.note(_("%d revisions have been skipped\n") % len(skipped))
finally:
@@ -393,7 +393,7 @@
def clearstatus(repo):
'Remove the status files'
if os.path.exists(repo.join("rebasestate")):
- util.unlink(repo.join("rebasestate"))
+ util.unlinkpath(repo.join("rebasestate"))
def restorestatus(repo):
'Restore a previously stored status'
--- a/hgext/record.py Sat Feb 12 16:08:41 2011 +0800
+++ b/hgext/record.py Wed Feb 16 14:13:22 2011 -0600
@@ -10,7 +10,7 @@
from mercurial.i18n import gettext, _
from mercurial import cmdutil, commands, extensions, hg, mdiff, patch
from mercurial import util
-import copy, cStringIO, errno, os, re, tempfile
+import copy, cStringIO, errno, os, re, shutil, tempfile
lines_re = re.compile(r'@@ -(\d+),(\d+) \+(\d+),(\d+) @@\s*(.*)')
@@ -42,7 +42,7 @@
line = lr.readline()
if not line:
break
- if line.startswith('diff --git a/'):
+ if line.startswith('diff --git a/') or line.startswith('diff -r '):
def notheader(line):
s = line.split(None, 1)
return not s or s[0] not in ('---', 'diff')
@@ -70,7 +70,8 @@
XXX shoudn't we move this to mercurial/patch.py ?
"""
- diff_re = re.compile('diff --git a/(.*) b/(.*)$')
+ diffgit_re = re.compile('diff --git a/(.*) b/(.*)$')
+ diff_re = re.compile('diff -r .* (.*)$')
allhunks_re = re.compile('(?:index|new file|deleted file) ')
pretty_re = re.compile('(?:new file|deleted file) ')
special_re = re.compile('(?:index|new|deleted|copy|rename) ')
@@ -80,9 +81,7 @@
self.hunks = []
def binary(self):
- for h in self.header:
- if h.startswith('index '):
- return True
+ return util.any(h.startswith('index ') for h in self.header)
def pretty(self, fp):
for h in self.header:
@@ -105,15 +104,17 @@
fp.write(''.join(self.header))
def allhunks(self):
- for h in self.header:
- if self.allhunks_re.match(h):
- return True
+ return util.any(self.allhunks_re.match(h) for h in self.header)
def files(self):
- fromfile, tofile = self.diff_re.match(self.header[0]).groups()
- if fromfile == tofile:
- return [fromfile]
- return [fromfile, tofile]
+ match = self.diffgit_re.match(self.header[0])
+ if match:
+ fromfile, tofile = match.groups()
+ if fromfile == tofile:
+ return [fromfile]
+ return [fromfile, tofile]
+ else:
+ return self.diff_re.match(self.header[0]).groups()
def filename(self):
return self.files()[-1]
@@ -122,9 +123,7 @@
return '<header %s>' % (' '.join(map(repr, self.files())))
def special(self):
- for h in self.header:
- if self.special_re.match(h):
- return True
+ return util.any(self.special_re.match(h) for h in self.header)
def countchanges(hunk):
"""hunk -> (n+,n-)"""
@@ -173,7 +172,7 @@
return '<hunk %r@%d>' % (self.filename(), self.fromline)
def parsepatch(fp):
- """patch -> [] of hunks """
+ """patch -> [] of headers -> [] of hunks """
class parser(object):
"""patch parsing state machine"""
def __init__(self):
@@ -184,7 +183,7 @@
self.context = []
self.before = []
self.hunk = []
- self.stream = []
+ self.headers = []
def addrange(self, limits):
fromstart, fromend, tostart, toend, proc = limits
@@ -197,7 +196,6 @@
h = hunk(self.header, self.fromline, self.toline, self.proc,
self.before, self.hunk, context)
self.header.hunks.append(h)
- self.stream.append(h)
self.fromline += len(self.before) + h.removed
self.toline += len(self.before) + h.added
self.before = []
@@ -214,12 +212,12 @@
def newfile(self, hdr):
self.addcontext([])
h = header(hdr)
- self.stream.append(h)
+ self.headers.append(h)
self.header = h
def finished(self):
self.addcontext([])
- return self.stream
+ return self.headers
transitions = {
'file': {'context': addcontext,
@@ -248,27 +246,10 @@
state = newstate
return p.finished()
-def filterpatch(ui, chunks):
+def filterpatch(ui, headers):
"""Interactively filter patch chunks into applied-only chunks"""
- chunks = list(chunks)
- chunks.reverse()
- seen = set()
- def consumefile():
- """fetch next portion from chunks until a 'header' is seen
- NB: header == new-file mark
- """
- consumed = []
- while chunks:
- if isinstance(chunks[-1], header):
- break
- else:
- consumed.append(chunks.pop())
- return consumed
- resp_all = [None] # this two are changed from inside prompt,
- resp_file = [None] # so can't be usual variables
- applied = {} # 'filename' -> [] of chunks
- def prompt(query):
+ def prompt(skipfile, skipall, query):
"""prompt query, and process base inputs
- y/n for the rest of file
@@ -276,13 +257,12 @@
- ? (help)
- q (quit)
- Returns True/False and sets reps_all and resp_file as
- appropriate.
+ Return True/False and possibly updated skipfile and skipall.
"""
- if resp_all[0] is not None:
- return resp_all[0]
- if resp_file[0] is not None:
- return resp_file[0]
+ if skipall is not None:
+ return skipall, skipfile, skipall
+ if skipfile is not None:
+ return skipfile, skipfile, skipall
while True:
resps = _('[Ynsfdaq?]')
choices = (_('&Yes, record this change'),
@@ -307,47 +287,48 @@
elif r == 1: # no
ret = False
elif r == 2: # Skip
- ret = resp_file[0] = False
+ ret = skipfile = False
elif r == 3: # file (Record remaining)
- ret = resp_file[0] = True
+ ret = skipfile = True
elif r == 4: # done, skip remaining
- ret = resp_all[0] = False
+ ret = skipall = False
elif r == 5: # all
- ret = resp_all[0] = True
+ ret = skipall = True
elif r == 6: # quit
raise util.Abort(_('user quit'))
- return ret
- pos, total = 0, len(chunks) - 1
- while chunks:
- pos = total - len(chunks) + 1
- chunk = chunks.pop()
- if isinstance(chunk, header):
- # new-file mark
- resp_file = [None]
- fixoffset = 0
- hdr = ''.join(chunk.header)
- if hdr in seen:
- consumefile()
- continue
- seen.add(hdr)
- if resp_all[0] is None:
+ return ret, skipfile, skipall
+
+ seen = set()
+ applied = {} # 'filename' -> [] of chunks
+ skipfile, skipall = None, None
+ pos, total = 1, sum(len(h.hunks) for h in headers)
+ for h in headers:
+ pos += len(h.hunks)
+ skipfile = None
+ fixoffset = 0
+ hdr = ''.join(h.header)
+ if hdr in seen:
+ continue
+ seen.add(hdr)
+ if skipall is None:
+ h.pretty(ui)
+ msg = (_('examine changes to %s?') %
+ _(' and ').join(map(repr, h.files())))
+ r, skipfile, skipall = prompt(skipfile, skipall, msg)
+ if not r:
+ continue
+ applied[h.filename()] = [h]
+ if h.allhunks():
+ applied[h.filename()] += h.hunks
+ continue
+ for i, chunk in enumerate(h.hunks):
+ if skipfile is None and skipall is None:
chunk.pretty(ui)
- r = prompt(_('examine changes to %s?') %
- _(' and ').join(map(repr, chunk.files())))
- if r:
- applied[chunk.filename()] = [chunk]
- if chunk.allhunks():
- applied[chunk.filename()] += consumefile()
- else:
- consumefile()
- else:
- # new hunk
- if resp_file[0] is None and resp_all[0] is None:
- chunk.pretty(ui)
- r = total == 1 and prompt(_('record this change to %r?') %
- chunk.filename()) \
- or prompt(_('record change %d/%d to %r?') %
- (pos, total, chunk.filename()))
+ msg = (total == 1
+ and (_('record this change to %r?') % chunk.filename())
+ or (_('record change %d/%d to %r?') %
+ (pos - len(h.hunks) + i, total, chunk.filename())))
+ r, skipfile, skipall = prompt(skipfile, skipall, msg)
if r:
if fixoffset:
chunk = copy.copy(chunk)
@@ -403,8 +384,6 @@
def committomq(ui, repo, *pats, **opts):
mq.new(ui, repo, patch, *pats, **opts)
- opts = opts.copy()
- opts['force'] = True # always 'qnew -f'
dorecord(ui, repo, committomq, *pats, **opts)
@@ -415,21 +394,22 @@
def recordfunc(ui, repo, message, match, opts):
"""This is generic record driver.
- Its job is to interactively filter local changes, and accordingly
- prepare working dir into a state, where the job can be delegated to
- non-interactive commit command such as 'commit' or 'qrefresh'.
+ Its job is to interactively filter local changes, and
+ accordingly prepare working directory into a state in which the
+ job can be delegated to a non-interactive commit command such as
+ 'commit' or 'qrefresh'.
- After the actual job is done by non-interactive command, working dir
- state is restored to original.
+ After the actual job is done by non-interactive command, the
+ working directory is restored to its original state.
- In the end we'll record interesting changes, and everything else will be
- left in place, so the user can continue his work.
+ In the end we'll record interesting changes, and everything else
+ will be left in place, so the user can continue working.
"""
merge = len(repo[None].parents()) > 1
if merge:
raise util.Abort(_('cannot partially commit a merge '
- '(use hg commit instead)'))
+ '(use "hg commit" instead)'))
changes = repo.status(match=match)[:3]
diffopts = mdiff.diffopts(git=True, nodates=True)
@@ -475,6 +455,7 @@
os.close(fd)
ui.debug('backup %r as %r\n' % (f, tmpname))
util.copyfile(repo.wjoin(f), tmpname)
+ shutil.copystat(repo.wjoin(f), tmpname)
backups[f] = tmpname
fp = cStringIO.StringIO()
@@ -502,11 +483,13 @@
raise util.Abort(str(err))
del fp
- # 4. We prepared working directory according to filtered patch.
- # Now is the time to delegate the job to commit/qrefresh or the like!
+ # 4. We prepared working directory according to filtered
+ # patch. Now is the time to delegate the job to
+ # commit/qrefresh or the like!
- # it is important to first chdir to repo root -- we'll call a
- # highlevel command with list of pathnames relative to repo root
+ # it is important to first chdir to repo root -- we'll call
+ # a highlevel command with list of pathnames relative to
+ # repo root
cwd = os.getcwd()
os.chdir(repo.root)
try:
@@ -521,6 +504,14 @@
for realname, tmpname in backups.iteritems():
ui.debug('restoring %r to %r\n' % (tmpname, realname))
util.copyfile(tmpname, repo.wjoin(realname))
+ # Our calls to copystat() here and above are a
+ # hack to trick any editors that have f open that
+ # we haven't modified them.
+ #
+ # Also note that this racy as an editor could
+ # notice the file's mtime before we've finished
+ # writing it.
+ shutil.copystat(tmpname, repo.wjoin(realname))
os.unlink(tmpname)
os.rmdir(backupdir)
except OSError:
@@ -540,11 +531,7 @@
cmdtable = {
"record":
- (record,
-
- # add commit options
- commands.table['^commit|ci'][1],
-
+ (record, commands.table['^commit|ci'][1], # same options as commit
_('hg record [OPTION]... [FILE]...')),
}
@@ -557,11 +544,7 @@
qcmdtable = {
"qrecord":
- (qrecord,
-
- # add qnew options, except '--force'
- [opt for opt in mq.cmdtable['^qnew'][1] if opt[1] != 'force'],
-
+ (qrecord, mq.cmdtable['^qnew'][1], # same options as qnew
_('hg qrecord [OPTION]... PATCH [FILE]...')),
}
--- a/hgext/transplant.py Sat Feb 12 16:08:41 2011 +0800
+++ b/hgext/transplant.py Wed Feb 16 14:13:22 2011 -0600
@@ -401,7 +401,7 @@
def hasnode(repo, node):
try:
- return repo.changelog.rev(node) != None
+ return repo.changelog.rev(node) is not None
except error.RevlogError:
return False
--- a/i18n/da.po Sat Feb 12 16:08:41 2011 +0800
+++ b/i18n/da.po Wed Feb 16 14:13:22 2011 -0600
@@ -17,8 +17,8 @@
msgstr ""
"Project-Id-Version: Mercurial\n"
"Report-Msgid-Bugs-To: <mercurial-devel@selenic.com>\n"
-"POT-Creation-Date: 2010-12-10 12:44+0100\n"
-"PO-Revision-Date: 2010-12-10 12:46+0100\n"
+"POT-Creation-Date: 2011-01-04 12:03+0100\n"
+"PO-Revision-Date: 2011-01-04 12:15+0100\n"
"Last-Translator: <mg@lazybytes.net>\n"
"Language-Team: Danish\n"
"Language: Danish\n"
@@ -1142,10 +1142,10 @@
msgstr ""
msgid ""
-" If <REVMAP> isn't given, it will be put in a default location\n"
-" (<dest>/.hg/shamap by default). The <REVMAP> is a simple text file\n"
-" that maps each source commit ID to the destination ID for that\n"
-" revision, like so::"
+" If ``REVMAP`` isn't given, it will be put in a default location\n"
+" (``<dest>/.hg/shamap`` by default). The ``REVMAP`` is a simple\n"
+" text file that maps each source commit ID to the destination ID\n"
+" for that revision, like so::"
msgstr ""
msgid " <source ID> <destination ID>"
@@ -1251,15 +1251,25 @@
msgstr ""
msgid ""
-" --config convert.hg.ignoreerrors=False (boolean)\n"
-" ignore integrity errors when reading. Use it to fix Mercurial\n"
-" repositories with missing revlogs, by converting from and to\n"
-" Mercurial.\n"
-" --config convert.hg.saverev=False (boolean)\n"
-" store original revision ID in changeset (forces target IDs to\n"
-" change)\n"
-" --config convert.hg.startrev=0 (hg revision identifier)\n"
-" convert start revision and its descendants"
+" The Mercurial source recognizes the following configuration\n"
+" options, which you can set on the command line with ``--config``:"
+msgstr ""
+
+msgid ""
+" :convert.hg.ignoreerrors: ignore integrity errors when reading.\n"
+" Use it to fix Mercurial repositories with missing revlogs, by\n"
+" converting from and to Mercurial. Default is False."
+msgstr ""
+
+msgid ""
+" :convert.hg.saverev: store original. revision ID in changeset\n"
+" (forces target IDs to change). It takes and boolean argument\n"
+" and defaults to False."
+msgstr ""
+
+msgid ""
+" :convert.hg.startrev: convert start revision and its descendants.\n"
+" It takes a hg revision identifier and defaults to 0."
msgstr ""
msgid ""
@@ -1271,45 +1281,59 @@
" CVS source will use a sandbox (i.e. a checked-out copy) from CVS\n"
" to indicate the starting point of what will be converted. Direct\n"
" access to the repository files is not needed, unless of course the\n"
-" repository is :local:. The conversion uses the top level directory\n"
-" in the sandbox to find the CVS repository, and then uses CVS rlog\n"
-" commands to find files to convert. This means that unless a\n"
-" filemap is given, all files under the starting directory will be\n"
+" repository is ``:local:``. The conversion uses the top level\n"
+" directory in the sandbox to find the CVS repository, and then uses\n"
+" CVS rlog commands to find files to convert. This means that unless\n"
+" a filemap is given, all files under the starting directory will be\n"
" converted, and that any directory reorganization in the CVS\n"
" sandbox is ignored."
msgstr ""
-msgid " The options shown are the defaults."
-msgstr ""
-
-msgid ""
-" --config convert.cvsps.cache=True (boolean)\n"
-" Set to False to disable remote log caching, for testing and\n"
-" debugging purposes.\n"
-" --config convert.cvsps.fuzz=60 (integer)\n"
-" Specify the maximum time (in seconds) that is allowed between\n"
-" commits with identical user and log message in a single\n"
-" changeset. When very large files were checked in as part of a\n"
-" changeset then the default may not be long enough.\n"
-" --config convert.cvsps.mergeto='{{mergetobranch ([-\\w]+)}}'\n"
-" Specify a regular expression to which commit log messages are\n"
-" matched. If a match occurs, then the conversion process will\n"
-" insert a dummy revision merging the branch on which this log\n"
-" message occurs to the branch indicated in the regex.\n"
-" --config convert.cvsps.mergefrom='{{mergefrombranch ([-\\w]+)}}'\n"
-" Specify a regular expression to which commit log messages are\n"
-" matched. If a match occurs, then the conversion process will\n"
-" add the most recent revision on the branch indicated in the\n"
-" regex as the second parent of the changeset.\n"
-" --config hook.cvslog\n"
-" Specify a Python function to be called at the end of gathering\n"
-" the CVS log. The function is passed a list with the log entries,\n"
-" and can modify the entries in-place, or add or delete them.\n"
-" --config hook.cvschangesets\n"
-" Specify a Python function to be called after the changesets\n"
-" are calculated from the the CVS log. The function is passed\n"
-" a list with the changeset entries, and can modify the changesets\n"
-" in-place, or add or delete them."
+msgid " The following options can be used with ``--config``:"
+msgstr ""
+
+msgid ""
+" :convert.cvsps.cache: Set to False to disable remote log caching,\n"
+" for testing and debugging purposes. Default is True."
+msgstr ""
+
+msgid ""
+" :convert.cvsps.fuzz: Specify the maximum time (in seconds) that is\n"
+" allowed between commits with identical user and log message in\n"
+" a single changeset. When very large files were checked in as\n"
+" part of a changeset then the default may not be long enough.\n"
+" The default is 60."
+msgstr ""
+
+msgid ""
+" :convert.cvsps.mergeto: Specify a regular expression to which\n"
+" commit log messages are matched. If a match occurs, then the\n"
+" conversion process will insert a dummy revision merging the\n"
+" branch on which this log message occurs to the branch\n"
+" indicated in the regex. Default is ``{{mergetobranch\n"
+" ([-\\w]+)}}``"
+msgstr ""
+
+msgid ""
+" :convert.cvsps.mergefrom: Specify a regular expression to which\n"
+" commit log messages are matched. If a match occurs, then the\n"
+" conversion process will add the most recent revision on the\n"
+" branch indicated in the regex as the second parent of the\n"
+" changeset. Default is ``{{mergefrombranch ([-\\w]+)}}``"
+msgstr ""
+
+msgid ""
+" :hook.cvslog: Specify a Python function to be called at the end of\n"
+" gathering the CVS log. The function is passed a list with the\n"
+" log entries, and can modify the entries in-place, or add or\n"
+" delete them."
+msgstr ""
+
+msgid ""
+" :hook.cvschangesets: Specify a Python function to be called after\n"
+" the changesets are calculated from the the CVS log. The\n"
+" function is passed a list with the changeset entries, and can\n"
+" modify the changesets in-place, or add or delete them."
msgstr ""
msgid ""
@@ -1326,24 +1350,33 @@
msgid ""
" Subversion source detects classical trunk/branches/tags layouts.\n"
-" By default, the supplied \"svn://repo/path/\" source URL is\n"
-" converted as a single branch. If \"svn://repo/path/trunk\" exists it\n"
-" replaces the default branch. If \"svn://repo/path/branches\" exists,\n"
-" its subdirectories are listed as possible branches. If\n"
-" \"svn://repo/path/tags\" exists, it is looked for tags referencing\n"
-" converted branches. Default \"trunk\", \"branches\" and \"tags\" values\n"
-" can be overridden with following options. Set them to paths\n"
+" By default, the supplied ``svn://repo/path/`` source URL is\n"
+" converted as a single branch. If ``svn://repo/path/trunk`` exists\n"
+" it replaces the default branch. If ``svn://repo/path/branches``\n"
+" exists, its subdirectories are listed as possible branches. If\n"
+" ``svn://repo/path/tags`` exists, it is looked for tags referencing\n"
+" converted branches. Default ``trunk``, ``branches`` and ``tags``\n"
+" values can be overridden with following options. Set them to paths\n"
" relative to the source URL, or leave them blank to disable auto\n"
" detection."
msgstr ""
-msgid ""
-" --config convert.svn.branches=branches (directory name)\n"
-" specify the directory containing branches\n"
-" --config convert.svn.tags=tags (directory name)\n"
-" specify the directory containing tags\n"
-" --config convert.svn.trunk=trunk (directory name)\n"
-" specify the name of the trunk branch"
+msgid " The following options can be set with ``--config``:"
+msgstr ""
+
+msgid ""
+" :convert.svn.branches: specify the directory containing branches.\n"
+" The defaults is ``branches``."
+msgstr ""
+
+msgid ""
+" :convert.svn.tags: specify the directory containing tags. The\n"
+" default is ``tags``."
+msgstr ""
+
+msgid ""
+" :convert.svn.trunk: specify the name of the trunk branch The\n"
+" defauls is ``trunk``."
msgstr ""
msgid ""
@@ -1353,8 +1386,8 @@
msgstr ""
msgid ""
-" --config convert.svn.startrev=0 (svn revision number)\n"
-" specify start Subversion revision."
+" :convert.svn.startrev: specify start Subversion revision number.\n"
+" The default is 0."
msgstr ""
msgid ""
@@ -1368,17 +1401,17 @@
" source to a flat Mercurial repository, ignoring labels, branches\n"
" and integrations. Note that when a depot path is given you then\n"
" usually should specify a target directory, because otherwise the\n"
-" target may be named ...-hg."
+" target may be named ``...-hg``."
msgstr ""
msgid ""
" It is possible to limit the amount of source history to be\n"
-" converted by specifying an initial Perforce revision."
-msgstr ""
-
-msgid ""
-" --config convert.p4.startrev=0 (perforce changelist number)\n"
-" specify initial Perforce revision."
+" converted by specifying an initial Perforce revision:"
+msgstr ""
+
+msgid ""
+" :convert.p4.startrev: specify initial Perforce revision, a\n"
+" Perforce changelist number)."
msgstr ""
msgid ""
@@ -1386,17 +1419,24 @@
" '''''''''''''''''''''"
msgstr ""
-msgid ""
-" --config convert.hg.clonebranches=False (boolean)\n"
-" dispatch source branches in separate clones.\n"
-" --config convert.hg.tagsbranch=default (branch name)\n"
-" tag revisions branch name\n"
-" --config convert.hg.usebranchnames=True (boolean)\n"
-" preserve branch names"
-msgstr ""
-
-msgid " "
-msgstr " "
+msgid " The following options are supported:"
+msgstr ""
+
+msgid ""
+" :convert.hg.clonebranches: dispatch source branches in separate\n"
+" clones. The default is False."
+msgstr ""
+
+msgid ""
+" :convert.hg.tagsbranch: branch name for tag revisions, defaults to\n"
+" ``default``."
+msgstr ""
+
+msgid ""
+" :convert.hg.usebranchnames: preserve branch names. The default is\n"
+" True\n"
+" "
+msgstr ""
msgid "create changeset information from CVS"
msgstr ""
@@ -1962,32 +2002,35 @@
"``[repository]``."
msgid ""
-"The ``[patterns]`` section specifies the line endings used in the\n"
-"working directory. The format is specified by a file pattern. The\n"
-"first match is used, so put more specific patterns first. The\n"
-"available line endings are ``LF``, ``CRLF``, and ``BIN``."
-msgstr ""
-"Sektionen ``[patterns]`` angiver hvilken type linieskift der skal\n"
-"bruges i arbejdskataloget. Typen er angivet ved et filmønster. Den\n"
-"første træffer bliver brugt, så skriv mere specifikke mønstre først.\n"
-"De mulige linieskifttyper er ``LF``, ``CRLF`` og ``BIN``."
+"The ``[patterns]`` section specifies how line endings should be\n"
+"converted between the working copy and the repository. The format is\n"
+"specified by a file pattern. The first match is used, so put more\n"
+"specific patterns first. The available line endings are ``LF``,\n"
+"``CRLF``, and ``BIN``."
+msgstr ""
+"Sektionen ``[patterns]`` angiver hvordan linieskift skal konverteres\n"
+"mellem arbejdskataloget og depotet. Formatet angives med et\n"
+"filmønster. Den første træffer bliver brugt, så skriv mere specifikke\n"
+"mønstre først. De mulige linieskifttyper er ``LF``, ``CRLF`` og\n"
+"``BIN``."
msgid ""
"Files with the declared format of ``CRLF`` or ``LF`` are always\n"
-"checked out in that format and files declared to be binary (``BIN``)\n"
-"are left unchanged. Additionally, ``native`` is an alias for the\n"
-"platform's default line ending: ``LF`` on Unix (including Mac OS X)\n"
-"and ``CRLF`` on Windows. Note that ``BIN`` (do nothing to line\n"
-"endings) is Mercurial's default behaviour; it is only needed if you\n"
-"need to override a later, more general pattern."
-msgstr ""
-"Filer deklareret som ``CRLF`` eller ``LF`` bliver altid hentet ud i\n"
-"dette format og filer deklareret som binære (``BIN``) bliver ikke\n"
-"ændret. Desuden er ``native`` et alias for platforms normale\n"
-"linieskift: ``LF`` på Unix (samt Mac OS X) og ``CRLF`` på Windows.\n"
-"Bemærk at ``BIN`` (gør ingenting ved linieskift) er Mercurials\n"
-"standardopførsel; det er kun nødvendigt at bruge den hvis du skal\n"
-"overskrive et senere og mere generelt mønster."
+"checked out and stored in the repository in that format and files\n"
+"declared to be binary (``BIN``) are left unchanged. Additionally,\n"
+"``native`` is an alias for checking out in the platform's default line\n"
+"ending: ``LF`` on Unix (including Mac OS X) and ``CRLF`` on\n"
+"Windows. Note that ``BIN`` (do nothing to line endings) is Mercurial's\n"
+"default behaviour; it is only needed if you need to override a later,\n"
+"more general pattern."
+msgstr ""
+"Filer deklareret som ``CRLF`` eller ``LF`` bliver altid hentet ud og\n"
+"gemt i depotet i dette format og filer deklareret som binære (``BIN``)\n"
+"bliver ikke ændret. Desuden er ``native`` et alias for platformens\n"
+"normale linieskift: ``LF`` på Unix (samt Mac OS X) og ``CRLF`` på\n"
+"Windows. Bemærk at ``BIN`` (gør ingenting ved linieskift) er\n"
+"Mercurials standardopførsel; det er kun nødvendigt at bruge den hvis\n"
+"du skal overskrive et senere og mere generelt mønster."
msgid ""
"The optional ``[repository]`` section specifies the line endings to\n"
@@ -2036,6 +2079,12 @@
" native = LF"
msgid ""
+".. note::\n"
+" The rules will first apply when files are touched in the working\n"
+" copy, e.g. by updating to null and back to tip to touch all files."
+msgstr ""
+
+msgid ""
"The extension uses an optional ``[eol]`` section in your hgrc file\n"
"(not the ``.hgeol`` file) for settings that control the overall\n"
"behavior. There are two settings:"
@@ -2070,6 +2119,13 @@
" antagelse af at de har miksede linieskift med vilje."
msgid ""
+"The extension provides ``cleverencode:`` and ``cleverdecode:`` filters\n"
+"like the deprecated win32text extension does. This means that you can\n"
+"disable win32text and enable eol and your filters will still work. You\n"
+"only need to these filters until you have prepared a ``.hgeol`` file."
+msgstr ""
+
+msgid ""
"The ``win32text.forbid*`` hooks provided by the win32text extension\n"
"have been unified into a single hook named ``eol.hook``. The hook will\n"
"lookup the expected line endings from the ``.hgeol`` file, which means\n"
@@ -3392,6 +3448,10 @@
msgid "working directory revision is not qtip"
msgstr "arbejdskatalogets revision er ikke qtip"
+#, python-format
+msgid "uncommitted changes in subrepository %s"
+msgstr "udeponerede ændringer i underdepot %s"
+
msgid "local changes found, refresh first"
msgstr "lokale ændringer fundet, genopfrisk først"
@@ -3460,6 +3520,16 @@
msgid "patch series already fully applied\n"
msgstr "serien af rettelser er allerede anvendt fuldt ud\n"
+msgid "cannot use --exact and --move together"
+msgstr "kan ikke bruge --exact og --move sammen"
+
+msgid "cannot push --exact with applied patches"
+msgstr "kan push --exact med anvendte rettelser"
+
+#, python-format
+msgid "%s does not have a parent recorded"
+msgstr "%s har ikke gemt nogen forælder"
+
msgid "please specify the patch to move"
msgstr "angiv venligst lappen der skal flyttes"
@@ -3508,18 +3578,6 @@
msgid "cannot refresh a revision with children"
msgstr "kan ikke genopfriske en revision som har børn"
-#, python-format
-msgid "warning: not refreshing %s\n"
-msgstr "advarsel: genopfrisker ikke %s\n"
-
-#, python-format
-msgid "warning: not adding %s\n"
-msgstr "advarsel: tilføjer ikke %s\n"
-
-#, python-format
-msgid "warning: not removing %s\n"
-msgstr "advarsel: fjerner ikke %s\n"
-
msgid ""
"refresh interrupted while patch was popped! (revert --all, qpush to "
"recover)\n"
@@ -4486,6 +4544,9 @@
msgid "apply on top of local changes"
msgstr "anvend ovenpå lokale ændringer"
+msgid "apply the target patch to its recorded parent"
+msgstr ""
+
msgid "list patch name in commit text"
msgstr ""
@@ -4987,6 +5048,11 @@
msgstr ""
msgid ""
+" In case email sending fails, you will find a backup of your series\n"
+" introductory message in ``.hg/last-email.txt``."
+msgstr ""
+
+msgid ""
" hg email -r 3000 # send patch 3000 only\n"
" hg email -r 3000 -r 3001 # send patches 3000 and 3001\n"
" hg email -r 3000:3005 # send patches 3000 through 3005\n"
@@ -5177,7 +5243,7 @@
" [progress]\n"
" delay = 3 # number of seconds (float) before showing the progress bar\n"
" refresh = 0.1 # time in seconds between refreshes of the progress bar\n"
-" format = topic bar number # format of the progress bar\n"
+" format = topic bar number estimate # format of the progress bar\n"
" width = <none> # if set, the maximum width of the progress information\n"
" # (that is, min(width, term width) will be used)\n"
" clear-complete = True # clear the progress bar after it's done\n"
@@ -5187,10 +5253,26 @@
msgstr ""
msgid ""
-"Valid entries for the format field are topic, bar, number, unit, and\n"
-"item. item defaults to the last 20 characters of the item, but this\n"
-"can be changed by adding either ``-<num>`` which would take the last\n"
-"num characters, or ``+<num>`` for the first num characters.\n"
+"Valid entries for the format field are topic, bar, number, unit,\n"
+"estimate, and item. item defaults to the last 20 characters of the\n"
+"item, but this can be changed by adding either ``-<num>`` which would\n"
+"take the last num characters, or ``+<num>`` for the first num\n"
+"characters.\n"
+msgstr ""
+
+#. i18n: format XX seconds as "XXs"
+#, python-format
+msgid "%02ds"
+msgstr ""
+
+#. i18n: format X minutes and YY seconds as "XmYYs"
+#, python-format
+msgid "%dm%02ds"
+msgstr ""
+
+#. i18n: format X hours and YY minutes as "XhYYm"
+#, python-format
+msgid "%dh%02dm"
msgstr ""
msgid "command to delete untracked files from the working directory"
@@ -5382,7 +5464,8 @@
msgstr "ændringer"
msgid "unresolved conflicts (see hg resolve, then hg rebase --continue)"
-msgstr "uløste konflikter (se først hg resolve og dernæst hg rebase --continue)"
+msgstr ""
+"uløste konflikter (se først hg resolve og dernæst hg rebase --continue)"
#, python-format
msgid "no changes, revision %d skipped\n"
@@ -5578,8 +5661,8 @@
msgid "running non-interactively, use commit instead"
msgstr "kører ikke interaktivt, brug commit i stedet"
-msgid "cannot partially commit a merge (use hg commit instead)"
-msgstr "kan ikke deponere en sammenføjning partielt (brug i stedet hg commit)"
+msgid "cannot partially commit a merge (use \"hg commit\" instead)"
+msgstr "kan ikke deponere en sammenføjning partielt (brug i stedet \"hg commit\")"
msgid "no changes to record\n"
msgstr "ingen ændringer at optage\n"
@@ -6176,6 +6259,9 @@
msgid "unknown archive type '%s'"
msgstr "ukendt depottype '%s'"
+msgid "archiving"
+msgstr "arkiverer"
+
msgid "invalid changegroup"
msgstr "ugyldig changegroup"
@@ -8502,6 +8588,9 @@
msgid "you can't specify a revision and a date"
msgstr "du kan ikke specificeret en revision og en dato"
+msgid "uncommitted merge - use \"hg update\", see \"hg help revert\""
+msgstr ""
+
msgid "no files or directories specified; use --all to revert the whole repo"
msgstr ""
"ingen filer eller mapper specificeret; brug --all for at føre hele repo'et "
@@ -8813,7 +8902,8 @@
msgid ""
" Tags are used to name particular revisions of the repository and are\n"
" very useful to compare different revisions, to go back to significant\n"
-" earlier versions or to mark branch points as releases, etc."
+" earlier versions or to mark branch points as releases, etc. Changing\n"
+" an existing tag is normally disallowed; use -f/--force to override."
msgstr ""
msgid ""
@@ -8823,10 +8913,18 @@
msgid ""
" To facilitate version control, distribution, and merging of tags,\n"
-" they are stored as a file named \".hgtags\" which is managed\n"
-" similarly to other project files and can be hand-edited if\n"
-" necessary. The file '.hg/localtags' is used for local tags (not\n"
-" shared among repositories)."
+" they are stored as a file named \".hgtags\" which is managed similarly\n"
+" to other project files and can be hand-edited if necessary. This\n"
+" also means that tagging creates a new commit. The file\n"
+" \".hg/localtags\" is used for local tags (not shared among\n"
+" repositories)."
+msgstr ""
+
+msgid ""
+" Tag commits are usually made at the head of a branch. If the parent\n"
+" of the working directory is not a branch head, :hg:`tag` aborts; use\n"
+" -f/--force to force the tag commit to be based on a non-head\n"
+" changeset."
msgstr ""
msgid ""
@@ -8859,6 +8957,12 @@
msgid "tag '%s' already exists (use -f to force)"
msgstr "mærkaten '%s' eksisterer allerede (brug -f for at gennemtvinge)"
+msgid "uncommitted merge"
+msgstr "udeponeret sammenføjning"
+
+msgid "not at a branch head (use -f to force)"
+msgstr "ej ved et grenhoved (brug -f for at gennemtvinge)"
+
msgid "list repository tags"
msgstr "vis depotmærkater"
@@ -9752,8 +9856,8 @@
msgid "list the changed files of a revision"
msgstr "vis de ændrede filer i en revision"
-msgid "replace existing tag"
-msgstr "erstat eksisterende mærkat"
+msgid "force tag"
+msgstr "gennemtving markering"
msgid "make the tag local"
msgstr "gør mærkaten lokal"
@@ -10133,6 +10237,10 @@
msgstr "*** import af udvidelse %s fejlede: %s\n"
#, python-format
+msgid "warning: error finding commands in %s\n"
+msgstr "advarsel: fejl ved søgning efter kommandoer i %s\n"
+
+#, python-format
msgid "couldn't find merge tool %s\n"
msgstr "kunne ikke finde sammenføjningsværktøj %s\n"
@@ -11514,6 +11622,13 @@
"Regexp pattern matching is anchored at the root of the repository."
msgstr ""
+msgid ""
+"To read name patterns from a file, use ``listfile:`` or ``listfile0:``.\n"
+"The latter expects null delimited patterns while the former expects line\n"
+"feeds. Each string read from the file is itself treated as a file\n"
+"pattern."
+msgstr ""
+
msgid "Plain examples::"
msgstr ""
@@ -11539,8 +11654,15 @@
msgid "Regexp examples::"
msgstr ""
-msgid ""
-" re:.*\\.c$ any name ending in \".c\", anywhere in the repository\n"
+msgid " re:.*\\.c$ any name ending in \".c\", anywhere in the repository"
+msgstr ""
+
+msgid "File examples::"
+msgstr "Fillisteeksempler::"
+
+msgid ""
+" listfile:list.txt read list from list.txt with one file pattern per line\n"
+" listfile0:list.txt read list from list.txt with null byte delimiters\n"
msgstr ""
msgid "Mercurial supports several ways to specify individual revisions."
@@ -11959,8 +12081,9 @@
msgstr ""
msgid ""
-":branches: String. The name of the branch on which the changeset was\n"
-" committed. Will be empty if the branch name was default."
+":branches: List of strings. The name of the branch on which the\n"
+" changeset was committed. Will be empty if the branch name was\n"
+" default."
msgstr ""
msgid ":children: List of strings. The children of the changeset."
@@ -12344,6 +12467,10 @@
msgstr "(grensammenføjning, glem ikke at deponere)\n"
#, python-format
+msgid "config file %s not found!"
+msgstr "konfigurationsfilen %s blev ikke fundet!"
+
+#, python-format
msgid "error reading %s/.hg/hgrc: %s\n"
msgstr "fejl ved læsning af %s/.hg/hgrc: %s\n"
@@ -12490,6 +12617,10 @@
msgstr ".hg/sharedpath peger på et ikke-eksisterende katalog %s"
#, python-format
+msgid "warning: ignoring unknown working parent %s!\n"
+msgstr "advarsel: ignorerer ukendt forælder %s til arbejdsbiblioteket!\n"
+
+#, python-format
msgid "%r cannot be used in a tag name"
msgstr "%r kan ikke bruges i et mærkatnavnet"
@@ -12596,34 +12727,28 @@
msgid "%d changesets found\n"
msgstr "fandt %d ændringer\n"
-msgid "bundling changes"
-msgstr "bundter ændringer"
-
-msgid "chunks"
-msgstr ""
-
-msgid "bundling manifests"
-msgstr "bundter manifester"
+msgid "bundling"
+msgstr "bundter"
+
+msgid "manifests"
+msgstr "manifester"
#, python-format
msgid "empty or missing revlog for %s"
msgstr "tom eller manglende revlog for %s"
-msgid "bundling files"
-msgstr "bundter filer"
-
msgid "adding changesets\n"
msgstr "tilføjer ændringer\n"
+msgid "chunks"
+msgstr ""
+
msgid "received changelog group is empty"
msgstr "modtagen changelog-gruppe er tom"
msgid "adding manifests\n"
msgstr "tilføjer manifester\n"
-msgid "manifests"
-msgstr "manifester"
-
msgid "adding file changes\n"
msgstr "tilføjer filændringer\n"
@@ -12665,6 +12790,12 @@
msgid "transferred %s in %.1f seconds (%s/sec)\n"
msgstr "overførte %s i %.1f sekunder (%s/sek)\n"
+msgid "can't use TLS: Python SSL support not installed"
+msgstr "kan ikke bruge TLS: Python SSL support er ikke installeret"
+
+msgid "(using smtps)\n"
+msgstr "(bruger smtps)\n"
+
msgid "smtp.host not configured - cannot send mail"
msgstr ""
@@ -12672,11 +12803,8 @@
msgid "sending mail: smtp host %s, port %s\n"
msgstr "sender mail: smtp host %s, port %s\n"
-msgid "can't use TLS: Python SSL support not installed"
-msgstr "kan ikke bruge TLS: Python SSL support er ikke installeret"
-
-msgid "(using tls)\n"
-msgstr "(bruger tsl)\n"
+msgid "(using starttls)\n"
+msgstr "(bruger starttls)\n"
#, python-format
msgid "(authenticating to mail server as %s)\n"
@@ -12717,6 +12845,10 @@
msgstr "ugyldig mønster"
#, python-format
+msgid "unable to read file list (%s)"
+msgstr "kan ikke læse filliste (%s)"
+
+#, python-format
msgid "diff context lines count must be an integer, not %r"
msgstr ""
@@ -13008,10 +13140,10 @@
#, python-format
msgid "can't use %s here"
-msgstr ""
+msgstr "kan ikke bruge %s her"
msgid "can't use a list in this context"
-msgstr ""
+msgstr "en liste kan ikke bruges i denne konteks"
#, python-format
msgid "not a function: %s"
@@ -13028,7 +13160,7 @@
#. i18n: "id" is a keyword
msgid "id requires a string"
-msgstr ""
+msgstr "id kræver en streng"
msgid ""
"``rev(number)``\n"
@@ -13037,29 +13169,30 @@
#. i18n: "rev" is a keyword
msgid "rev requires one argument"
-msgstr ""
+msgstr "rev kræver et argument"
#. i18n: "rev" is a keyword
msgid "rev requires a number"
-msgstr ""
+msgstr "rev kræver et tal"
#. i18n: "rev" is a keyword
msgid "rev expects a number"
msgstr "rev forventer et revisionsnummer"
msgid ""
-"``p1(set)``\n"
-" First parent of changesets in set."
-msgstr ""
-
-msgid ""
-"``p2(set)``\n"
-" Second parent of changesets in set."
-msgstr ""
-
-msgid ""
-"``parents(set)``\n"
-" The set of all parents for all changesets in set."
+"``p1([set])``\n"
+" First parent of changesets in set, or the working directory."
+msgstr ""
+
+msgid ""
+"``p2([set])``\n"
+" Second parent of changesets in set, or the working directory."
+msgstr ""
+
+msgid ""
+"``parents([set])``\n"
+" The set of all parents for all changesets in set, or the working "
+"directory."
msgstr ""
msgid ""
@@ -13322,20 +13455,23 @@
"``tag(name)``\n"
" The specified tag by name, or all tagged revisions if no name is given."
msgstr ""
+"``tag(navn)``\n"
+" Den navngivne mærkat eller alle revisioner med en mærkat hvis der\n"
+" ikke angives noget navn."
#. i18n: "tag" is a keyword
msgid "tag takes one or no arguments"
-msgstr ""
+msgstr "tag tager et eller to argumenter"
#. i18n: "tag" is a keyword
msgid "the argument to tag must be a string"
-msgstr ""
+msgstr "argumentet til tag skal være en streng"
msgid "can't negate that"
msgstr ""
msgid "not a symbol"
-msgstr ""
+msgstr "ikke et symbol"
msgid "empty query"
msgstr "tomt forespørgsel"
@@ -13435,6 +13571,10 @@
msgstr "ukendt underdepottype %s"
#, python-format
+msgid "archiving (%s)"
+msgstr "arkiverer (%s)"
+
+#, python-format
msgid "warning: error \"%s\" in subrepository \"%s\"\n"
msgstr "advarsel: fejl \"%s\" i underdepot \"%s\"\n"
@@ -13458,6 +13598,39 @@
msgstr "fjerner ikke depotet %s fordi det er ændret.\n"
#, python-format
+msgid "cloning subrepo %s\n"
+msgstr "kloner underdepot %s\n"
+
+#, python-format
+msgid "pulling subrepo %s\n"
+msgstr "hiver underdepot %s\n"
+
+#, python-format
+msgid "revision %s does not exist in subrepo %s\n"
+msgstr "revision %s findes ikke i underdepot %s\n"
+
+#, python-format
+msgid "checking out detached HEAD in subrepo %s\n"
+msgstr ""
+
+msgid "check out a git branch if you intend to make changes\n"
+msgstr ""
+
+#, python-format
+msgid "unrelated git branch checked out in subrepo %s\n"
+msgstr ""
+
+#, python-format
+msgid "pushing branch %s of subrepo %s\n"
+msgstr "skubber gren %s af underdepot %s\n"
+
+#, python-format
+msgid ""
+"no branch checked out in subrepo %s\n"
+"cannot push revision %s"
+msgstr ""
+
+#, python-format
msgid "%s, line %s: %s\n"
msgstr "%s, linie %s: %s\n"
@@ -13471,22 +13644,36 @@
msgid ".hg/tags.cache is corrupt, rebuilding it\n"
msgstr ""
+#, python-format
+msgid "unknown method '%s'"
+msgstr "ukendt metode '%s'"
+
+msgid "expected a symbol"
+msgstr "forventede et symbol"
+
+#, python-format
+msgid "unknown function '%s'"
+msgstr "ukendt funktion '%s'"
+
+msgid "expected template specifier"
+msgstr ""
+
+#, python-format
+msgid "filter %s expects one argument"
+msgstr "filter %s kræver et argument"
+
msgid "unmatched quotes"
msgstr ""
#, python-format
-msgid "error expanding '%s%%%s'"
-msgstr "fejl ved ekspansion af '%s%%%s'"
-
-#, python-format
-msgid "unknown filter '%s'"
-msgstr "ukendt filter '%s'"
-
-#, python-format
msgid "style not found: %s"
msgstr ""
#, python-format
+msgid "\"%s\" not in template map"
+msgstr "\"%s\" er ikke i skabelon-fil"
+
+#, python-format
msgid "template file %s: %s"
msgstr "skabelon-fil %s: %s"
@@ -13577,6 +13764,9 @@
msgid "ignoring invalid [auth] key '%s'\n"
msgstr "ignorerer ugyldig [auth] nøgle '%s'\n"
+msgid "kb"
+msgstr ""
+
msgid "certificate checking requires Python 2.6"
msgstr ""
@@ -13588,10 +13778,15 @@
msgstr "certifikatet er for %s"
msgid "no commonName found in certificate"
-msgstr ""
+msgstr "fandt ikke noget commonName i certifikatet"
#, python-format
msgid "%s certificate error: %s"
+msgstr "%s certifikatfejl: %s"
+
+#, python-format
+msgid ""
+"warning: %s certificate not verified (check web.cacerts config setting)\n"
msgstr ""
#, python-format
@@ -13599,6 +13794,10 @@
msgstr "kommandoen '%s' fejlede: %s"
#, python-format
+msgid "path ends in directory separator: %s"
+msgstr ""
+
+#, python-format
msgid "path contains illegal component: %s"
msgstr "stien indeholder ugyldig komponent: %s"
@@ -13686,7 +13885,7 @@
#, python-format
msgid "no port number associated with service '%s'"
-msgstr ""
+msgstr "der er ikke knyttet noget portnummer til servicen '%s'"
msgid "cannot verify bundle or remote repos"
msgstr "kan ikke verificere bundt eller fjerndepoter"
@@ -13743,7 +13942,7 @@
msgstr "duplikeret revision %d (%d)"
msgid "abandoned transaction found - run hg recover\n"
-msgstr ""
+msgstr "fandt efterladt transaktion - kør hg recover\n"
#, python-format
msgid "repository uses revlog format %d\n"
@@ -13777,7 +13976,7 @@
msgstr "krydstjekker filer i ændringer og manifester\n"
msgid "crosschecking"
-msgstr ""
+msgstr "krydstjekker"
#, python-format
msgid "changeset refers to unknown manifest %s"
@@ -13805,7 +14004,7 @@
#, python-format
msgid "%s not in manifests"
-msgstr ""
+msgstr "%s findes ikke i manifestet"
#, python-format
msgid "unpacked size is %s, %s expected"
--- a/i18n/polib.py Sat Feb 12 16:08:41 2011 +0800
+++ b/i18n/polib.py Wed Feb 16 14:13:22 2011 -0600
@@ -105,7 +105,7 @@
... finally:
... os.unlink(tmpf)
"""
- if kwargs.get('autodetect_encoding', True) == True:
+ if kwargs.get('autodetect_encoding', True):
enc = detect_encoding(fpath)
else:
enc = kwargs.get('encoding', default_encoding)
@@ -159,7 +159,7 @@
... finally:
... os.unlink(tmpf)
"""
- if kwargs.get('autodetect_encoding', True) == True:
+ if kwargs.get('autodetect_encoding', True):
enc = detect_encoding(fpath, True)
else:
enc = kwargs.get('encoding', default_encoding)
--- a/mercurial/archival.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/archival.py Wed Feb 16 14:13:22 2011 -0600
@@ -8,7 +8,7 @@
from i18n import _
from node import hex
import cmdutil
-import util
+import util, encoding
import cStringIO, os, stat, tarfile, time, zipfile
import zlib, gzip
@@ -84,6 +84,7 @@
def __init__(self, dest, mtime, kind=''):
self.mtime = mtime
+ self.fileobj = None
def taropen(name, mode, fileobj=None):
if kind == 'gz':
@@ -93,8 +94,10 @@
gzfileobj = self.GzipFileWithTime(name, mode + 'b',
zlib.Z_BEST_COMPRESSION,
fileobj, timestamp=mtime)
+ self.fileobj = gzfileobj
return tarfile.TarFile.taropen(name, mode, gzfileobj)
else:
+ self.fileobj = fileobj
return tarfile.open(name, mode + kind, fileobj)
if isinstance(dest, str):
@@ -120,6 +123,8 @@
def done(self):
self.z.close()
+ if self.fileobj:
+ self.fileobj.close()
class tellable(object):
'''provide tell method for zipfile.ZipFile when writing to http
@@ -245,7 +250,7 @@
if repo.ui.configbool("ui", "archivemeta", True):
def metadata():
base = 'repo: %s\nnode: %s\nbranch: %s\n' % (
- repo[0].hex(), hex(node), ctx.branch())
+ repo[0].hex(), hex(node), encoding.fromlocal(ctx.branch()))
tags = ''.join('tag: %s\n' % t for t in ctx.tags()
if repo.tagtype(t) == 'global')
@@ -262,13 +267,18 @@
write('.hg_archival.txt', 0644, False, metadata)
- for f in ctx:
+ total = len(ctx.manifest())
+ repo.ui.progress(_('archiving'), 0, unit=_('files'), total=total)
+ for i, f in enumerate(ctx):
ff = ctx.flags(f)
write(f, 'x' in ff and 0755 or 0644, 'l' in ff, ctx[f].data)
+ repo.ui.progress(_('archiving'), i + 1, item=f,
+ unit=_('files'), total=total)
+ repo.ui.progress(_('archiving'), None)
if subrepos:
for subpath in ctx.substate:
sub = ctx.sub(subpath)
- sub.archive(archiver, prefix)
+ sub.archive(repo.ui, archiver, prefix)
archiver.done()
--- a/mercurial/bdiff.c Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/bdiff.c Wed Feb 16 14:13:22 2011 -0600
@@ -57,12 +57,10 @@
int pos, len;
};
+struct hunk;
struct hunk {
int a1, a2, b1, b2;
-};
-
-struct hunklist {
- struct hunk *base, *head;
+ struct hunk *next;
};
int splitlines(const char *a, int len, struct line **lr)
@@ -223,8 +221,8 @@
return mk + mb;
}
-static void recurse(struct line *a, struct line *b, struct pos *pos,
- int a1, int a2, int b1, int b2, struct hunklist *l)
+static struct hunk *recurse(struct line *a, struct line *b, struct pos *pos,
+ int a1, int a2, int b1, int b2, struct hunk *l)
{
int i, j, k;
@@ -232,51 +230,66 @@
/* find the longest match in this chunk */
k = longest_match(a, b, pos, a1, a2, b1, b2, &i, &j);
if (!k)
- return;
+ return l;
/* and recurse on the remaining chunks on either side */
- recurse(a, b, pos, a1, i, b1, j, l);
- l->head->a1 = i;
- l->head->a2 = i + k;
- l->head->b1 = j;
- l->head->b2 = j + k;
- l->head++;
- /* tail-recursion didn't happen, so doing equivalent iteration */
+ l = recurse(a, b, pos, a1, i, b1, j, l);
+ if (!l)
+ return NULL;
+
+ l->next = (struct hunk *)malloc(sizeof(struct hunk));
+ if (!l->next)
+ return NULL;
+
+ l = l->next;
+ l->a1 = i;
+ l->a2 = i + k;
+ l->b1 = j;
+ l->b2 = j + k;
+ l->next = NULL;
+
+ /* tail-recursion didn't happen, so do equivalent iteration */
a1 = i + k;
b1 = j + k;
}
}
-static struct hunklist diff(struct line *a, int an, struct line *b, int bn)
+static int diff(struct line *a, int an, struct line *b, int bn,
+ struct hunk *base)
{
- struct hunklist l;
struct hunk *curr;
struct pos *pos;
- int t;
+ int t, count = 0;
/* allocate and fill arrays */
t = equatelines(a, an, b, bn);
pos = (struct pos *)calloc(bn ? bn : 1, sizeof(struct pos));
- /* we can't have more matches than lines in the shorter file */
- l.head = l.base = (struct hunk *)malloc(sizeof(struct hunk) *
- ((an<bn ? an:bn) + 1));
+
+ if (pos && t) {
+ /* generate the matching block list */
+
+ curr = recurse(a, b, pos, 0, an, 0, bn, base);
+ if (!curr)
+ return -1;
- if (pos && l.base && t) {
- /* generate the matching block list */
- recurse(a, b, pos, 0, an, 0, bn, &l);
- l.head->a1 = l.head->a2 = an;
- l.head->b1 = l.head->b2 = bn;
- l.head++;
+ /* sentinel end hunk */
+ curr->next = (struct hunk *)malloc(sizeof(struct hunk));
+ if (!curr->next)
+ return -1;
+ curr = curr->next;
+ curr->a1 = curr->a2 = an;
+ curr->b1 = curr->b2 = bn;
+ curr->next = NULL;
}
free(pos);
/* normalize the hunk list, try to push each hunk towards the end */
- for (curr = l.base; curr != l.head; curr++) {
- struct hunk *next = curr + 1;
+ for (curr = base->next; curr; curr = curr->next) {
+ struct hunk *next = curr->next;
int shift = 0;
- if (next == l.head)
+ if (!next)
break;
if (curr->a2 == next->a1)
@@ -297,16 +310,26 @@
next->a1 += shift;
}
- return l;
+ for (curr = base->next; curr; curr = curr->next)
+ count++;
+ return count;
+}
+
+static void freehunks(struct hunk *l)
+{
+ struct hunk *n;
+ for (; l; l = n) {
+ n = l->next;
+ free(l);
+ }
}
static PyObject *blocks(PyObject *self, PyObject *args)
{
PyObject *sa, *sb, *rl = NULL, *m;
struct line *a, *b;
- struct hunklist l = {NULL, NULL};
- struct hunk *h;
- int an, bn, pos = 0;
+ struct hunk l, *h;
+ int an, bn, count, pos = 0;
if (!PyArg_ParseTuple(args, "SS:bdiff", &sa, &sb))
return NULL;
@@ -317,12 +340,16 @@
if (!a || !b)
goto nomem;
- l = diff(a, an, b, bn);
- rl = PyList_New(l.head - l.base);
- if (!l.head || !rl)
+ l.next = NULL;
+ count = diff(a, an, b, bn, &l);
+ if (count < 0)
goto nomem;
- for (h = l.base; h != l.head; h++) {
+ rl = PyList_New(count);
+ if (!rl)
+ goto nomem;
+
+ for (h = l.next; h; h = h->next) {
m = Py_BuildValue("iiii", h->a1, h->a2, h->b1, h->b2);
PyList_SetItem(rl, pos, m);
pos++;
@@ -331,7 +358,7 @@
nomem:
free(a);
free(b);
- free(l.base);
+ freehunks(l.next);
return rl ? rl : PyErr_NoMemory();
}
@@ -340,10 +367,9 @@
char *sa, *sb;
PyObject *result = NULL;
struct line *al, *bl;
- struct hunklist l = {NULL, NULL};
- struct hunk *h;
+ struct hunk l, *h;
char encode[12], *rb;
- int an, bn, len = 0, la, lb;
+ int an, bn, len = 0, la, lb, count;
if (!PyArg_ParseTuple(args, "s#s#:bdiff", &sa, &la, &sb, &lb))
return NULL;
@@ -353,13 +379,14 @@
if (!al || !bl)
goto nomem;
- l = diff(al, an, bl, bn);
- if (!l.head)
+ l.next = NULL;
+ count = diff(al, an, bl, bn, &l);
+ if (count < 0)
goto nomem;
/* calculate length of output */
la = lb = 0;
- for (h = l.base; h != l.head; h++) {
+ for (h = l.next; h; h = h->next) {
if (h->a1 != la || h->b1 != lb)
len += 12 + bl[h->b1].l - bl[lb].l;
la = h->a2;
@@ -375,7 +402,7 @@
rb = PyBytes_AsString(result);
la = lb = 0;
- for (h = l.base; h != l.head; h++) {
+ for (h = l.next; h; h = h->next) {
if (h->a1 != la || h->b1 != lb) {
len = bl[h->b1].l - bl[lb].l;
*(uint32_t *)(encode) = htonl(al[la].l - al->l);
@@ -392,7 +419,7 @@
nomem:
free(al);
free(bl);
- free(l.base);
+ freehunks(l.next);
return result ? result : PyErr_NoMemory();
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/bookmarks.py Wed Feb 16 14:13:22 2011 -0600
@@ -0,0 +1,176 @@
+# Mercurial bookmark support code
+#
+# Copyright 2008 David Soria Parra <dsp@php.net>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+from mercurial.i18n import _
+from mercurial.node import nullid, nullrev, bin, hex, short
+from mercurial import encoding, util
+import os
+
+def valid(mark):
+ for c in (':', '\0', '\n', '\r'):
+ if c in mark:
+ return False
+ return True
+
+def read(repo):
+ '''Parse .hg/bookmarks file and return a dictionary
+
+ Bookmarks are stored as {HASH}\\s{NAME}\\n (localtags format) values
+ in the .hg/bookmarks file.
+ Read the file and return a (name=>nodeid) dictionary
+ '''
+ try:
+ bookmarks = {}
+ for line in repo.opener('bookmarks'):
+ sha, refspec = line.strip().split(' ', 1)
+ refspec = encoding.tolocal(refspec)
+ bookmarks[refspec] = repo.changelog.lookup(sha)
+ except:
+ pass
+ return bookmarks
+
+def readcurrent(repo):
+ '''Get the current bookmark
+
+ If we use gittishsh branches we have a current bookmark that
+ we are on. This function returns the name of the bookmark. It
+ is stored in .hg/bookmarks.current
+ '''
+ mark = None
+ if os.path.exists(repo.join('bookmarks.current')):
+ file = repo.opener('bookmarks.current')
+ # No readline() in posixfile_nt, reading everything is cheap
+ mark = encoding.tolocal((file.readlines() or [''])[0])
+ if mark == '':
+ mark = None
+ file.close()
+ return mark
+
+def write(repo):
+ '''Write bookmarks
+
+ Write the given bookmark => hash dictionary to the .hg/bookmarks file
+ in a format equal to those of localtags.
+
+ We also store a backup of the previous state in undo.bookmarks that
+ can be copied back on rollback.
+ '''
+ refs = repo._bookmarks
+
+ try:
+ bms = repo.opener('bookmarks').read()
+ except IOError:
+ bms = ''
+ repo.opener('undo.bookmarks', 'w').write(bms)
+
+ if repo._bookmarkcurrent not in refs:
+ setcurrent(repo, None)
+ for mark in refs.keys():
+ if not valid(mark):
+ raise util.Abort(_("bookmark '%s' contains illegal "
+ "character" % mark))
+
+ wlock = repo.wlock()
+ try:
+
+ file = repo.opener('bookmarks', 'w', atomictemp=True)
+ for refspec, node in refs.iteritems():
+ file.write("%s %s\n" % (hex(node), encoding.fromlocal(refspec)))
+ file.rename()
+
+ # touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
+ try:
+ os.utime(repo.sjoin('00changelog.i'), None)
+ except OSError:
+ pass
+
+ finally:
+ wlock.release()
+
+def setcurrent(repo, mark):
+ '''Set the name of the bookmark that we are currently on
+
+ Set the name of the bookmark that we are on (hg update <bookmark>).
+ The name is recorded in .hg/bookmarks.current
+ '''
+ current = repo._bookmarkcurrent
+ if current == mark:
+ return
+
+ refs = repo._bookmarks
+
+ # do not update if we do update to a rev equal to the current bookmark
+ if (mark and mark not in refs and
+ current and refs[current] == repo.changectx('.').node()):
+ return
+ if mark not in refs:
+ mark = ''
+ if not valid(mark):
+ raise util.Abort(_("bookmark '%s' contains illegal "
+ "character" % mark))
+
+ wlock = repo.wlock()
+ try:
+ file = repo.opener('bookmarks.current', 'w', atomictemp=True)
+ file.write(mark)
+ file.rename()
+ finally:
+ wlock.release()
+ repo._bookmarkcurrent = mark
+
+def update(repo, parents, node):
+ marks = repo._bookmarks
+ update = False
+ mark = repo._bookmarkcurrent
+ if mark and marks[mark] in parents:
+ marks[mark] = node
+ update = True
+ if update:
+ write(repo)
+
+def listbookmarks(repo):
+ # We may try to list bookmarks on a repo type that does not
+ # support it (e.g., statichttprepository).
+ if not hasattr(repo, '_bookmarks'):
+ return {}
+
+ d = {}
+ for k, v in repo._bookmarks.iteritems():
+ d[k] = hex(v)
+ return d
+
+def pushbookmark(repo, key, old, new):
+ w = repo.wlock()
+ try:
+ marks = repo._bookmarks
+ if hex(marks.get(key, '')) != old:
+ return False
+ if new == '':
+ del marks[key]
+ else:
+ if new not in repo:
+ return False
+ marks[key] = repo[new].node()
+ write(repo)
+ return True
+ finally:
+ w.release()
+
+def diff(ui, repo, remote):
+ ui.status(_("searching for changed bookmarks\n"))
+
+ lmarks = repo.listkeys('bookmarks')
+ rmarks = remote.listkeys('bookmarks')
+
+ diff = sorted(set(rmarks) - set(lmarks))
+ for k in diff:
+ ui.write(" %-25s %s\n" % (k, rmarks[k][:12]))
+
+ if len(diff) <= 0:
+ ui.status(_("no changed bookmarks found\n"))
+ return 1
+ return 0
--- a/mercurial/bundlerepo.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/bundlerepo.py Wed Feb 16 14:13:22 2011 -0600
@@ -174,7 +174,7 @@
self._url = 'bundle:' + bundlename
self.tempfile = None
- f = open(bundlename, "rb")
+ f = util.posixfile(bundlename, "rb")
self.bundle = changegroup.readbundle(f, bundlename)
if self.bundle.compressed():
fdtemp, temp = tempfile.mkstemp(prefix="hg-bundle-",
@@ -192,7 +192,7 @@
finally:
fptemp.close()
- f = open(self.tempfile, "rb")
+ f = util.posixfile(self.tempfile, "rb")
self.bundle = changegroup.readbundle(f, bundlename)
# dict with the mapping 'filename' -> position in the bundle
@@ -251,11 +251,6 @@
self.bundle.close()
if self.tempfile is not None:
os.unlink(self.tempfile)
-
- def __del__(self):
- del self.bundle
- if self.tempfile is not None:
- os.unlink(self.tempfile)
if self._tempparent:
shutil.rmtree(self._tempparent, True)
--- a/mercurial/cmdutil.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/cmdutil.py Wed Feb 16 14:13:22 2011 -0600
@@ -147,6 +147,11 @@
# attempt to parse old-style ranges first to deal with
# things like old-tag which contain query metacharacters
try:
+ if isinstance(spec, int):
+ seen.add(spec)
+ l.append(spec)
+ continue
+
if revrangesep in spec:
start, end = spec.split(revrangesep, 1)
start = revfix(repo, start, 0)
@@ -228,7 +233,8 @@
writable = 'w' in mode or 'a' in mode
if not pat or pat == '-':
- return writable and sys.stdout or sys.stdin
+ fp = writable and sys.stdout or sys.stdin
+ return os.fdopen(os.dup(fp.fileno()), mode)
if hasattr(pat, 'write') and writable:
return pat
if hasattr(pat, 'read') and 'r' in mode:
@@ -673,7 +679,9 @@
parents.reverse()
prev = (parents and parents[0]) or nullid
+ shouldclose = False
if not fp:
+ shouldclose = True
fp = make_file(repo, template, node, total=total, seqno=seqno,
revwidth=revwidth, mode='ab')
if fp != sys.stdout and hasattr(fp, 'name'):
@@ -694,6 +702,9 @@
for chunk in patch.diff(repo, prev, node, opts=opts):
fp.write(chunk)
+ if shouldclose:
+ fp.close()
+
for seqno, rev in enumerate(revs):
single(rev, seqno + 1, fp)
@@ -796,9 +807,11 @@
branch = ctx.branch()
# don't show the default branch name
if branch != 'default':
- branch = encoding.tolocal(branch)
self.ui.write(_("branch: %s\n") % branch,
label='log.branch')
+ for bookmark in self.repo.nodebookmarks(changenode):
+ self.ui.write(_("bookmark: %s\n") % bookmark,
+ label='log.bookmark')
for tag in self.repo.nodetags(changenode):
self.ui.write(_("tag: %s\n") % tag,
label='log.tag')
@@ -1352,8 +1365,7 @@
if ctx.p2():
edittext.append(_("HG: branch merge"))
if ctx.branch():
- edittext.append(_("HG: branch '%s'")
- % encoding.tolocal(ctx.branch()))
+ edittext.append(_("HG: branch '%s'") % ctx.branch())
edittext.extend([_("HG: subrepo %s") % s for s in subs])
edittext.extend([_("HG: added %s") % f for f in added])
edittext.extend([_("HG: changed %s") % f for f in modified])
--- a/mercurial/commands.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/commands.py Wed Feb 16 14:13:22 2011 -0600
@@ -9,7 +9,7 @@
from lock import release
from i18n import _, gettext
import os, re, sys, difflib, time, tempfile
-import hg, util, revlog, extensions, copies, error
+import hg, util, revlog, extensions, copies, error, bookmarks
import patch, help, mdiff, url, encoding, templatekw, discovery
import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server
import merge as mergemod
@@ -58,7 +58,7 @@
repository.
New files are ignored if they match any of the patterns in
- .hgignore. As with add, these changes take effect at the next
+ ``.hgignore``. As with add, these changes take effect at the next
commit.
Use the -s/--similarity option to detect renamed files. With a
@@ -126,7 +126,7 @@
lastfunc = funcmap[-1]
funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
- ctx = repo[opts.get('rev')]
+ ctx = cmdutil.revsingle(repo, opts.get('rev'))
m = cmdutil.match(repo, pats, opts)
follow = not opts.get('no_follow')
for abs in ctx.walk(m):
@@ -178,7 +178,7 @@
Returns 0 on success.
'''
- ctx = repo[opts.get('rev')]
+ ctx = cmdutil.revsingle(repo, opts.get('rev'))
if not ctx:
raise util.Abort(_('no working directory: please specify a revision'))
node = ctx.node()
@@ -239,7 +239,7 @@
opts['date'] = util.parsedate(date)
cmdutil.bail_if_changed(repo)
- node = repo.lookup(rev)
+ node = cmdutil.revsingle(repo, rev).node()
op1, op2 = repo.dirstate.parents()
a = repo.changelog.ancestor(op1, node)
@@ -404,7 +404,8 @@
raise util.Abort(_("%s killed") % command)
else:
transition = "bad"
- ctx = repo[rev or '.']
+ ctx = cmdutil.revsingle(repo, rev)
+ rev = None # clear for future iterations
state[transition].append(ctx.node())
ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
check_state(state, interactive=False)
@@ -456,6 +457,95 @@
cmdutil.bail_if_changed(repo)
return hg.clean(repo, node)
+def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False, rename=None):
+ '''track a line of development with movable markers
+
+ Bookmarks are pointers to certain commits that move when
+ committing. Bookmarks are local. They can be renamed, copied and
+ deleted. It is possible to use bookmark names in :hg:`merge` and
+ :hg:`update` to merge and update respectively to a given bookmark.
+
+ You can use :hg:`bookmark NAME` to set a bookmark on the working
+ directory's parent revision with the given name. If you specify
+ a revision using -r REV (where REV may be an existing bookmark),
+ the bookmark is assigned to that revision.
+
+ Bookmarks can be pushed and pulled between repositories (see :hg:`help
+ push` and :hg:`help pull`). This requires both the local and remote
+ repositories to support bookmarks. For versions prior to 1.8, this means
+ the bookmarks extension must be enabled.
+ '''
+ hexfn = ui.debugflag and hex or short
+ marks = repo._bookmarks
+ cur = repo.changectx('.').node()
+
+ if rename:
+ if rename not in marks:
+ raise util.Abort(_("a bookmark of this name does not exist"))
+ if mark in marks and not force:
+ raise util.Abort(_("a bookmark of the same name already exists"))
+ if mark is None:
+ raise util.Abort(_("new bookmark name required"))
+ marks[mark] = marks[rename]
+ del marks[rename]
+ if repo._bookmarkcurrent == rename:
+ bookmarks.setcurrent(repo, mark)
+ bookmarks.write(repo)
+ return
+
+ if delete:
+ if mark is None:
+ raise util.Abort(_("bookmark name required"))
+ if mark not in marks:
+ raise util.Abort(_("a bookmark of this name does not exist"))
+ if mark == repo._bookmarkcurrent:
+ bookmarks.setcurrent(repo, None)
+ del marks[mark]
+ bookmarks.write(repo)
+ return
+
+ if mark is not None:
+ if "\n" in mark:
+ raise util.Abort(_("bookmark name cannot contain newlines"))
+ mark = mark.strip()
+ if not mark:
+ raise util.Abort(_("bookmark names cannot consist entirely of "
+ "whitespace"))
+ if mark in marks and not force:
+ raise util.Abort(_("a bookmark of the same name already exists"))
+ if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
+ and not force):
+ raise util.Abort(
+ _("a bookmark cannot have the name of an existing branch"))
+ if rev:
+ marks[mark] = repo.lookup(rev)
+ else:
+ marks[mark] = repo.changectx('.').node()
+ bookmarks.setcurrent(repo, mark)
+ bookmarks.write(repo)
+ return
+
+ if mark is None:
+ if rev:
+ raise util.Abort(_("bookmark name required"))
+ if len(marks) == 0:
+ ui.status(_("no bookmarks set\n"))
+ else:
+ for bmark, n in sorted(marks.iteritems()):
+ current = repo._bookmarkcurrent
+ if bmark == current and n == cur:
+ prefix, label = '*', 'bookmarks.current'
+ else:
+ prefix, label = ' ', ''
+
+ if ui.quiet:
+ ui.write("%s\n" % bmark, label=label)
+ else:
+ ui.write(" %s %-25s %d:%s\n" % (
+ prefix, bmark, repo.changelog.rev(n), hexfn(n)),
+ label=label)
+ return
+
def branch(ui, repo, label=None, **opts):
"""set or show the current branch name
@@ -483,15 +573,14 @@
repo.dirstate.setbranch(label)
ui.status(_('reset working directory to branch %s\n') % label)
elif label:
- utflabel = encoding.fromlocal(label)
- if not opts.get('force') and utflabel in repo.branchtags():
+ if not opts.get('force') and label in repo.branchtags():
if label not in [p.branch() for p in repo.parents()]:
raise util.Abort(_('a branch of the same name already exists'
" (use 'hg update' to switch to it)"))
- repo.dirstate.setbranch(utflabel)
+ repo.dirstate.setbranch(label)
ui.status(_('marked working directory as branch %s\n') % label)
else:
- ui.write("%s\n" % encoding.tolocal(repo.dirstate.branch()))
+ ui.write("%s\n" % repo.dirstate.branch())
def branches(ui, repo, active=False, closed=False):
"""list repository named branches
@@ -520,9 +609,8 @@
for isactive, node, tag in branches:
if (not active) or isactive:
- encodedtag = encoding.tolocal(tag)
if ui.quiet:
- ui.write("%s\n" % encodedtag)
+ ui.write("%s\n" % tag)
else:
hn = repo.lookup(node)
if isactive:
@@ -538,10 +626,10 @@
notice = _(' (inactive)')
if tag == repo.dirstate.branch():
label = 'branches.current'
- rev = str(node).rjust(31 - encoding.colwidth(encodedtag))
+ rev = str(node).rjust(31 - encoding.colwidth(tag))
rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
- encodedtag = ui.label(encodedtag, label)
- ui.write("%s %s%s\n" % (encodedtag, rev, notice))
+ tag = ui.label(tag, label)
+ ui.write("%s %s%s\n" % (tag, rev, notice))
def bundle(ui, repo, fname, dest=None, **opts):
"""create a changegroup file
@@ -568,11 +656,14 @@
Returns 0 on success, 1 if no changes found.
"""
- revs = opts.get('rev') or None
+ revs = None
+ if 'rev' in opts:
+ revs = cmdutil.revrange(repo, opts['rev'])
+
if opts.get('all'):
base = ['null']
else:
- base = opts.get('base')
+ base = cmdutil.revrange(repo, opts.get('base'))
if base:
if dest:
raise util.Abort(_("--base is incompatible with specifying "
@@ -654,6 +745,7 @@
if opts.get('decode'):
data = repo.wwritedata(abs, data)
fp.write(data)
+ fp.close()
err = 0
return err
@@ -666,12 +758,12 @@
basename of the source.
The location of the source is added to the new repository's
- .hg/hgrc file, as the default to be used for future pulls.
+ ``.hg/hgrc`` file, as the default to be used for future pulls.
See :hg:`help urls` for valid source format details.
It is possible to specify an ``ssh://`` URL as the destination, but no
- .hg/hgrc and working directory will be created on the remote side.
+ ``.hg/hgrc`` and working directory will be created on the remote side.
Please see :hg:`help urls` for important details about ``ssh://`` URLs.
A set of changesets (tags, or branch names) to pull may be specified
@@ -737,7 +829,7 @@
"""commit the specified files or all outstanding changes
Commit changes to the given files into the repository. Unlike a
- centralized RCS, this operation is a local operation. See
+ centralized SCM, this operation is a local operation. See
:hg:`push` for a way to actively distribute your changes.
If a list of files is omitted, all changes reported by :hg:`status`
@@ -1022,7 +1114,7 @@
def debugrebuildstate(ui, repo, rev="tip"):
"""rebuild the dirstate as it would look like for the given revision"""
- ctx = repo[rev]
+ ctx = cmdutil.revsingle(repo, rev)
wlock = repo.wlock()
try:
repo.dirstate.rebuild(ctx.node(), ctx.manifest())
@@ -1112,7 +1204,7 @@
key, old, new = keyinfo
r = target.pushkey(namespace, key, old, new)
ui.status(str(r) + '\n')
- return not(r)
+ return not r
else:
for k, v in target.listkeys(namespace).iteritems():
ui.write("%s\t%s\n" % (k.encode('string-escape'),
@@ -1136,12 +1228,12 @@
Returns 0 on success.
"""
- if not rev2:
- rev2 = hex(nullid)
+ r1 = cmdutil.revsingle(repo, rev1).node()
+ r2 = cmdutil.revsingle(repo, rev2, 'null').node()
wlock = repo.wlock()
try:
- repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
+ repo.dirstate.setparents(r1, r2)
finally:
wlock.release()
@@ -1170,9 +1262,8 @@
ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
def debugsub(ui, repo, rev=None):
- if rev == '':
- rev = None
- for k, v in sorted(repo[rev].substate.items()):
+ ctx = cmdutil.revsingle(repo, rev, None)
+ for k, v in sorted(ctx.substate.items()):
ui.write('path %s\n' % k)
ui.write(' source %s\n' % v[0])
ui.write(' revision %s\n' % v[1])
@@ -1256,6 +1347,14 @@
m = util.matchdate(range)
ui.write("match: %s\n" % m(d[0]))
+def debugignore(ui, repo, *values, **opts):
+ """display the combined ignore pattern"""
+ ignore = repo.dirstate._ignore
+ if hasattr(ignore, 'includepat'):
+ ui.write("%s\n" % ignore.includepat)
+ else:
+ raise util.Abort(_("no ignore patterns found"))
+
def debugindex(ui, repo, file_, **opts):
"""dump the contents of an index file"""
r = None
@@ -1431,7 +1530,7 @@
def debugrename(ui, repo, file1, *pats, **opts):
"""dump rename information"""
- ctx = repo[opts.get('rev')]
+ ctx = cmdutil.revsingle(repo, opts.get('rev'))
m = cmdutil.match(repo, (file1,) + pats, opts)
for abs in ctx.walk(m):
fctx = ctx[abs]
@@ -1804,10 +1903,9 @@
Returns 0 if matching heads are found, 1 if not.
"""
- if opts.get('rev'):
- start = repo.lookup(opts['rev'])
- else:
- start = None
+ start = None
+ if 'rev' in opts:
+ start = cmdutil.revsingle(repo, opts['rev'], None).node()
if opts.get('topo'):
heads = [repo[h] for h in repo.heads(start)]
@@ -1824,8 +1922,7 @@
heads += [repo[h] for h in ls if rev(h) in descendants]
if branchrevs:
- decode, encode = encoding.fromlocal, encoding.tolocal
- branches = set(repo[decode(br)].branch() for br in branchrevs)
+ branches = set(repo[br].branch() for br in branchrevs)
heads = [h for h in heads if h.branch() in branches]
if not opts.get('closed'):
@@ -1838,7 +1935,7 @@
if branchrevs:
haveheads = set(h.branch() for h in heads)
if branches - haveheads:
- headless = ', '.join(encode(b) for b in branches - haveheads)
+ headless = ', '.join(b for b in branches - haveheads)
msg = _('no open branch heads found on branches %s')
if opts.get('rev'):
msg += _(' (started at %s)' % opts['rev'])
@@ -2031,7 +2128,7 @@
'extensions\n'))
def helpextcmd(name):
- cmd, ext, mod = extensions.disabledcmd(name, ui.config('ui', 'strict'))
+ cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
doc = gettext(mod.__doc__).splitlines()[0]
msg = help.listexts(_("'%s' is provided by the following "
@@ -2196,14 +2293,14 @@
output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
(changed) and "+" or ""))
else:
- ctx = repo[rev]
+ ctx = cmdutil.revsingle(repo, rev)
if default or id:
output = [hexfunc(ctx.node())]
if num:
output.append(str(ctx.rev()))
if repo.local() and default and not ui.quiet:
- b = encoding.tolocal(ctx.branch())
+ b = ctx.branch()
if b != 'default':
output.append("(%s)" % b)
@@ -2213,7 +2310,7 @@
output.append(t)
if branch:
- output.append(encoding.tolocal(ctx.branch()))
+ output.append(ctx.branch())
if tags:
output.extend(ctx.tags())
@@ -2275,6 +2372,7 @@
d = opts["base"]
strip = opts["strip"]
wlock = lock = None
+ msgs = []
def tryone(ui, hunk):
tmpname, message, user, date, branch, nodeid, p1, p2 = \
@@ -2325,7 +2423,10 @@
finally:
files = cmdutil.updatedir(ui, repo, files,
similarity=sim / 100.0)
- if not opts.get('no_commit'):
+ if opts.get('no_commit'):
+ if message:
+ msgs.append(message)
+ else:
if opts.get('exact'):
m = None
else:
@@ -2374,6 +2475,8 @@
if not haspatch:
raise util.Abort(_('no diffs found'))
+ if msgs:
+ repo.opener('last-message.txt', 'wb').write('\n* * *\n'.join(msgs))
finally:
release(lock, wlock)
@@ -2394,6 +2497,13 @@
if opts.get('bundle') and opts.get('subrepos'):
raise util.Abort(_('cannot combine --bundle and --subrepos'))
+ if opts.get('bookmarks'):
+ source, branches = hg.parseurl(ui.expandpath(source),
+ opts.get('branch'))
+ other = hg.repository(hg.remoteui(repo, opts), source)
+ ui.status(_('comparing with %s\n') % url.hidepassword(source))
+ return bookmarks.diff(ui, repo, other)
+
ret = hg.incoming(ui, repo, source, opts)
return ret
@@ -2433,7 +2543,7 @@
Returns 0 if a match is found, 1 otherwise.
"""
end = opts.get('print0') and '\0' or '\n'
- rev = opts.get('rev') or None
+ rev = cmdutil.revsingle(repo, opts.get('rev'), None).node()
ret = 1
m = cmdutil.match(repo, pats, opts, default='relglob')
@@ -2568,7 +2678,7 @@
node = rev
decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
- ctx = repo[node]
+ ctx = cmdutil.revsingle(repo, node)
for f in ctx:
if ui.debugflag:
ui.write("%40s " % hex(ctx.manifest()[f]))
@@ -2611,7 +2721,7 @@
node = opts.get('rev')
if not node:
- branch = repo.changectx(None).branch()
+ branch = repo[None].branch()
bheads = repo.branchheads(branch)
if len(bheads) > 2:
raise util.Abort(_(
@@ -2637,6 +2747,8 @@
raise util.Abort(_('working dir not at a head rev - '
'use "hg update" or merge with an explicit rev'))
node = parent == bheads[0] and bheads[-1] or bheads[0]
+ else:
+ node = cmdutil.revsingle(repo, node).node()
if opts.get('preview'):
# find nodes that are ancestors of p2 but not of p1
@@ -2668,6 +2780,14 @@
Returns 0 if there are outgoing changes, 1 otherwise.
"""
+
+ if opts.get('bookmarks'):
+ dest = ui.expandpath(dest or 'default-push', dest or 'default')
+ dest, branches = hg.parseurl(dest, opts.get('branch'))
+ other = hg.repository(hg.remoteui(repo, opts), dest)
+ ui.status(_('comparing with %s\n') % url.hidepassword(dest))
+ return bookmarks.diff(ui, other, repo)
+
ret = hg.outgoing(ui, repo, dest, opts)
return ret
@@ -2682,11 +2802,8 @@
Returns 0 on success.
"""
- rev = opts.get('rev')
- if rev:
- ctx = repo[rev]
- else:
- ctx = repo[None]
+
+ ctx = cmdutil.revsingle(repo, opts.get('rev'), None)
if file_:
m = cmdutil.match(repo, (file_,), opts)
@@ -2787,6 +2904,16 @@
other = hg.repository(hg.remoteui(repo, opts), source)
ui.status(_('pulling from %s\n') % url.hidepassword(source))
revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
+
+ if opts.get('bookmark'):
+ if not revs:
+ revs = []
+ rb = other.listkeys('bookmarks')
+ for b in opts['bookmark']:
+ if b not in rb:
+ raise util.Abort(_('remote bookmark %s not found!') % b)
+ revs.append(rb[b])
+
if revs:
try:
revs = [other.lookup(rev) for rev in revs]
@@ -2800,10 +2927,21 @@
checkout = str(repo.changelog.rev(other.lookup(checkout)))
repo._subtoppath = source
try:
- return postincoming(ui, repo, modheads, opts.get('update'), checkout)
+ ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
+
finally:
del repo._subtoppath
+ # update specified bookmarks
+ if opts.get('bookmark'):
+ for b in opts['bookmark']:
+ # explicit pull overrides local bookmark if any
+ ui.status(_("importing bookmark %s\n") % b)
+ repo._bookmarks[b] = repo[rb[b]].node()
+ bookmarks.write(repo)
+
+ return ret
+
def push(ui, repo, dest=None, **opts):
"""push changes to the specified destination
@@ -2833,6 +2971,17 @@
Returns 0 if push was successful, 1 if nothing to push.
"""
+
+ if opts.get('bookmark'):
+ for b in opts['bookmark']:
+ # translate -B options to -r so changesets get pushed
+ if b in repo._bookmarks:
+ opts.setdefault('rev', []).append(b)
+ else:
+ # if we try to push a deleted bookmark, translate it to null
+ # this lets simultaneous -r, -b options continue working
+ opts.setdefault('rev', []).append("null")
+
dest = ui.expandpath(dest or 'default-push', dest or 'default')
dest, branches = hg.parseurl(dest, opts.get('branch'))
revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
@@ -2851,9 +3000,33 @@
return False
finally:
del repo._subtoppath
- r = repo.push(other, opts.get('force'), revs=revs,
- newbranch=opts.get('new_branch'))
- return r == 0
+ result = repo.push(other, opts.get('force'), revs=revs,
+ newbranch=opts.get('new_branch'))
+
+ result = (result == 0)
+
+ if opts.get('bookmark'):
+ rb = other.listkeys('bookmarks')
+ for b in opts['bookmark']:
+ # explicit push overrides remote bookmark if any
+ if b in repo._bookmarks:
+ ui.status(_("exporting bookmark %s\n") % b)
+ new = repo[b].hex()
+ elif b in rb:
+ ui.status(_("deleting remote bookmark %s\n") % b)
+ new = '' # delete
+ else:
+ ui.warn(_('bookmark %s does not exist on the local '
+ 'or remote repository!\n') % b)
+ return 2
+ old = rb.get(b, '')
+ r = other.pushkey('bookmarks', b, old, new)
+ if not r:
+ ui.warn(_('updating bookmark %s failed!\n') % b)
+ if not result:
+ result = 2
+
+ return result
def recover(ui, repo):
"""roll back an interrupted transaction
@@ -3094,15 +3267,16 @@
raise util.Abort(_("you can't specify a revision and a date"))
opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
+ parent, p2 = repo.dirstate.parents()
+ if not opts.get('rev') and p2 != nullid:
+ raise util.Abort(_('uncommitted merge - '
+ 'use "hg update", see "hg help revert"'))
+
if not pats and not opts.get('all'):
raise util.Abort(_('no files or directories specified; '
'use --all to revert the whole repo'))
- parent, p2 = repo.dirstate.parents()
- if not opts.get('rev') and p2 != nullid:
- raise util.Abort(_('uncommitted merge - please provide a '
- 'specific revision'))
- ctx = repo[opts.get('rev')]
+ ctx = cmdutil.revsingle(repo, opts.get('rev'))
node = ctx.node()
mf = ctx.manifest()
if node == parent:
@@ -3241,7 +3415,7 @@
continue
audit_path(f)
try:
- util.unlink(repo.wjoin(f))
+ util.unlinkpath(repo.wjoin(f))
except OSError:
pass
repo.dirstate.remove(f)
@@ -3722,7 +3896,7 @@
bheads = repo.branchheads()
if not opts.get('force') and bheads and p1 not in bheads:
raise util.Abort(_('not at a branch head (use -f to force)'))
- r = repo[rev_].node()
+ r = cmdutil.revsingle(repo, rev_).node()
if not message:
# we don't translate commit messages
@@ -3856,6 +4030,8 @@
if not rev:
rev = node
+ # if we defined a bookmark, we have to remember the original bookmark name
+ brev = rev
rev = cmdutil.revsingle(repo, rev, rev).rev()
if check and clean:
@@ -3873,9 +4049,14 @@
rev = cmdutil.finddate(ui, repo, date)
if clean or check:
- return hg.clean(repo, rev)
+ ret = hg.clean(repo, rev)
else:
- return hg.update(repo, rev)
+ ret = hg.update(repo, rev)
+
+ if brev in repo._bookmarks:
+ bookmarks.setcurrent(repo, brev)
+
+ return ret
def verify(ui, repo):
"""verify the integrity of the repository
@@ -4066,6 +4247,13 @@
_('use command to check changeset state'), _('CMD')),
('U', 'noupdate', False, _('do not update to target'))],
_("[-gbsr] [-U] [-c CMD] [REV]")),
+ "bookmarks":
+ (bookmark,
+ [('f', 'force', False, _('force')),
+ ('r', 'rev', '', _('revision'), _('REV')),
+ ('d', 'delete', False, _('delete a given bookmark')),
+ ('m', 'rename', '', _('rename a given bookmark'), _('NAME'))],
+ _('hg bookmarks [-f] [-d] [-m NAME] [-r REV] [NAME]')),
"branch":
(branch,
[('f', 'force', None,
@@ -4165,6 +4353,7 @@
_('[-e] DATE [RANGE]')),
"debugdata": (debugdata, [], _('FILE REV')),
"debugfsinfo": (debugfsinfo, [], _('[PATH]')),
+ "debugignore": (debugignore, [], ''),
"debugindex": (debugindex,
[('f', 'format', 0, _('revlog format'), _('FORMAT'))],
_('FILE')),
@@ -4282,6 +4471,7 @@
_('file to store the bundles into'), _('FILE')),
('r', 'rev', [],
_('a remote changeset intended to be added'), _('REV')),
+ ('B', 'bookmarks', False, _("compare bookmarks")),
('b', 'branch', [],
_('a specific branch you would like to pull'), _('BRANCH')),
] + logopts + remoteopts + subrepoopts,
@@ -4350,6 +4540,7 @@
_('a changeset intended to be included in the destination'),
_('REV')),
('n', 'newest-first', None, _('show newest record first')),
+ ('B', 'bookmarks', False, _("compare bookmarks")),
('b', 'branch', [],
_('a specific branch you would like to push'), _('BRANCH')),
] + logopts + remoteopts + subrepoopts,
@@ -4369,6 +4560,7 @@
_('run even when remote repository is unrelated')),
('r', 'rev', [],
_('a remote changeset intended to be added'), _('REV')),
+ ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
('b', 'branch', [],
_('a specific branch you would like to pull'), _('BRANCH')),
] + remoteopts,
@@ -4379,6 +4571,7 @@
('r', 'rev', [],
_('a changeset intended to be included in the destination'),
_('REV')),
+ ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
('b', 'branch', [],
_('a specific branch you would like to push'), _('BRANCH')),
('', 'new-branch', False, _('allow pushing a new branch')),
--- a/mercurial/config.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/config.py Wed Feb 16 14:13:22 2011 -0600
@@ -130,7 +130,7 @@
name = m.group(1)
if sections and section not in sections:
continue
- if self.get(section, name) != None:
+ if self.get(section, name) is not None:
del self._data[section][name]
continue
--- a/mercurial/context.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/context.py Wed Feb 16 14:13:22 2011 -0600
@@ -7,7 +7,7 @@
from node import nullid, nullrev, short, hex
from i18n import _
-import ancestor, bdiff, error, util, subrepo, patch
+import ancestor, bdiff, error, util, subrepo, patch, encoding
import os, errno, stat
propertycache = util.propertycache
@@ -109,11 +109,13 @@
def description(self):
return self._changeset[4]
def branch(self):
- return self._changeset[5].get("branch")
+ return encoding.tolocal(self._changeset[5].get("branch"))
def extra(self):
return self._changeset[5]
def tags(self):
return self._repo.nodetags(self._node)
+ def bookmarks(self):
+ return self._repo.nodebookmarks(self._node)
def parents(self):
"""return contexts for each parent changeset"""
@@ -179,7 +181,7 @@
"""
# deal with workingctxs
n2 = c2._node
- if n2 == None:
+ if n2 is None:
n2 = c2._parents[0]._node
n = self._repo.changelog.ancestor(self._node, n2)
return changectx(self._repo, n)
@@ -591,9 +593,8 @@
if extra:
self._extra = extra.copy()
if 'branch' not in self._extra:
- branch = self._repo.dirstate.branch()
try:
- branch = branch.decode('UTF-8').encode('UTF-8')
+ branch = encoding.fromlocal(self._repo.dirstate.branch())
except UnicodeDecodeError:
raise util.Abort(_('branch name not in UTF-8!'))
self._extra['branch'] = branch
@@ -603,6 +604,9 @@
def __str__(self):
return str(self._parents[0]) + "+"
+ def __repr__(self):
+ return "<workingctx %s>" % str(self)
+
def __nonzero__(self):
return True
@@ -712,13 +716,14 @@
assert self._clean is not None # must call status first
return self._clean
def branch(self):
- return self._extra['branch']
+ return encoding.tolocal(self._extra['branch'])
def extra(self):
return self._extra
def tags(self):
t = []
- [t.extend(p.tags()) for p in self.parents()]
+ for p in self.parents():
+ t.extend(p.tags())
return t
def children(self):
@@ -827,7 +832,7 @@
if unlink:
for f in list:
try:
- util.unlink(self._repo.wjoin(f))
+ util.unlinkpath(self._repo.wjoin(f))
except OSError, inst:
if inst.errno != errno.ENOENT:
raise
@@ -902,6 +907,9 @@
def __str__(self):
return "%s@%s" % (self.path(), self._changectx)
+ def __repr__(self):
+ return "<workingfilectx %s>" % str(self)
+
def data(self):
return self._repo.wread(self._path)
def renamed(self):
@@ -1042,7 +1050,7 @@
def clean(self):
return self._status[6]
def branch(self):
- return self._extra['branch']
+ return encoding.tolocal(self._extra['branch'])
def extra(self):
return self._extra
def flags(self, f):
--- a/mercurial/demandimport.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/demandimport.py Wed Feb 16 14:13:22 2011 -0600
@@ -78,10 +78,10 @@
self._load()
setattr(self._module, attr, val)
-def _demandimport(name, globals=None, locals=None, fromlist=None, level=None):
+def _demandimport(name, globals=None, locals=None, fromlist=None, level=-1):
if not locals or name in ignore or fromlist == ('*',):
# these cases we can't really delay
- if level is None:
+ if level == -1:
return _origimport(name, globals, locals, fromlist)
else:
return _origimport(name, globals, locals, fromlist, level)
@@ -91,7 +91,10 @@
base, rest = name.split('.', 1)
# email.__init__ loading email.mime
if globals and globals.get('__name__', None) == base:
- return _origimport(name, globals, locals, fromlist)
+ if level != -1:
+ return _origimport(name, globals, locals, fromlist, level)
+ else:
+ return _origimport(name, globals, locals, fromlist)
# if a is already demand-loaded, add b to its submodule list
if base in locals:
if isinstance(locals[base], _demandmod):
@@ -99,7 +102,7 @@
return locals[base]
return _demandmod(name, globals, locals)
else:
- if level is not None:
+ if level != -1:
# from . import b,c,d or from .a import b,c,d
return _origimport(name, globals, locals, fromlist, level)
# from a import b,c,d
@@ -111,7 +114,7 @@
mod = getattr(mod, comp)
for x in fromlist:
# set requested submodules for demand load
- if not(hasattr(mod, x)):
+ if not hasattr(mod, x):
setattr(mod, x, _demandmod(x, mod.__dict__, locals))
return mod
--- a/mercurial/dirstate.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/dirstate.py Wed Feb 16 14:13:22 2011 -0600
@@ -7,7 +7,7 @@
from node import nullid
from i18n import _
-import util, ignore, osutil, parsers
+import util, ignore, osutil, parsers, encoding
import struct, os, stat, errno
import cStringIO
@@ -36,7 +36,7 @@
class dirstate(object):
- def __init__(self, opener, ui, root):
+ def __init__(self, opener, ui, root, validate):
'''Create a new dirstate object.
opener is an open()-like callable that can be used to open the
@@ -44,6 +44,7 @@
the dirstate.
'''
self._opener = opener
+ self._validate = validate
self._root = root
self._rootdir = os.path.join(root, '')
self._dirty = False
@@ -79,7 +80,9 @@
@propertycache
def _pl(self):
try:
- st = self._opener("dirstate").read(40)
+ fp = self._opener("dirstate")
+ st = fp.read(40)
+ fp.close()
l = len(st)
if l == 40:
return st[:20], st[20:40]
@@ -197,10 +200,10 @@
yield x
def parents(self):
- return self._pl
+ return [self._validate(p) for p in self._pl]
def branch(self):
- return self._branch
+ return encoding.tolocal(self._branch)
def setparents(self, p1, p2=nullid):
self._dirty = self._dirtypl = True
@@ -209,8 +212,8 @@
def setbranch(self, branch):
if branch in ['tip', '.', 'null']:
raise util.Abort(_('the name \'%s\' is reserved') % branch)
- self._branch = branch
- self._opener("branch", "w").write(branch + '\n')
+ self._branch = encoding.fromlocal(branch)
+ self._opener("branch", "w").write(self._branch + '\n')
def _read(self):
self._map = {}
@@ -229,7 +232,8 @@
self._pl = p
def invalidate(self):
- for a in "_map _copymap _foldmap _branch _pl _dirs _ignore".split():
+ for a in ("_map", "_copymap", "_foldmap", "_branch", "_pl", "_dirs",
+ "_ignore"):
if a in self.__dict__:
delattr(self, a)
self._dirty = False
--- a/mercurial/discovery.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/discovery.py Wed Feb 16 14:13:22 2011 -0600
@@ -220,8 +220,6 @@
# - a local outgoing head descended from update
# - a remote head that's known locally and not
# ancestral to an outgoing head
- #
- # New named branches cannot be created without --force.
# 1. Create set of branches involved in the push.
branches = set(repo[n].branch() for n in outg)
@@ -280,20 +278,30 @@
# 5. Check for new heads.
# If there are more heads after the push than before, a suitable
- # warning, depending on unsynced status, is displayed.
+ # error message, depending on unsynced status, is displayed.
+ error = None
for branch in branches:
- if len(newmap[branch]) > len(oldmap[branch]):
+ newhs = set(newmap[branch])
+ oldhs = set(oldmap[branch])
+ if len(newhs) > len(oldhs):
+ if error is None:
+ if branch:
+ error = _("push creates new remote heads "
+ "on branch '%s'!") % branch
+ else:
+ error = _("push creates new remote heads!")
+ if branch in unsynced:
+ hint = _("you should pull and merge or "
+ "use push -f to force")
+ else:
+ hint = _("did you forget to merge? "
+ "use push -f to force")
if branch:
- msg = _("push creates new remote heads "
- "on branch '%s'!") % branch
- else:
- msg = _("push creates new remote heads!")
-
- if branch in unsynced:
- hint = _("you should pull and merge or use push -f to force")
- else:
- hint = _("did you forget to merge? use push -f to force")
- raise util.Abort(msg, hint=hint)
+ repo.ui.debug("new remote heads on branch '%s'\n" % branch)
+ for h in (newhs - oldhs):
+ repo.ui.debug("new remote head %s\n" % short(h))
+ if error:
+ raise util.Abort(error, hint=hint)
# 6. Check for unsynced changes on involved branches.
if unsynced:
--- a/mercurial/dispatch.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/dispatch.py Wed Feb 16 14:13:22 2011 -0600
@@ -221,15 +221,20 @@
def fn(ui, *args):
env = {'HG_ARGS': ' '.join((self.name,) + args)}
def _checkvar(m):
- if int(m.groups()[0]) <= len(args):
+ if m.groups()[0] == '$':
+ return m.group()
+ elif int(m.groups()[0]) <= len(args):
return m.group()
else:
+ ui.debug(_("No argument found for substitution"
+ "of %i variable in alias '%s' definition.")
+ % (int(m.groups()[0]), self.name))
return ''
- cmd = re.sub(r'\$(\d+)', _checkvar, self.definition[1:])
+ cmd = re.sub(r'\$(\d+|\$)', _checkvar, self.definition[1:])
replace = dict((str(i + 1), arg) for i, arg in enumerate(args))
replace['0'] = self.name
replace['@'] = ' '.join(args)
- cmd = util.interpolate(r'\$', replace, cmd)
+ cmd = util.interpolate(r'\$', replace, cmd, escape_prefix=True)
return util.system(cmd, environ=env)
self.fn = fn
return
@@ -290,7 +295,7 @@
ui.debug("alias '%s' shadows command '%s'\n" %
(self.name, self.cmdname))
- if self.definition.startswith('!'):
+ if hasattr(self, 'shell'):
return self.fn(ui, *args, **opts)
else:
try:
@@ -589,8 +594,12 @@
msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
ui.log("command", msg + "\n")
d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
- return runcommand(lui, repo, cmd, fullargs, ui, options, d,
- cmdpats, cmdoptions)
+ try:
+ return runcommand(lui, repo, cmd, fullargs, ui, options, d,
+ cmdpats, cmdoptions)
+ finally:
+ if repo:
+ repo.close()
def _runcommand(ui, options, cmd, cmdfunc):
def checkargs():
--- a/mercurial/encoding.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/encoding.py Wed Feb 16 14:13:22 2011 -0600
@@ -48,6 +48,16 @@
encodingmode = os.environ.get("HGENCODINGMODE", "strict")
fallbackencoding = 'ISO-8859-1'
+class localstr(str):
+ '''This class allows strings that are unmodified to be
+ round-tripped to the local encoding and back'''
+ def __new__(cls, u, l):
+ s = str.__new__(cls, l)
+ s._utf8 = u
+ return s
+ def __hash__(self):
+ return hash(self._utf8) # avoid collisions in local string space
+
def tolocal(s):
"""
Convert a string from internal UTF-8 to local encoding
@@ -57,17 +67,45 @@
other character sets. We attempt to decode everything strictly
using UTF-8, then Latin-1, and failing that, we use UTF-8 and
replace unknown characters.
+
+ The localstr class is used to cache the known UTF-8 encoding of
+ strings next to their local representation to allow lossless
+ round-trip conversion back to UTF-8.
+
+ >>> u = 'foo: \\xc3\\xa4' # utf-8
+ >>> l = tolocal(u)
+ >>> l
+ 'foo: ?'
+ >>> fromlocal(l)
+ 'foo: \\xc3\\xa4'
+ >>> u2 = 'foo: \\xc3\\xa1'
+ >>> d = { l: 1, tolocal(u2): 2 }
+ >>> d # no collision
+ {'foo: ?': 1, 'foo: ?': 2}
+ >>> 'foo: ?' in d
+ False
+ >>> l1 = 'foo: \\xe4' # historical latin1 fallback
+ >>> l = tolocal(l1)
+ >>> l
+ 'foo: ?'
+ >>> fromlocal(l) # magically in utf-8
+ 'foo: \\xc3\\xa4'
"""
+
for e in ('UTF-8', fallbackencoding):
try:
u = s.decode(e) # attempt strict decoding
- return u.encode(encoding, "replace")
+ if e == 'UTF-8':
+ return localstr(s, u.encode(encoding, "replace"))
+ else:
+ return localstr(u.encode('UTF-8'),
+ u.encode(encoding, "replace"))
except LookupError, k:
raise error.Abort("%s, please check your locale settings" % k)
except UnicodeDecodeError:
pass
u = s.decode("utf-8", "replace") # last ditch
- return u.encode(encoding, "replace")
+ return u.encode(encoding, "replace") # can't round-trip
def fromlocal(s):
"""
@@ -79,6 +117,11 @@
'replace', which replaces unknown characters with a special
Unicode character, and 'ignore', which drops the character.
"""
+
+ # can we do a lossless round-trip?
+ if isinstance(s, localstr):
+ return s._utf8
+
try:
return s.decode(encoding, encodingmode).encode("utf-8")
except UnicodeDecodeError, inst:
--- a/mercurial/extensions.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/extensions.py Wed Feb 16 14:13:22 2011 -0600
@@ -11,6 +11,7 @@
_extensions = {}
_order = []
+_ignore = ['hbisect', 'bookmarks']
def extensions():
for name in _order:
@@ -45,6 +46,8 @@
shortname = name[6:]
else:
shortname = name
+ if shortname in _ignore:
+ return None
if shortname in _extensions:
return _extensions[shortname]
_extensions[shortname] = None
@@ -248,7 +251,7 @@
if name in paths:
return _disabledhelp(paths[name])
-def disabledcmd(cmd, strict=False):
+def disabledcmd(ui, cmd, strict=False):
'''import disabled extensions until cmd is found.
returns (cmdname, extname, doc)'''
@@ -266,6 +269,10 @@
getattr(mod, 'cmdtable', {}), strict)
except (error.AmbiguousCommand, error.UnknownCommand):
return
+ except Exception:
+ ui.warn(_('warning: error finding commands in %s\n') % path)
+ ui.traceback()
+ return
for c in aliases:
if c.startswith(cmd):
cmd = c
--- a/mercurial/filelog.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/filelog.py Wed Feb 16 14:13:22 2011 -0600
@@ -7,6 +7,17 @@
import revlog
+def _parsemeta(text):
+ if not text.startswith('\1\n'):
+ return {}
+ s = text.index('\1\n', 2)
+ mt = text[2:s]
+ m = {}
+ for l in mt.splitlines():
+ k, v = l.split(": ", 1)
+ m[k] = v
+ return m
+
class filelog(revlog.revlog):
def __init__(self, opener, path):
revlog.revlog.__init__(self, opener,
@@ -19,18 +30,6 @@
s = t.index('\1\n', 2)
return t[s + 2:]
- def _readmeta(self, node):
- t = self.revision(node)
- if not t.startswith('\1\n'):
- return {}
- s = t.index('\1\n', 2)
- mt = t[2:s]
- m = {}
- for l in mt.splitlines():
- k, v = l.split(": ", 1)
- m[k] = v
- return m
-
def add(self, text, meta, transaction, link, p1=None, p2=None):
if meta or text.startswith('\1\n'):
mt = ["%s: %s\n" % (k, v) for k, v in sorted(meta.iteritems())]
@@ -40,7 +39,8 @@
def renamed(self, node):
if self.parents(node)[0] != revlog.nullid:
return False
- m = self._readmeta(node)
+ t = self.revision(node)
+ m = _parsemeta(t)
if m and "copy" in m:
return (m["copy"], revlog.bin(m["copyrev"]))
return False
--- a/mercurial/help/patterns.txt Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/help/patterns.txt Wed Feb 16 14:13:22 2011 -0600
@@ -20,6 +20,11 @@
To use a Perl/Python regular expression, start a name with ``re:``.
Regexp pattern matching is anchored at the root of the repository.
+To read name patterns from a file, use ``listfile:`` or ``listfile0:``.
+The latter expects null delimited patterns while the former expects line
+feeds. Each string read from the file is itself treated as a file
+pattern.
+
Plain examples::
path:foo/bar a name bar in a directory named foo in the root
@@ -39,3 +44,8 @@
Regexp examples::
re:.*\.c$ any name ending in ".c", anywhere in the repository
+
+File examples::
+
+ listfile:list.txt read list from list.txt with one file pattern per line
+ listfile0:list.txt read list from list.txt with null byte delimiters
--- a/mercurial/help/subrepos.txt Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/help/subrepos.txt Wed Feb 16 14:13:22 2011 -0600
@@ -78,7 +78,10 @@
:commit: commit creates a consistent snapshot of the state of the
entire project and its subrepositories. It does this by first
attempting to commit all modified subrepositories, then recording
- their state and finally committing it in the parent repository.
+ their state and finally committing it in the parent
+ repository. Mercurial can be made to abort if any subrepository
+ content is modified by setting "ui.commitsubrepos=no" in a
+ configuration file (see :hg:`help config`).
:diff: diff does not recurse in subrepos unless -S/--subrepos is
specified. Changes are displayed as usual, on the subrepositories
--- a/mercurial/help/urls.txt Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/help/urls.txt Wed Feb 16 14:13:22 2011 -0600
@@ -4,7 +4,7 @@
file://local/filesystem/path[#revision]
http://[user[:pass]@]host[:port]/[path][#revision]
https://[user[:pass]@]host[:port]/[path][#revision]
- ssh://[user[:pass]@]host[:port]/[path][#revision]
+ ssh://[user@]host[:port]/[path][#revision]
Paths in the local filesystem can either point to Mercurial
repositories or to bundle files (as created by :hg:`bundle` or :hg:`
--- a/mercurial/hg.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/hg.py Wed Feb 16 14:13:22 2011 -0600
@@ -32,24 +32,22 @@
return revs, revs[0]
branchmap = repo.branchmap()
- def primary(butf8):
- if butf8 == '.':
+ def primary(branch):
+ if branch == '.':
if not lrepo or not lrepo.local():
raise util.Abort(_("dirstate branch not accessible"))
- butf8 = lrepo.dirstate.branch()
- if butf8 in branchmap:
- revs.extend(node.hex(r) for r in reversed(branchmap[butf8]))
+ branch = lrepo.dirstate.branch()
+ if branch in branchmap:
+ revs.extend(node.hex(r) for r in reversed(branchmap[branch]))
return True
else:
return False
for branch in branches:
- butf8 = encoding.fromlocal(branch)
- if not primary(butf8):
+ if not primary(branch):
raise error.RepoLookupError(_("unknown branch '%s'") % branch)
if hashbranch:
- butf8 = encoding.fromlocal(hashbranch)
- if not primary(butf8):
+ if not primary(hashbranch):
revs.append(hashbranch)
return revs, revs[0]
@@ -365,8 +363,7 @@
except error.RepoLookupError:
continue
bn = dest_repo[uprev].branch()
- dest_repo.ui.status(_("updating to branch %s\n")
- % encoding.tolocal(bn))
+ dest_repo.ui.status(_("updating to branch %s\n") % bn)
_update(dest_repo, uprev)
return src_repo, dest_repo
@@ -398,7 +395,8 @@
return stats[3] > 0
def merge(repo, node, force=None, remind=True):
- """branch merge with node, resolving changes"""
+ """Branch merge with node, resolving changes. Return true if any
+ unresolved conflicts."""
stats = mergemod.update(repo, node, True, force, False)
_showstats(repo, stats)
if stats[3]:
--- a/mercurial/hgweb/common.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/hgweb/common.py Wed Feb 16 14:13:22 2011 -0600
@@ -119,7 +119,10 @@
os.stat(path)
ct = mimetypes.guess_type(path)[0] or "text/plain"
req.respond(HTTP_OK, ct, length = os.path.getsize(path))
- return open(path, 'rb').read()
+ fp = open(path, 'rb')
+ data = fp.read()
+ fp.close()
+ return data
except TypeError:
raise ErrorResponse(HTTP_SERVER_ERROR, 'illegal filename')
except OSError, err:
--- a/mercurial/hgweb/hgwebdir_mod.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/hgweb/hgwebdir_mod.py Wed Feb 16 14:13:22 2011 -0600
@@ -33,14 +33,23 @@
repos.append((prefix, root))
continue
roothead = os.path.normpath(os.path.abspath(roothead))
- for path in util.walkrepos(roothead, followsym=True, recurse=recurse):
- path = os.path.normpath(path)
- name = util.pconvert(path[len(roothead):]).strip('/')
- if prefix:
- name = prefix + '/' + name
- repos.append((name, path))
+ paths = util.walkrepos(roothead, followsym=True, recurse=recurse)
+ repos.extend(urlrepos(prefix, roothead, paths))
return repos
+def urlrepos(prefix, roothead, paths):
+ """yield url paths and filesystem paths from a list of repo paths
+
+ >>> list(urlrepos('hg', '/opt', ['/opt/r', '/opt/r/r', '/opt']))
+ [('hg/r', '/opt/r'), ('hg/r/r', '/opt/r/r'), ('hg', '/opt')]
+ >>> list(urlrepos('', '/opt', ['/opt/r', '/opt/r/r', '/opt']))
+ [('r', '/opt/r'), ('r/r', '/opt/r/r'), ('', '/opt')]
+ """
+ for path in paths:
+ path = os.path.normpath(path)
+ yield (prefix + '/' +
+ util.pconvert(path[len(roothead):]).lstrip('/')).strip('/'), path
+
class hgwebdir(object):
refreshinterval = 20
--- a/mercurial/hgweb/webcommands.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/hgweb/webcommands.py Wed Feb 16 14:13:22 2011 -0600
@@ -550,7 +550,8 @@
"targetline": targetline,
"line": l,
"lineid": "l%d" % (lineno + 1),
- "linenumber": "% 6d" % (lineno + 1)}
+ "linenumber": "% 6d" % (lineno + 1),
+ "revdate": f.date()}
return tmpl("fileannotate",
file=f,
--- a/mercurial/hook.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/hook.py Wed Feb 16 14:13:22 2011 -0600
@@ -92,6 +92,12 @@
for k, v in args.iteritems():
if hasattr(v, '__call__'):
v = v()
+ if isinstance(v, dict):
+ # make the dictionary element order stable across Python
+ # implementations
+ v = ('{' +
+ ', '.join('%r: %r' % i for i in sorted(v.iteritems())) +
+ '}')
env['HG_' + k.upper()] = v
if repo:
--- a/mercurial/httprepo.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/httprepo.py Wed Feb 16 14:13:22 2011 -0600
@@ -160,7 +160,7 @@
break
tempname = changegroup.writebundle(cg, None, type)
- fp = url.httpsendfile(tempname, "rb")
+ fp = url.httpsendfile(self.ui, tempname, "rb")
headers = {'Content-Type': 'application/mercurial-0.1'}
try:
--- a/mercurial/ignore.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/ignore.py Wed Feb 16 14:13:22 2011 -0600
@@ -86,7 +86,8 @@
(f, inst.strerror))
allpats = []
- [allpats.extend(patlist) for patlist in pats.values()]
+ for patlist in pats.values():
+ allpats.extend(patlist)
if not allpats:
return util.never
--- a/mercurial/localrepo.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/localrepo.py Wed Feb 16 14:13:22 2011 -0600
@@ -8,7 +8,7 @@
from node import bin, hex, nullid, nullrev, short
from i18n import _
import repo, changegroup, subrepo, discovery, pushkey
-import changelog, dirstate, filelog, manifest, context
+import changelog, dirstate, filelog, manifest, context, bookmarks
import lock, transaction, store, encoding
import util, extensions, hook, error
import match as matchmod
@@ -105,7 +105,7 @@
self._tags = None
self._tagtypes = None
- self._branchcache = None # in UTF-8
+ self._branchcache = None
self._branchcachetip = None
self.nodetagscache = None
self.filterpats = {}
@@ -161,6 +161,13 @@
parts.pop()
return False
+ @util.propertycache
+ def _bookmarks(self):
+ return bookmarks.read(self)
+
+ @util.propertycache
+ def _bookmarkcurrent(self):
+ return bookmarks.readcurrent(self)
@propertycache
def changelog(self):
@@ -178,7 +185,19 @@
@propertycache
def dirstate(self):
- return dirstate.dirstate(self.opener, self.ui, self.root)
+ warned = [0]
+ def validate(node):
+ try:
+ r = self.changelog.rev(node)
+ return node
+ except error.LookupError:
+ if not warned[0]:
+ warned[0] = True
+ self.ui.warn(_("warning: ignoring unknown"
+ " working parent %s!\n") % short(node))
+ return nullid
+
+ return dirstate.dirstate(self.opener, self.ui, self.root, validate)
def __getitem__(self, changeid):
if changeid is None:
@@ -264,6 +283,8 @@
# committed tags are stored in UTF-8
writetags(fp, names, encoding.fromlocal, prevtags)
+ fp.close()
+
if '.hgtags' not in self.dirstate:
self[None].add(['.hgtags'])
@@ -379,6 +400,13 @@
tags.sort()
return self.nodetagscache.get(node, [])
+ def nodebookmarks(self, node):
+ marks = []
+ for bookmark, n in self._bookmarks.iteritems():
+ if n == node:
+ marks.append(bookmark)
+ return sorted(marks)
+
def _branchtags(self, partial, lrev):
# TODO: rename this function?
tiprev = len(self) - 1
@@ -424,11 +452,10 @@
bt[bn] = tip
return bt
-
def _readbranchcache(self):
partial = {}
try:
- f = self.opener("branchheads.cache")
+ f = self.opener("cache/branchheads")
lines = f.read().split('\n')
f.close()
except (IOError, OSError):
@@ -444,7 +471,8 @@
if not l:
continue
node, label = l.split(" ", 1)
- partial.setdefault(label.strip(), []).append(bin(node))
+ label = encoding.tolocal(label.strip())
+ partial.setdefault(label, []).append(bin(node))
except KeyboardInterrupt:
raise
except Exception, inst:
@@ -455,11 +483,11 @@
def _writebranchcache(self, branches, tip, tiprev):
try:
- f = self.opener("branchheads.cache", "w", atomictemp=True)
+ f = self.opener("cache/branchheads", "w", atomictemp=True)
f.write("%s %s\n" % (hex(tip), tiprev))
for label, nodes in branches.iteritems():
for node in nodes:
- f.write("%s %s\n" % (hex(node), label))
+ f.write("%s %s\n" % (hex(node), encoding.fromlocal(label)))
f.rename()
except (IOError, OSError):
pass
@@ -500,6 +528,8 @@
n = self.changelog._match(key)
if n:
return n
+ if key in self._bookmarks:
+ return self._bookmarks[key]
if key in self.tags():
return self.tags()[key]
if key in self.branchtags():
@@ -618,10 +648,6 @@
def wwrite(self, filename, data, flags):
data = self._filter(self._decodefilterpats, filename, data)
- try:
- os.unlink(self.wjoin(filename))
- except OSError:
- pass
if 'l' in flags:
self.wopener.symlink(data, filename)
else:
@@ -648,7 +674,8 @@
except IOError:
ds = ""
self.opener("journal.dirstate", "w").write(ds)
- self.opener("journal.branch", "w").write(self.dirstate.branch())
+ self.opener("journal.branch", "w").write(
+ encoding.fromlocal(self.dirstate.branch()))
self.opener("journal.desc", "w").write("%d\n%s\n" % (len(self), desc))
renames = [(self.sjoin("journal"), self.sjoin("undo")),
@@ -700,13 +727,16 @@
transaction.rollback(self.sopener, self.sjoin("undo"),
self.ui.warn)
util.rename(self.join("undo.dirstate"), self.join("dirstate"))
+ if os.path.exists(self.join('undo.bookmarks')):
+ util.rename(self.join('undo.bookmarks'),
+ self.join('bookmarks'))
try:
branch = self.opener("undo.branch").read()
self.dirstate.setbranch(branch)
except IOError:
self.ui.warn(_("Named branch could not be reset, "
"current branch still is: %s\n")
- % encoding.tolocal(self.dirstate.branch()))
+ % self.dirstate.branch())
self.invalidate()
self.dirstate.invalidate()
self.destroyed()
@@ -724,7 +754,7 @@
self._branchcachetip = None
def invalidate(self):
- for a in "changelog manifest".split():
+ for a in ("changelog", "manifest", "_bookmarks", "_bookmarkscurrent"):
if a in self.__dict__:
delattr(self, a)
self.invalidatecaches()
@@ -753,8 +783,8 @@
l.lock()
return l
- l = self._lock(self.sjoin("lock"), wait, None, self.invalidate,
- _('repository %s') % self.origroot)
+ l = self._lock(self.sjoin("lock"), wait, self.store.write,
+ self.invalidate, _('repository %s') % self.origroot)
self._lockref = weakref.ref(l)
return l
@@ -903,6 +933,12 @@
if '.hgsubstate' not in changes[0]:
changes[0].insert(0, '.hgsubstate')
+ if subs and not self.ui.configbool('ui', 'commitsubrepos', True):
+ changedsubs = [s for s in subs if wctx.sub(s).dirty(True)]
+ if changedsubs:
+ raise util.Abort(_("uncommitted changes in subrepo %s")
+ % changedsubs[0])
+
# make sure all explicit patterns are matched
if not force and match.files():
matched = set(changes[0] + changes[1] + changes[2])
@@ -968,7 +1004,11 @@
_('note: commit message saved in %s\n') % msgfn)
raise
- # update dirstate and mergestate
+ # update bookmarks, dirstate and mergestate
+ parents = (p1, p2)
+ if p2 == nullid:
+ parents = (p1,)
+ bookmarks.update(self, parents, ret)
for f in changes[0] + changes[1]:
self.dirstate.normal(f)
for f in changes[2]:
@@ -1202,14 +1242,14 @@
self.ui.status(_("skipping missing subrepository: %s\n")
% subpath)
- [l.sort() for l in r]
+ for l in r:
+ l.sort()
return r
def heads(self, start=None):
heads = self.changelog.heads(start)
# sort the output in rev descending order
- heads = [(-self.changelog.rev(h), h) for h in heads]
- return [n for (r, n) in sorted(heads)]
+ return sorted(heads, key=self.changelog.rev, reverse=True)
def branchheads(self, branch=None, start=None, closed=False):
'''return a (possibly filtered) list of heads for the given branch
@@ -1276,26 +1316,57 @@
common, fetch, rheads = tmp
if not fetch:
self.ui.status(_("no changes found\n"))
- return 0
-
- if heads is None and fetch == [nullid]:
- self.ui.status(_("requesting all changes\n"))
- elif heads is None and remote.capable('changegroupsubset'):
- # issue1320, avoid a race if remote changed after discovery
- heads = rheads
+ result = 0
+ else:
+ if heads is None and fetch == [nullid]:
+ self.ui.status(_("requesting all changes\n"))
+ elif heads is None and remote.capable('changegroupsubset'):
+ # issue1320, avoid a race if remote changed after discovery
+ heads = rheads
- if heads is None:
- cg = remote.changegroup(fetch, 'pull')
- else:
- if not remote.capable('changegroupsubset'):
+ if heads is None:
+ cg = remote.changegroup(fetch, 'pull')
+ elif not remote.capable('changegroupsubset'):
raise util.Abort(_("partial pull cannot be done because "
- "other repository doesn't support "
- "changegroupsubset."))
- cg = remote.changegroupsubset(fetch, heads, 'pull')
- return self.addchangegroup(cg, 'pull', remote.url(), lock=lock)
+ "other repository doesn't support "
+ "changegroupsubset."))
+ else:
+ cg = remote.changegroupsubset(fetch, heads, 'pull')
+ result = self.addchangegroup(cg, 'pull', remote.url(),
+ lock=lock)
finally:
lock.release()
+ self.ui.debug("checking for updated bookmarks\n")
+ rb = remote.listkeys('bookmarks')
+ changed = False
+ for k in rb.keys():
+ if k in self._bookmarks:
+ nr, nl = rb[k], self._bookmarks[k]
+ if nr in self:
+ cr = self[nr]
+ cl = self[nl]
+ if cl.rev() >= cr.rev():
+ continue
+ if cr in cl.descendants():
+ self._bookmarks[k] = cr.node()
+ changed = True
+ self.ui.status(_("updating bookmark %s\n") % k)
+ else:
+ self.ui.warn(_("not updating divergent"
+ " bookmark %s\n") % k)
+ if changed:
+ bookmarks.write(self)
+
+ return result
+
+ def checkpush(self, force, revs):
+ """Extensions can override this function if additional checks have
+ to be performed before pushing, or call it if they override push
+ command.
+ """
+ pass
+
def push(self, remote, force=False, revs=None, newbranch=False):
'''Push outgoing changesets (limited by revs) from the current
repository to remote. Return an integer:
@@ -1312,35 +1383,52 @@
# unbundle assumes local user cannot lock remote repo (new ssh
# servers, http servers).
+ self.checkpush(force, revs)
lock = None
unbundle = remote.capable('unbundle')
if not unbundle:
lock = remote.lock()
try:
- ret = discovery.prepush(self, remote, force, revs, newbranch)
- if ret[0] is None:
- # and here we return 0 for "nothing to push" or 1 for
- # "something to push but I refuse"
- return ret[1]
-
- cg, remote_heads = ret
- if unbundle:
- # local repo finds heads on server, finds out what revs it must
- # push. once revs transferred, if server finds it has
- # different heads (someone else won commit/push race), server
- # aborts.
- if force:
- remote_heads = ['force']
- # ssh: return remote's addchangegroup()
- # http: return remote's addchangegroup() or 0 for error
- return remote.unbundle(cg, remote_heads, 'push')
- else:
- # we return an integer indicating remote head count change
- return remote.addchangegroup(cg, 'push', self.url(), lock=lock)
+ cg, remote_heads = discovery.prepush(self, remote, force, revs,
+ newbranch)
+ ret = remote_heads
+ if cg is not None:
+ if unbundle:
+ # local repo finds heads on server, finds out what
+ # revs it must push. once revs transferred, if server
+ # finds it has different heads (someone else won
+ # commit/push race), server aborts.
+ if force:
+ remote_heads = ['force']
+ # ssh: return remote's addchangegroup()
+ # http: return remote's addchangegroup() or 0 for error
+ ret = remote.unbundle(cg, remote_heads, 'push')
+ else:
+ # we return an integer indicating remote head count change
+ ret = remote.addchangegroup(cg, 'push', self.url(),
+ lock=lock)
finally:
if lock is not None:
lock.release()
+ self.ui.debug("checking for updated bookmarks\n")
+ rb = remote.listkeys('bookmarks')
+ for k in rb.keys():
+ if k in self._bookmarks:
+ nr, nl = rb[k], hex(self._bookmarks[k])
+ if nr in self:
+ cr = self[nr]
+ cl = self[nl]
+ if cl in cr.descendants():
+ r = remote.pushkey('bookmarks', k, nr, nl)
+ if r:
+ self.ui.status(_("updating bookmark %s\n") % k)
+ else:
+ self.ui.warn(_('updating bookmark %s'
+ ' failed!\n') % k)
+
+ return ret
+
def changegroupinfo(self, nodes, source):
if self.ui.verbose or source == 'bundle':
self.ui.status(_("%d changesets found\n") % len(nodes))
@@ -1404,9 +1492,6 @@
# Nor do we know which filenodes are missing.
msng_filenode_set = {}
- junk = mnfst.index[len(mnfst) - 1] # Get around a bug in lazyindex
- junk = None
-
# A changeset always belongs to itself, so the changenode lookup
# function for a changenode is identity.
def identity(x):
@@ -1494,8 +1579,13 @@
group = cl.group(msng_cl_lst, identity, collect)
for cnt, chnk in enumerate(group):
yield chnk
- self.ui.progress(_('bundling changes'), cnt, unit=_('chunks'))
- self.ui.progress(_('bundling changes'), None)
+ # revlog.group yields three entries per node, so
+ # dividing by 3 gives an approximation of how many
+ # nodes have been processed.
+ self.ui.progress(_('bundling'), cnt / 3,
+ unit=_('changesets'))
+ changecount = cnt / 3
+ self.ui.progress(_('bundling'), None)
prune(mnfst, msng_mnfst_set)
add_extra_nodes(1, msng_mnfst_set)
@@ -1507,10 +1597,17 @@
group = mnfst.group(msng_mnfst_lst,
lambda mnode: msng_mnfst_set[mnode],
filenode_collector(changedfiles))
+ efiles = {}
for cnt, chnk in enumerate(group):
+ if cnt % 3 == 1:
+ mnode = chnk[:20]
+ efiles.update(mnfst.readdelta(mnode))
yield chnk
- self.ui.progress(_('bundling manifests'), cnt, unit=_('chunks'))
- self.ui.progress(_('bundling manifests'), None)
+ # see above comment for why we divide by 3
+ self.ui.progress(_('bundling'), cnt / 3,
+ unit=_('manifests'), total=changecount)
+ self.ui.progress(_('bundling'), None)
+ efiles = len(efiles)
# These are no longer needed, dereference and toss the memory for
# them.
@@ -1524,8 +1621,7 @@
msng_filenode_set.setdefault(fname, {})
changedfiles.add(fname)
# Go through all our files in order sorted by name.
- cnt = 0
- for fname in sorted(changedfiles):
+ for idx, fname in enumerate(sorted(changedfiles)):
filerevlog = self.file(fname)
if not len(filerevlog):
raise util.Abort(_("empty or missing revlog for %s") % fname)
@@ -1548,13 +1644,16 @@
group = filerevlog.group(nodeiter,
lambda fnode: missingfnodes[fnode])
for chnk in group:
+ # even though we print the same progress on
+ # most loop iterations, put the progress call
+ # here so that time estimates (if any) can be updated
self.ui.progress(
- _('bundling files'), cnt, item=fname, unit=_('chunks'))
- cnt += 1
+ _('bundling'), idx, item=fname,
+ unit=_('files'), total=efiles)
yield chnk
# Signal that no more groups are left.
yield changegroup.closechunk()
- self.ui.progress(_('bundling files'), None)
+ self.ui.progress(_('bundling'), None)
if msng_cl_lst:
self.hook('outgoing', node=hex(msng_cl_lst[0]), source=source)
@@ -1602,20 +1701,30 @@
collect = changegroup.collector(cl, mmfs, changedfiles)
for cnt, chnk in enumerate(cl.group(nodes, identity, collect)):
- self.ui.progress(_('bundling changes'), cnt, unit=_('chunks'))
+ # revlog.group yields three entries per node, so
+ # dividing by 3 gives an approximation of how many
+ # nodes have been processed.
+ self.ui.progress(_('bundling'), cnt / 3, unit=_('changesets'))
yield chnk
- self.ui.progress(_('bundling changes'), None)
+ changecount = cnt / 3
+ self.ui.progress(_('bundling'), None)
mnfst = self.manifest
nodeiter = gennodelst(mnfst)
+ efiles = {}
for cnt, chnk in enumerate(mnfst.group(nodeiter,
lookuplinkrev_func(mnfst))):
- self.ui.progress(_('bundling manifests'), cnt, unit=_('chunks'))
+ if cnt % 3 == 1:
+ mnode = chnk[:20]
+ efiles.update(mnfst.readdelta(mnode))
+ # see above comment for why we divide by 3
+ self.ui.progress(_('bundling'), cnt / 3,
+ unit=_('manifests'), total=changecount)
yield chnk
- self.ui.progress(_('bundling manifests'), None)
+ efiles = len(efiles)
+ self.ui.progress(_('bundling'), None)
- cnt = 0
- for fname in sorted(changedfiles):
+ for idx, fname in enumerate(sorted(changedfiles)):
filerevlog = self.file(fname)
if not len(filerevlog):
raise util.Abort(_("empty or missing revlog for %s") % fname)
@@ -1627,10 +1736,10 @@
lookup = lookuplinkrev_func(filerevlog)
for chnk in filerevlog.group(nodeiter, lookup):
self.ui.progress(
- _('bundling files'), cnt, item=fname, unit=_('chunks'))
- cnt += 1
+ _('bundling'), idx, item=fname,
+ total=efiles, unit=_('files'))
yield chnk
- self.ui.progress(_('bundling files'), None)
+ self.ui.progress(_('bundling'), None)
yield changegroup.closechunk()
@@ -1643,6 +1752,8 @@
"""Add the changegroup returned by source.read() to this repo.
srctype is a string like 'push', 'pull', or 'unbundle'. url is
the URL of the repo where this changegroup is coming from.
+ If lock is not None, the function takes ownership of the lock
+ and releases it after the changegroup is added.
Return an integer summarizing the change to this repo:
- nothing changed or no source: 0
@@ -1795,6 +1906,10 @@
self.hook("incoming", node=hex(cl.node(i)),
source=srctype, url=url)
+ # FIXME - why does this care about tip?
+ if newheads == oldheads:
+ bookmarks.update(self, self.dirstate.parents(), self['tip'].node())
+
# never return 0 here:
if newheads < oldheads:
return newheads - oldheads - 1
@@ -1803,59 +1918,63 @@
def stream_in(self, remote, requirements):
- fp = remote.stream_out()
- l = fp.readline()
+ lock = self.lock()
try:
- resp = int(l)
- except ValueError:
- raise error.ResponseError(
- _('Unexpected response from remote server:'), l)
- if resp == 1:
- raise util.Abort(_('operation forbidden by server'))
- elif resp == 2:
- raise util.Abort(_('locking the remote repository failed'))
- elif resp != 0:
- raise util.Abort(_('the server sent an unknown error code'))
- self.ui.status(_('streaming all changes\n'))
- l = fp.readline()
- try:
- total_files, total_bytes = map(int, l.split(' ', 1))
- except (ValueError, TypeError):
- raise error.ResponseError(
- _('Unexpected response from remote server:'), l)
- self.ui.status(_('%d files to transfer, %s of data\n') %
- (total_files, util.bytecount(total_bytes)))
- start = time.time()
- for i in xrange(total_files):
- # XXX doesn't support '\n' or '\r' in filenames
+ fp = remote.stream_out()
l = fp.readline()
try:
- name, size = l.split('\0', 1)
- size = int(size)
+ resp = int(l)
+ except ValueError:
+ raise error.ResponseError(
+ _('Unexpected response from remote server:'), l)
+ if resp == 1:
+ raise util.Abort(_('operation forbidden by server'))
+ elif resp == 2:
+ raise util.Abort(_('locking the remote repository failed'))
+ elif resp != 0:
+ raise util.Abort(_('the server sent an unknown error code'))
+ self.ui.status(_('streaming all changes\n'))
+ l = fp.readline()
+ try:
+ total_files, total_bytes = map(int, l.split(' ', 1))
except (ValueError, TypeError):
raise error.ResponseError(
_('Unexpected response from remote server:'), l)
- self.ui.debug('adding %s (%s)\n' % (name, util.bytecount(size)))
- # for backwards compat, name was partially encoded
- ofp = self.sopener(store.decodedir(name), 'w')
- for chunk in util.filechunkiter(fp, limit=size):
- ofp.write(chunk)
- ofp.close()
- elapsed = time.time() - start
- if elapsed <= 0:
- elapsed = 0.001
- self.ui.status(_('transferred %s in %.1f seconds (%s/sec)\n') %
- (util.bytecount(total_bytes), elapsed,
- util.bytecount(total_bytes / elapsed)))
+ self.ui.status(_('%d files to transfer, %s of data\n') %
+ (total_files, util.bytecount(total_bytes)))
+ start = time.time()
+ for i in xrange(total_files):
+ # XXX doesn't support '\n' or '\r' in filenames
+ l = fp.readline()
+ try:
+ name, size = l.split('\0', 1)
+ size = int(size)
+ except (ValueError, TypeError):
+ raise error.ResponseError(
+ _('Unexpected response from remote server:'), l)
+ self.ui.debug('adding %s (%s)\n' % (name, util.bytecount(size)))
+ # for backwards compat, name was partially encoded
+ ofp = self.sopener(store.decodedir(name), 'w')
+ for chunk in util.filechunkiter(fp, limit=size):
+ ofp.write(chunk)
+ ofp.close()
+ elapsed = time.time() - start
+ if elapsed <= 0:
+ elapsed = 0.001
+ self.ui.status(_('transferred %s in %.1f seconds (%s/sec)\n') %
+ (util.bytecount(total_bytes), elapsed,
+ util.bytecount(total_bytes / elapsed)))
- # new requirements = old non-format requirements + new format-related
- # requirements from the streamed-in repository
- requirements.update(set(self.requirements) - self.supportedformats)
- self._applyrequirements(requirements)
- self._writerequirements()
+ # new requirements = old non-format requirements + new format-related
+ # requirements from the streamed-in repository
+ requirements.update(set(self.requirements) - self.supportedformats)
+ self._applyrequirements(requirements)
+ self._writerequirements()
- self.invalidate()
- return len(self.heads()) + 1
+ self.invalidate()
+ return len(self.heads()) + 1
+ finally:
+ lock.release()
def clone(self, remote, heads=[], stream=False):
'''clone remote repository.
--- a/mercurial/lock.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/lock.py Wed Feb 16 14:13:22 2011 -0600
@@ -113,7 +113,7 @@
# held, or can race and break valid lock.
try:
l = lock(self.f + '.break', timeout=0)
- os.unlink(self.f)
+ util.unlink(self.f)
l.release()
except error.LockError:
return locker
@@ -126,7 +126,7 @@
if self.releasefn:
self.releasefn()
try:
- os.unlink(self.f)
+ util.unlink(self.f)
except OSError:
pass
--- a/mercurial/mail.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/mail.py Wed Feb 16 14:13:22 2011 -0600
@@ -33,7 +33,17 @@
def _smtp(ui):
'''build an smtp connection and return a function to send mail'''
local_hostname = ui.config('smtp', 'local_hostname')
- s = smtplib.SMTP(local_hostname=local_hostname)
+ tls = ui.config('smtp', 'tls', 'none')
+ # backward compatible: when tls = true, we use starttls.
+ starttls = tls == 'starttls' or util.parsebool(tls)
+ smtps = tls == 'smtps'
+ if (starttls or smtps) and not hasattr(socket, 'ssl'):
+ raise util.Abort(_("can't use TLS: Python SSL support not installed"))
+ if smtps:
+ ui.note(_('(using smtps)\n'))
+ s = smtplib.SMTP_SSL(local_hostname=local_hostname)
+ else:
+ s = smtplib.SMTP(local_hostname=local_hostname)
mailhost = ui.config('smtp', 'host')
if not mailhost:
raise util.Abort(_('smtp.host not configured - cannot send mail'))
@@ -41,11 +51,8 @@
ui.note(_('sending mail: smtp host %s, port %s\n') %
(mailhost, mailport))
s.connect(host=mailhost, port=mailport)
- if ui.configbool('smtp', 'tls'):
- if not hasattr(socket, 'ssl'):
- raise util.Abort(_("can't use TLS: Python SSL support "
- "not installed"))
- ui.note(_('(using tls)\n'))
+ if starttls:
+ ui.note(_('(using starttls)\n'))
s.ehlo()
s.starttls()
s.ehlo()
--- a/mercurial/manifest.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/manifest.py Wed Feb 16 14:13:22 2011 -0600
@@ -171,19 +171,19 @@
raise AssertionError(
_("failed to remove %s from manifest") % f)
l = ""
- if dstart != None and dstart <= start and dend >= start:
+ if dstart is not None and dstart <= start and dend >= start:
if dend < end:
dend = end
if l:
dline.append(l)
else:
- if dstart != None:
+ if dstart is not None:
delta.append([dstart, dend, "".join(dline)])
dstart = start
dend = end
dline = [l]
- if dstart != None:
+ if dstart is not None:
delta.append([dstart, dend, "".join(dline)])
# apply the delta to the addlist, and get a delta for addrevision
cachedelta = (self.rev(p1), addlistdelta(addlist, delta))
--- a/mercurial/match.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/match.py Wed Feb 16 14:13:22 2011 -0600
@@ -39,11 +39,11 @@
self._anypats = bool(include or exclude)
if include:
- im = _buildmatch(_normalize(include, 'glob', root, cwd, auditor),
- '(?:/|$)')
+ pats = _normalize(include, 'glob', root, cwd, auditor)
+ self.includepat, im = _buildmatch(pats, '(?:/|$)')
if exclude:
- em = _buildmatch(_normalize(exclude, 'glob', root, cwd, auditor),
- '(?:/|$)')
+ pats = _normalize(exclude, 'glob', root, cwd, auditor)
+ self.excludepat, em = _buildmatch(pats, '(?:/|$)')
if exact:
self._files = patterns
pm = self.exact
@@ -51,7 +51,7 @@
pats = _normalize(patterns, default, root, cwd, auditor)
self._files = _roots(pats)
self._anypats = self._anypats or _anypats(pats)
- pm = _buildmatch(pats, '$')
+ self.patternspat, pm = _buildmatch(pats, '$')
if patterns or exact:
if include:
@@ -161,7 +161,8 @@
actual pattern."""
if ':' in pat:
kind, val = pat.split(':', 1)
- if kind in ('re', 'glob', 'path', 'relglob', 'relpath', 'relre'):
+ if kind in ('re', 'glob', 'path', 'relglob', 'relpath', 'relre',
+ 'listfile', 'listfile0'):
return kind, val
return default, pat
@@ -245,7 +246,7 @@
pat = '(?:%s)' % '|'.join([_regex(k, p, tail) for (k, p) in pats])
if len(pat) > 20000:
raise OverflowError()
- return re.compile(pat).match
+ return pat, re.compile(pat).match
except OverflowError:
# We're using a Python with a tiny regex engine and we
# made it explode, so we'll divide the pattern list in two
@@ -253,8 +254,9 @@
l = len(pats)
if l < 2:
raise
- a, b = _buildmatch(pats[:l//2], tail), _buildmatch(pats[l//2:], tail)
- return lambda s: a(s) or b(s)
+ pata, a = _buildmatch(pats[:l//2], tail),
+ patb, b = _buildmatch(pats[l//2:], tail)
+ return pat, lambda s: a(s) or b(s)
except re.error:
for k, p in pats:
try:
@@ -270,6 +272,15 @@
name = util.canonpath(root, cwd, name, auditor)
elif kind in ('relglob', 'path'):
name = util.normpath(name)
+ elif kind in ('listfile', 'listfile0'):
+ delimiter = kind == 'listfile0' and '\0' or '\n'
+ try:
+ files = open(name, 'r').read().split(delimiter)
+ files = [f for f in files if f]
+ except EnvironmentError:
+ raise util.Abort(_("unable to read file list (%s)") % name)
+ pats += _normalize(files, default, root, cwd, auditor)
+ continue
pats.append((kind, name))
return pats
--- a/mercurial/merge.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/merge.py Wed Feb 16 14:13:22 2011 -0600
@@ -32,6 +32,7 @@
else:
bits = l[:-1].split("\0")
self._state[bits[0]] = bits[1:]
+ f.close()
except IOError, err:
if err.errno != errno.ENOENT:
raise
@@ -42,6 +43,7 @@
f.write(hex(self._local) + "\n")
for d, v in self._state.iteritems():
f.write("\0".join([d] + v) + "\n")
+ f.close()
self._dirty = False
def add(self, fcl, fco, fca, fd, flags):
hash = util.sha1(fcl.path()).hexdigest()
@@ -67,6 +69,7 @@
state, hash, lfile, afile, anode, ofile, flags = self._state[dfile]
f = self._repo.opener("merge/" + hash)
self._repo.wwrite(dfile, f.read(), flags)
+ f.close()
fcd = wctx[dfile]
fco = octx[ofile]
fca = self._repo.filectx(afile, fileid=anode)
@@ -255,6 +258,9 @@
wctx is the working copy context
mctx is the context to be merged into the working copy
actx is the context of the common ancestor
+
+ Return a tuple of counts (updated, merged, removed, unresolved) that
+ describes how many files were affected by the update.
"""
updated, merged, removed, unresolved = 0, 0, 0, 0
@@ -309,7 +315,7 @@
if f == '.hgsubstate': # subrepo states need updating
subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
try:
- util.unlink(repo.wjoin(f))
+ util.unlinkpath(repo.wjoin(f))
except OSError, inst:
if inst.errno != errno.ENOENT:
repo.ui.warn(_("update failed to remove %s: %s!\n") %
@@ -347,7 +353,7 @@
repo.ui.note(_("moving %s to %s\n") % (f, fd))
t = wctx.filectx(f).data()
repo.wwrite(fd, t, flags)
- util.unlink(repo.wjoin(f))
+ util.unlinkpath(repo.wjoin(f))
if f2:
repo.ui.note(_("getting %s to %s\n") % (f2, fd))
t = mctx.filectx(f2).data()
@@ -462,6 +468,8 @@
use 'hg update -C' to discard changes)
3 = abort: uncommitted local changes
4 = incompatible options (checked in commands.py)
+
+ Return the same tuple as applyupdates().
"""
onode = node
@@ -524,7 +532,7 @@
action += manifestmerge(repo, wc, p2, pa, overwrite, partial)
### apply phase
- if not branchmerge: # just jump to the new rev
+ if not branchmerge or fastforward: # just jump to the new rev
fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
if not partial:
repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
@@ -533,7 +541,7 @@
if not partial:
repo.dirstate.setparents(fp1, fp2)
- recordupdates(repo, action, branchmerge)
+ recordupdates(repo, action, branchmerge and not fastforward)
if not branchmerge and not fastforward:
repo.dirstate.setbranch(p2.branch())
finally:
--- a/mercurial/minirst.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/minirst.py Wed Feb 16 14:13:22 2011 -0600
@@ -14,27 +14,8 @@
are just indented blocks that look like they are nested. This relies
on the user to keep the right indentation for the blocks.
-It only supports a small subset of reStructuredText:
-
-- sections
-
-- paragraphs
-
-- literal blocks
-
-- definition lists
-
-- specific admonitions
-
-- bullet lists (items must start with '-')
-
-- enumerated lists (no autonumbering)
-
-- field lists (colons cannot be escaped)
-
-- option lists (supports only long options without arguments)
-
-- inline literals (no other inline markup is not recognized)
+Remember to update http://mercurial.selenic.com/wiki/HelpStyleGuide
+when adding support for new constructs.
"""
import re, sys
@@ -118,7 +99,8 @@
return blocks
_bulletre = re.compile(r'(-|[0-9A-Za-z]+\.|\(?[0-9A-Za-z]+\)|\|) ')
-_optionre = re.compile(r'^(--[a-z-]+)((?:[ =][a-zA-Z][\w-]*)? +)(.*)$')
+_optionre = re.compile(r'^(-([a-zA-Z0-9]), )?(--[a-z0-9-]+)'
+ r'((.*) +)(.*)$')
_fieldre = re.compile(r':(?![: ])([^:]*)(?<! ):[ ]+(.*)')
_definitionre = re.compile(r'[^ ]')
@@ -192,6 +174,42 @@
return blocks
+def updateoptionlists(blocks):
+ i = 0
+ while i < len(blocks):
+ if blocks[i]['type'] != 'option':
+ i += 1
+ continue
+
+ optstrwidth = 0
+ j = i
+ while j < len(blocks) and blocks[j]['type'] == 'option':
+ m = _optionre.match(blocks[j]['lines'][0])
+
+ shortoption = m.group(2)
+ group3 = m.group(3)
+ longoption = group3[2:].strip()
+ desc = m.group(6).strip()
+ longoptionarg = m.group(5).strip()
+ blocks[j]['lines'][0] = desc
+
+ noshortop = ''
+ if not shortoption:
+ noshortop = ' '
+
+ opt = "%s%s" % (shortoption and "-%s " % shortoption or '',
+ ("%s--%s %s") % (noshortop, longoption,
+ longoptionarg))
+ opt = opt.rstrip()
+ blocks[j]['optstr'] = opt
+ optstrwidth = max(optstrwidth, encoding.colwidth(opt))
+ j += 1
+
+ for block in blocks[i:j]:
+ block['optstrwidth'] = optstrwidth
+ i = j + 1
+ return blocks
+
def prunecontainers(blocks, keep):
"""Prune unwanted containers.
@@ -297,8 +315,11 @@
i = 0
while i < len(blocks):
b = blocks[i]
- if b['type'] == 'paragraph' and b['lines'][0].startswith('.. '):
+ if b['type'] == 'paragraph' and (b['lines'][0].startswith('.. ') or
+ b['lines'] == ['..']):
del blocks[i]
+ if i < len(blocks) and blocks[i]['type'] == 'margin':
+ del blocks[i]
else:
i += 1
return blocks
@@ -338,6 +359,17 @@
'tip': _('Tip:'),
'warning': _('Warning!')}
+def formatoption(block, width):
+ desc = ' '.join(map(str.strip, block['lines']))
+ colwidth = encoding.colwidth(block['optstr'])
+ usablewidth = width - 1
+ hanging = block['optstrwidth']
+ initindent = '%s%s ' % (block['optstr'], ' ' * ((hanging - colwidth)))
+ hangindent = ' ' * (encoding.colwidth(initindent) + 1)
+ return ' %s' % (util.wrap(desc, usablewidth,
+ initindent=initindent,
+ hangindent=hangindent))
+
def formatblock(block, width):
"""Format a block according to width."""
if width <= 0:
@@ -394,9 +426,7 @@
key = key.ljust(_fieldwidth)
block['lines'][0] = key + block['lines'][0]
elif block['type'] == 'option':
- m = _optionre.match(block['lines'][0])
- option, arg, rest = m.groups()
- subindent = indent + (len(option) + len(arg)) * ' '
+ return formatoption(block, width)
text = ' '.join(map(str.strip, block['lines']))
return util.wrap(text, width=width,
@@ -416,8 +446,9 @@
blocks = hgrole(blocks)
blocks = splitparagraphs(blocks)
blocks = updatefieldlists(blocks)
+ blocks = updateoptionlists(blocks)
+ blocks = addmargins(blocks)
blocks = prunecomments(blocks)
- blocks = addmargins(blocks)
blocks = findadmonitions(blocks)
text = '\n'.join(formatblock(b, width) for b in blocks)
if keep is None:
@@ -443,8 +474,9 @@
blocks = debug(inlineliterals, blocks)
blocks = debug(splitparagraphs, blocks)
blocks = debug(updatefieldlists, blocks)
+ blocks = debug(updateoptionlists, blocks)
blocks = debug(findsections, blocks)
+ blocks = debug(addmargins, blocks)
blocks = debug(prunecomments, blocks)
- blocks = debug(addmargins, blocks)
blocks = debug(findadmonitions, blocks)
print '\n'.join(formatblock(b, 30) for b in blocks)
--- a/mercurial/osutil.c Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/osutil.c Wed Feb 16 14:13:22 2011 -0600
@@ -436,7 +436,14 @@
}
else
flags = _O_TEXT;
- if (plus) {
+ if (m0 == 'r' && !plus) {
+ flags |= _O_RDONLY;
+ access = GENERIC_READ;
+ } else {
+ /*
+ work around http://support.microsoft.com/kb/899149 and
+ set _O_RDWR for 'w' and 'a', even if mode has no '+'
+ */
flags |= _O_RDWR;
access = GENERIC_READ | GENERIC_WRITE;
fpmode[fppos++] = '+';
@@ -446,25 +453,13 @@
switch (m0) {
case 'r':
creation = OPEN_EXISTING;
- if (!plus) {
- flags |= _O_RDONLY;
- access = GENERIC_READ;
- }
break;
case 'w':
creation = CREATE_ALWAYS;
- if (!plus) {
- access = GENERIC_WRITE;
- flags |= _O_WRONLY;
- }
break;
case 'a':
creation = OPEN_ALWAYS;
flags |= _O_APPEND;
- if (!plus) {
- flags |= _O_WRONLY;
- access = GENERIC_WRITE;
- }
break;
default:
PyErr_Format(PyExc_ValueError,
--- a/mercurial/parser.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/parser.py Wed Feb 16 14:13:22 2011 -0600
@@ -22,6 +22,7 @@
self._tokenizer = tokenizer
self._elements = elements
self._methods = methods
+ self.current = None
def _advance(self):
'advance the tokenizer'
t = self.current
@@ -76,7 +77,7 @@
def parse(self, message):
'generate a parse tree from a message'
self._iter = self._tokenizer(message)
- self.current = self._iter.next()
+ self._advance()
return self._parse()
def eval(self, tree):
'recursively evaluate a parse tree using node methods'
--- a/mercurial/parsers.c Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/parsers.c Wed Feb 16 14:13:22 2011 -0600
@@ -244,41 +244,6 @@
const char nullid[20];
const int nullrev = -1;
-/* create an index tuple, insert into the nodemap */
-static PyObject * _build_idx_entry(PyObject *nodemap, int n, uint64_t offset_flags,
- int comp_len, int uncomp_len, int base_rev,
- int link_rev, int parent_1, int parent_2,
- const char *c_node_id)
-{
- int err;
- PyObject *entry, *node_id, *n_obj;
-
- node_id = PyBytes_FromStringAndSize(c_node_id, 20);
- n_obj = PyInt_FromLong(n);
-
- if (!node_id || !n_obj)
- err = -1;
- else
- err = PyDict_SetItem(nodemap, node_id, n_obj);
-
- Py_XDECREF(n_obj);
- if (err)
- goto error_dealloc;
-
- entry = Py_BuildValue("LiiiiiiN", offset_flags, comp_len,
- uncomp_len, base_rev, link_rev,
- parent_1, parent_2, node_id);
- if (!entry)
- goto error_dealloc;
- PyObject_GC_UnTrack(entry); /* don't waste time with this */
-
- return entry;
-
-error_dealloc:
- Py_XDECREF(node_id);
- return NULL;
-}
-
/* RevlogNG format (all in big endian, data may be inlined):
* 6 bytes: offset
* 2 bytes: flags
@@ -290,8 +255,8 @@
* 4 bytes: parent 2 revision
* 32 bytes: nodeid (only 20 bytes used)
*/
-static int _parse_index_ng (const char *data, int size, int inlined,
- PyObject *index, PyObject *nodemap)
+static int _parse_index_ng(const char *data, int size, int inlined,
+ PyObject *index)
{
PyObject *entry;
int n = 0, err;
@@ -321,13 +286,15 @@
parent_2 = ntohl(*((uint32_t *)(decode + 28)));
c_node_id = decode + 32;
- entry = _build_idx_entry(nodemap, n, offset_flags,
- comp_len, uncomp_len, base_rev,
- link_rev, parent_1, parent_2,
- c_node_id);
+ entry = Py_BuildValue("Liiiiiis#", offset_flags, comp_len,
+ uncomp_len, base_rev, link_rev,
+ parent_1, parent_2, c_node_id, 20);
+
if (!entry)
return 0;
+ PyObject_GC_UnTrack(entry); /* don't waste time with this */
+
if (inlined) {
err = PyList_Append(index, entry);
Py_DECREF(entry);
@@ -348,12 +315,14 @@
return 0;
}
- /* create the nullid/nullrev entry in the nodemap and the
- * magic nullid entry in the index at [-1] */
- entry = _build_idx_entry(nodemap,
- nullrev, 0, 0, 0, -1, -1, -1, -1, nullid);
+ /* create the magic nullid entry in the index at [-1] */
+ entry = Py_BuildValue("Liiiiiis#", (uint64_t)0, 0, 0, -1, -1, -1, -1, nullid, 20);
+
if (!entry)
return 0;
+
+ PyObject_GC_UnTrack(entry); /* don't waste time with this */
+
if (inlined) {
err = PyList_Append(index, entry);
Py_DECREF(entry);
@@ -366,17 +335,16 @@
}
/* This function parses a index file and returns a Python tuple of the
- * following format: (index, nodemap, cache)
+ * following format: (index, cache)
*
* index: a list of tuples containing the RevlogNG records
- * nodemap: a dict mapping node ids to indices in the index list
* cache: if data is inlined, a tuple (index_file_content, 0) else None
*/
-static PyObject *parse_index(PyObject *self, PyObject *args)
+static PyObject *parse_index2(PyObject *self, PyObject *args)
{
const char *data;
int size, inlined;
- PyObject *rval = NULL, *index = NULL, *nodemap = NULL, *cache = NULL;
+ PyObject *rval = NULL, *index = NULL, *cache = NULL;
PyObject *data_obj = NULL, *inlined_obj;
if (!PyArg_ParseTuple(args, "s#O", &data, &size, &inlined_obj))
@@ -384,16 +352,12 @@
inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
/* If no data is inlined, we know the size of the index list in
- * advance: size divided by size of one one revlog record (64 bytes)
- * plus one for the nullid */
+ * advance: size divided by the size of one revlog record (64 bytes)
+ * plus one for nullid */
index = inlined ? PyList_New(0) : PyList_New(size / 64 + 1);
if (!index)
goto quit;
- nodemap = PyDict_New();
- if (!nodemap)
- goto quit;
-
/* set up the cache return value */
if (inlined) {
/* Note that the reference to data_obj is only borrowed */
@@ -406,18 +370,17 @@
Py_INCREF(Py_None);
}
- /* actually populate the index and the nodemap with data */
- if (!_parse_index_ng (data, size, inlined, index, nodemap))
+ /* actually populate the index with data */
+ if (!_parse_index_ng(data, size, inlined, index))
goto quit;
- rval = Py_BuildValue("NNN", index, nodemap, cache);
+ rval = Py_BuildValue("NN", index, cache);
if (!rval)
goto quit;
return rval;
quit:
Py_XDECREF(index);
- Py_XDECREF(nodemap);
Py_XDECREF(cache);
Py_XDECREF(rval);
return NULL;
@@ -429,7 +392,7 @@
static PyMethodDef methods[] = {
{"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
{"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
- {"parse_index", parse_index, METH_VARARGS, "parse a revlog index\n"},
+ {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
{NULL, NULL}
};
--- a/mercurial/patch.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/patch.py Wed Feb 16 14:13:22 2011 -0600
@@ -6,7 +6,7 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-import cStringIO, email.Parser, os, re
+import cStringIO, email.Parser, os, errno, re
import tempfile, zlib
from i18n import _
@@ -429,10 +429,16 @@
# Ensure supplied data ends in fname, being a regular file or
# a symlink. cmdutil.updatedir will -too magically- take care
# of setting it to the proper type afterwards.
+ st_mode = None
islink = os.path.islink(fname)
if islink:
fp = cStringIO.StringIO()
else:
+ try:
+ st_mode = os.lstat(fname).st_mode & 0777
+ except OSError, e:
+ if e.errno != errno.ENOENT:
+ raise
fp = self.opener(fname, 'w')
try:
if self.eolmode == 'auto':
@@ -451,6 +457,8 @@
fp.writelines(lines)
if islink:
self.opener.symlink(fp.getvalue(), fname)
+ if st_mode is not None:
+ os.chmod(fname, st_mode)
finally:
fp.close()
@@ -976,7 +984,7 @@
fp.seek(pos)
return gitpatches
-def iterhunks(ui, fp, sourcefile=None):
+def iterhunks(ui, fp):
"""Read a patch and yield the following events:
- ("file", afile, bfile, firsthunk): select a new target file.
- ("hunk", hunk): a new hunk is ready to be applied, follows a
@@ -997,10 +1005,6 @@
BFILE = 1
context = None
lr = linereader(fp)
- # gitworkdone is True if a git operation (copy, rename, ...) was
- # performed already for the current file. Useful when the file
- # section may have no hunk.
- gitworkdone = False
while True:
newfile = newgitfile = False
@@ -1012,7 +1016,7 @@
current_hunk.fix_newline()
yield 'hunk', current_hunk
current_hunk = None
- if ((sourcefile or state == BFILE) and ((not context and x[0] == '@') or
+ if (state == BFILE and ((not context and x[0] == '@') or
((context is not False) and x.startswith('***************')))):
if context is None and x.startswith('***************'):
context = True
@@ -1034,7 +1038,6 @@
elif x.startswith('diff --git'):
# check for git diff, scanning the whole patch file if needed
m = gitre.match(x)
- gitworkdone = False
if m:
afile, bfile = m.group(1, 2)
if not git:
@@ -1049,7 +1052,6 @@
if gp and (gp.op in ('COPY', 'DELETE', 'RENAME', 'ADD')
or gp.mode):
afile = bfile
- gitworkdone = True
newgitfile = True
elif x.startswith('---'):
# check for a unified diff
@@ -1077,9 +1079,6 @@
afile = parsefilename(x)
bfile = parsefilename(l2)
- if newfile:
- gitworkdone = False
-
if newgitfile or newfile:
emitfile = True
state = BFILE
@@ -1091,7 +1090,7 @@
raise PatchError(_("malformed patch %s %s") % (afile,
current_hunk.desc))
-def applydiff(ui, fp, changed, strip=1, sourcefile=None, eolmode='strict'):
+def applydiff(ui, fp, changed, strip=1, eolmode='strict'):
"""Reads a patch from fp and tries to apply it.
The dict 'changed' is filled in with all of the filenames changed
@@ -1105,13 +1104,10 @@
Callers probably want to call 'cmdutil.updatedir' after this to
apply certain categories of changes not done by this function.
"""
- return _applydiff(
- ui, fp, patchfile, copyfile,
- changed, strip=strip, sourcefile=sourcefile, eolmode=eolmode)
+ return _applydiff(ui, fp, patchfile, copyfile, changed, strip=strip,
+ eolmode=eolmode)
-
-def _applydiff(ui, fp, patcher, copyfn, changed, strip=1,
- sourcefile=None, eolmode='strict'):
+def _applydiff(ui, fp, patcher, copyfn, changed, strip=1, eolmode='strict'):
rejects = 0
err = 0
current_file = None
@@ -1126,7 +1122,7 @@
current_file.write_rej()
return len(current_file.rej)
- for state, values in iterhunks(ui, fp, sourcefile):
+ for state, values in iterhunks(ui, fp):
if state == 'hunk':
if not current_file:
continue
@@ -1139,14 +1135,10 @@
rejects += closefile()
afile, bfile, first_hunk = values
try:
- if sourcefile:
- current_file = patcher(ui, sourcefile, opener,
- eolmode=eolmode)
- else:
- current_file, missing = selectfile(afile, bfile,
- first_hunk, strip)
- current_file = patcher(ui, current_file, opener,
- missing=missing, eolmode=eolmode)
+ current_file, missing = selectfile(afile, bfile,
+ first_hunk, strip)
+ current_file = patcher(ui, current_file, opener,
+ missing=missing, eolmode=eolmode)
except PatchError, err:
ui.warn(str(err) + '\n')
current_file = None
@@ -1537,6 +1529,8 @@
yield text
def diffstatdata(lines):
+ diffre = re.compile('^diff .*-r [a-z0-9]+\s(.*)$')
+
filename, adds, removes = None, 0, 0
for line in lines:
if line.startswith('diff'):
@@ -1547,9 +1541,9 @@
adds, removes = 0, 0
if line.startswith('diff --git'):
filename = gitre.search(line).group(1)
- else:
+ elif line.startswith('diff -r'):
# format: "diff -r ... -r ... filename"
- filename = line.split(None, 5)[-1]
+ filename = diffre.search(line).group(1)
elif line.startswith('+') and not line.startswith('+++'):
adds += 1
elif line.startswith('-') and not line.startswith('---'):
--- a/mercurial/posix.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/posix.py Wed Feb 16 14:13:22 2011 -0600
@@ -13,6 +13,8 @@
nulldev = '/dev/null'
normpath = os.path.normpath
samestat = os.path.samestat
+os_link = os.link
+unlink = os.unlink
rename = os.rename
expandglobs = False
@@ -23,6 +25,10 @@
'''return true if it is safe to hold open file handles to hardlinks'''
return True
+def nlinks(name):
+ '''return number of hardlinks for the given file'''
+ return os.lstat(name).st_nlink
+
def rcfiles(path):
rcs = [os.path.join(path, 'hgrc')]
rcdir = os.path.join(path, 'hgrc.d')
@@ -71,20 +77,26 @@
if l:
if not stat.S_ISLNK(s):
# switch file to link
- data = open(f).read()
+ fp = open(f)
+ data = fp.read()
+ fp.close()
os.unlink(f)
try:
os.symlink(data, f)
except:
# failed to make a link, rewrite file
- open(f, "w").write(data)
+ fp = open(f, "w")
+ fp.write(data)
+ fp.close()
# no chmod needed at this point
return
if stat.S_ISLNK(s):
# switch link to file
data = os.readlink(f)
os.unlink(f)
- open(f, "w").write(data)
+ fp = open(f, "w")
+ fp.write(data)
+ fp.close()
s = 0666 & ~umask # avoid restatting for chmod
sx = s & 0100
--- a/mercurial/pure/parsers.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/pure/parsers.py Wed Feb 16 14:13:22 2011 -0600
@@ -24,7 +24,7 @@
else:
mfdict[f] = bin(n)
-def parse_index(data, inline):
+def parse_index2(data, inline):
def gettype(q):
return int(q & 0xFFFF)
@@ -36,16 +36,14 @@
s = struct.calcsize(indexformatng)
index = []
cache = None
- nodemap = {nullid: nullrev}
n = off = 0
- # if we're not using lazymap, always read the whole index
+
l = len(data) - s
append = index.append
if inline:
cache = (0, data)
while off <= l:
e = _unpack(indexformatng, data[off:off + s])
- nodemap[e[7]] = n
append(e)
n += 1
if e[1] < 0:
@@ -54,7 +52,6 @@
else:
while off <= l:
e = _unpack(indexformatng, data[off:off + s])
- nodemap[e[7]] = n
append(e)
n += 1
off += s
@@ -67,7 +64,7 @@
# add the magic null revision at -1
index.append((0, 0, 0, -1, -1, -1, -1, nullid))
- return index, nodemap, cache
+ return index, cache
def parse_dirstate(dmap, copymap, st):
parents = [st[:20], st[20: 40]]
--- a/mercurial/pushkey.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/pushkey.py Wed Feb 16 14:13:22 2011 -0600
@@ -5,13 +5,16 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
+import bookmarks
+
def _nslist(repo):
n = {}
for k in _namespaces:
n[k] = ""
return n
-_namespaces = {"namespaces": (lambda *x: False, _nslist)}
+_namespaces = {"namespaces": (lambda *x: False, _nslist),
+ "bookmarks": (bookmarks.pushbookmark, bookmarks.listbookmarks)}
def register(namespace, pushkey, listkeys):
_namespaces[namespace] = (pushkey, listkeys)
--- a/mercurial/repair.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/repair.py Wed Feb 16 14:13:22 2011 -0600
@@ -6,7 +6,7 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-import changegroup
+import changegroup, bookmarks
from node import nullrev, short
from i18n import _
import os
@@ -105,6 +105,13 @@
saveheads.difference_update(parents)
saveheads.add(r)
+ bm = repo._bookmarks
+ updatebm = []
+ for m in bm:
+ rev = repo[bm[m]].rev()
+ if rev in tostrip:
+ updatebm.append(m)
+
saveheads = [cl.node(r) for r in saveheads]
files = _collectfiles(repo, striprev)
@@ -155,6 +162,11 @@
f.close()
if not keeppartialbundle:
os.unlink(chgrpfile)
+
+ for m in updatebm:
+ bm[m] = repo['.'].node()
+ bookmarks.write(repo)
+
except:
if backupfile:
ui.warn(_("strip failed, full bundle stored in '%s'\n")
--- a/mercurial/repo.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/repo.py Wed Feb 16 14:13:22 2011 -0600
@@ -35,3 +35,6 @@
def cancopy(self):
return self.local()
+
+ def close(self):
+ pass
--- a/mercurial/revlog.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/revlog.py Wed Feb 16 14:13:22 2011 -0600
@@ -38,11 +38,9 @@
REVIDX_PUNCHED_FLAG = 2
REVIDX_KNOWN_FLAGS = REVIDX_PUNCHED_FLAG | REVIDX_PARENTDELTA
-# amount of data read unconditionally, should be >= 4
-# when not inline: threshold for using lazy index
-_prereadsize = 1048576
# max size of revlog with inline data
_maxinline = 131072
+_chunksize = 1048576
RevlogError = error.RevlogError
LookupError = error.LookupError
@@ -121,209 +119,6 @@
return bin[1:]
raise RevlogError(_("unknown compression type %r") % t)
-class lazyparser(object):
- """
- this class avoids the need to parse the entirety of large indices
- """
-
- # lazyparser is not safe to use on windows if win32 extensions not
- # available. it keeps file handle open, which make it not possible
- # to break hardlinks on local cloned repos.
-
- def __init__(self, dataf):
- try:
- size = util.fstat(dataf).st_size
- except AttributeError:
- size = 0
- self.dataf = dataf
- self.s = struct.calcsize(indexformatng)
- self.datasize = size
- self.l = size // self.s
- self.index = [None] * self.l
- self.map = {nullid: nullrev}
- self.allmap = 0
- self.all = 0
- self.mapfind_count = 0
-
- def loadmap(self):
- """
- during a commit, we need to make sure the rev being added is
- not a duplicate. This requires loading the entire index,
- which is fairly slow. loadmap can load up just the node map,
- which takes much less time.
- """
- if self.allmap:
- return
- end = self.datasize
- self.allmap = 1
- cur = 0
- count = 0
- blocksize = self.s * 256
- self.dataf.seek(0)
- while cur < end:
- data = self.dataf.read(blocksize)
- off = 0
- for x in xrange(256):
- n = data[off + ngshaoffset:off + ngshaoffset + 20]
- self.map[n] = count
- count += 1
- if count >= self.l:
- break
- off += self.s
- cur += blocksize
-
- def loadblock(self, blockstart, blocksize, data=None):
- if self.all:
- return
- if data is None:
- self.dataf.seek(blockstart)
- if blockstart + blocksize > self.datasize:
- # the revlog may have grown since we've started running,
- # but we don't have space in self.index for more entries.
- # limit blocksize so that we don't get too much data.
- blocksize = max(self.datasize - blockstart, 0)
- data = self.dataf.read(blocksize)
- lend = len(data) // self.s
- i = blockstart // self.s
- off = 0
- # lazyindex supports __delitem__
- if lend > len(self.index) - i:
- lend = len(self.index) - i
- for x in xrange(lend):
- if self.index[i + x] is None:
- b = data[off : off + self.s]
- self.index[i + x] = b
- n = b[ngshaoffset:ngshaoffset + 20]
- self.map[n] = i + x
- off += self.s
-
- def findnode(self, node):
- """search backwards through the index file for a specific node"""
- if self.allmap:
- return None
-
- # hg log will cause many many searches for the manifest
- # nodes. After we get called a few times, just load the whole
- # thing.
- if self.mapfind_count > 8:
- self.loadmap()
- if node in self.map:
- return node
- return None
- self.mapfind_count += 1
- last = self.l - 1
- while self.index[last] != None:
- if last == 0:
- self.all = 1
- self.allmap = 1
- return None
- last -= 1
- end = (last + 1) * self.s
- blocksize = self.s * 256
- while end >= 0:
- start = max(end - blocksize, 0)
- self.dataf.seek(start)
- data = self.dataf.read(end - start)
- findend = end - start
- while True:
- # we're searching backwards, so we have to make sure
- # we don't find a changeset where this node is a parent
- off = data.find(node, 0, findend)
- findend = off
- if off >= 0:
- i = off / self.s
- off = i * self.s
- n = data[off + ngshaoffset:off + ngshaoffset + 20]
- if n == node:
- self.map[n] = i + start / self.s
- return node
- else:
- break
- end -= blocksize
- return None
-
- def loadindex(self, i=None, end=None):
- if self.all:
- return
- all = False
- if i is None:
- blockstart = 0
- blocksize = (65536 / self.s) * self.s
- end = self.datasize
- all = True
- else:
- if end:
- blockstart = i * self.s
- end = end * self.s
- blocksize = end - blockstart
- else:
- blockstart = (i & ~1023) * self.s
- blocksize = self.s * 1024
- end = blockstart + blocksize
- while blockstart < end:
- self.loadblock(blockstart, blocksize)
- blockstart += blocksize
- if all:
- self.all = True
-
-class lazyindex(object):
- """a lazy version of the index array"""
- def __init__(self, parser):
- self.p = parser
- def __len__(self):
- return len(self.p.index)
- def load(self, pos):
- if pos < 0:
- pos += len(self.p.index)
- self.p.loadindex(pos)
- return self.p.index[pos]
- def __getitem__(self, pos):
- return _unpack(indexformatng, self.p.index[pos] or self.load(pos))
- def __setitem__(self, pos, item):
- self.p.index[pos] = _pack(indexformatng, *item)
- def __delitem__(self, pos):
- del self.p.index[pos]
- def insert(self, pos, e):
- self.p.index.insert(pos, _pack(indexformatng, *e))
- def append(self, e):
- self.p.index.append(_pack(indexformatng, *e))
-
-class lazymap(object):
- """a lazy version of the node map"""
- def __init__(self, parser):
- self.p = parser
- def load(self, key):
- n = self.p.findnode(key)
- if n is None:
- raise KeyError(key)
- def __contains__(self, key):
- if key in self.p.map:
- return True
- self.p.loadmap()
- return key in self.p.map
- def __iter__(self):
- yield nullid
- for i, ret in enumerate(self.p.index):
- if not ret:
- self.p.loadindex(i)
- ret = self.p.index[i]
- if isinstance(ret, str):
- ret = _unpack(indexformatng, ret)
- yield ret[7]
- def __getitem__(self, key):
- try:
- return self.p.map[key]
- except KeyError:
- try:
- self.load(key)
- return self.p.map[key]
- except KeyError:
- raise KeyError("node " + hex(key))
- def __setitem__(self, key, val):
- self.p.map[key] = val
- def __delitem__(self, key):
- del self.p.map[key]
-
indexformatv0 = ">4l20s20s20s"
v0shaoffset = 56
@@ -331,13 +126,11 @@
def __init__(self):
self.size = struct.calcsize(indexformatv0)
- def parseindex(self, fp, data, inline):
+ def parseindex(self, data, inline):
s = self.size
index = []
nodemap = {nullid: nullrev}
n = off = 0
- if len(data) == _prereadsize:
- data += fp.read() # read the rest
l = len(data)
while off + s <= l:
cur = data[off:off + s]
@@ -350,6 +143,9 @@
nodemap[e[6]] = n
n += 1
+ # add the magic null revision at -1
+ index.append((0, 0, 0, -1, -1, -1, -1, nullid))
+
return index, nodemap, None
def packentry(self, entry, node, version, rev):
@@ -377,24 +173,10 @@
def __init__(self):
self.size = struct.calcsize(indexformatng)
- def parseindex(self, fp, data, inline):
- if len(data) == _prereadsize:
- if util.openhardlinks() and not inline:
- # big index, let's parse it on demand
- parser = lazyparser(fp)
- index = lazyindex(parser)
- nodemap = lazymap(parser)
- e = list(index[0])
- type = gettype(e[0])
- e[0] = offset_type(0, type)
- index[0] = e
- return index, nodemap, None
- else:
- data += fp.read()
-
+ def parseindex(self, data, inline):
# call the C implementation to parse the index data
- index, nodemap, cache = parsers.parse_index(data, inline)
- return index, nodemap, cache
+ index, cache = parsers.parse_index2(data, inline)
+ return index, None, cache
def packentry(self, entry, node, version, rev):
p = _pack(indexformatng, *entry)
@@ -439,10 +221,12 @@
self.opener = opener
self._cache = None
self._chunkcache = (0, '')
- self.nodemap = {nullid: nullrev}
self.index = []
self._shallowroot = shallowroot
self._parentdelta = 0
+ self._pcache = {}
+ self._nodecache = {nullid: nullrev}
+ self._nodepos = None
v = REVLOG_DEFAULT_VERSION
if hasattr(opener, 'options') and 'defversion' in opener.options:
@@ -458,10 +242,8 @@
i = ''
try:
f = self.opener(self.indexfile)
- if "nonlazy" in getattr(self.opener, 'options', {}):
- i = f.read()
- else:
- i = f.read(_prereadsize)
+ i = f.read()
+ f.close()
if len(i) > 0:
v = struct.unpack(versionformat, i[:4])[0]
except IOError, inst:
@@ -486,37 +268,15 @@
self._io = revlogio()
if self.version == REVLOGV0:
self._io = revlogoldio()
- if i:
- try:
- d = self._io.parseindex(f, i, self._inline)
- except (ValueError, IndexError):
- raise RevlogError(_("index %s is corrupted") % (self.indexfile))
- self.index, self.nodemap, self._chunkcache = d
- if not self._chunkcache:
- self._chunkclear()
-
- # add the magic null revision at -1 (if it hasn't been done already)
- if (self.index == [] or isinstance(self.index, lazyindex) or
- self.index[-1][7] != nullid) :
- self.index.append((0, 0, 0, -1, -1, -1, -1, nullid))
-
- def _loadindex(self, start, end):
- """load a block of indexes all at once from the lazy parser"""
- if isinstance(self.index, lazyindex):
- self.index.p.loadindex(start, end)
-
- def _loadindexmap(self):
- """loads both the map and the index from the lazy parser"""
- if isinstance(self.index, lazyindex):
- p = self.index.p
- p.loadindex()
- self.nodemap = p.map
-
- def _loadmap(self):
- """loads the map from the lazy parser"""
- if isinstance(self.nodemap, lazymap):
- self.nodemap.p.loadmap()
- self.nodemap = self.nodemap.p.map
+ try:
+ d = self._io.parseindex(i, self._inline)
+ except (ValueError, IndexError):
+ raise RevlogError(_("index %s is corrupted") % (self.indexfile))
+ self.index, nodemap, self._chunkcache = d
+ if nodemap is not None:
+ self.nodemap = self._nodecache = nodemap
+ if not self._chunkcache:
+ self._chunkclear()
def tip(self):
return self.node(len(self.index) - 2)
@@ -525,11 +285,29 @@
def __iter__(self):
for i in xrange(len(self)):
yield i
+
+ @util.propertycache
+ def nodemap(self):
+ n = self.rev(self.node(0))
+ return self._nodecache
+
def rev(self, node):
try:
- return self.nodemap[node]
+ return self._nodecache[node]
except KeyError:
+ n = self._nodecache
+ i = self.index
+ p = self._nodepos
+ if p is None:
+ p = len(i) - 2
+ for r in xrange(p, -1, -1):
+ v = i[r][7]
+ n[v] = r
+ if v == node:
+ self._nodepos = r - 1
+ return r
raise LookupError(node, self.indexfile, _('no node'))
+
def node(self, rev):
return self.index[rev][7]
def linkrev(self, rev):
@@ -937,15 +715,19 @@
pass
def _partialmatch(self, id):
+ if id in self._pcache:
+ return self._pcache[id]
+
if len(id) < 40:
try:
# hex(node)[:...]
l = len(id) // 2 # grab an even number of digits
- bin_id = bin(id[:l * 2])
- nl = [n for n in self.nodemap if n[:l] == bin_id]
+ prefix = bin(id[:l * 2])
+ nl = [e[7] for e in self.index if e[7].startswith(prefix)]
nl = [n for n in nl if hex(n).startswith(id)]
if len(nl) > 0:
if len(nl) == 1:
+ self._pcache[id] = nl[0]
return nl[0]
raise LookupError(id, self.indexfile,
_('ambiguous identifier'))
@@ -978,7 +760,7 @@
def _addchunk(self, offset, data):
o, d = self._chunkcache
# try to add to existing cache
- if o + len(d) == offset and len(d) + len(data) < _prereadsize:
+ if o + len(d) == offset and len(d) + len(data) < _chunksize:
self._chunkcache = o, d + data
else:
self._chunkcache = offset, data
@@ -1060,7 +842,6 @@
(self.flags(rev) & ~REVIDX_KNOWN_FLAGS))
# build delta chain
- self._loadindex(base, rev + 1)
chain = []
index = self.index # for performance
iterrev = rev
@@ -1088,13 +869,18 @@
bins = [self._chunk(r) for r in chain]
text = mdiff.patches(text, bins)
+
+ text = self._checkhash(text, node, rev)
+
+ self._cache = (node, rev, text)
+ return text
+
+ def _checkhash(self, text, node, rev):
p1, p2 = self.parents(node)
if (node != hash(text, p1, p2) and
not (self.flags(rev) & REVIDX_PUNCHED_FLAG)):
raise RevlogError(_("integrity check failed on %s:%d")
% (self.indexfile, rev))
-
- self._cache = (node, rev, text)
return text
def checkinlinesize(self, tr, fp=None):
@@ -1382,6 +1168,7 @@
if not dfh and not self._inline:
# addrevision switched from inline to conventional
# reopen the index
+ ifh.close()
dfh = self.opener(self.datafile, "a")
ifh = self.opener(self.indexfile, "a")
finally:
@@ -1408,9 +1195,6 @@
if len(self) == 0:
return
- if isinstance(self.index, lazyindex):
- self._loadindexmap()
-
for rev in self:
if self.index[rev][4] >= minlink:
break
@@ -1444,6 +1228,7 @@
f = self.opener(self.datafile)
f.seek(0, 2)
actual = f.tell()
+ f.close()
dd = actual - expected
except IOError, inst:
if inst.errno != errno.ENOENT:
@@ -1454,6 +1239,7 @@
f = self.opener(self.indexfile)
f.seek(0, 2)
actual = f.tell()
+ f.close()
s = self._io.size
i = max(0, actual // s)
di = actual - (i * s)
--- a/mercurial/revset.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/revset.py Wed Feb 16 14:13:22 2011 -0600
@@ -7,6 +7,7 @@
import re
import parser, util, error, discovery
+import bookmarks as bookmarksmod
import match as matchmod
from i18n import _, gettext
@@ -202,9 +203,13 @@
return [r for r in subset if r == l]
def p1(repo, subset, x):
- """``p1(set)``
- First parent of changesets in set.
+ """``p1([set])``
+ First parent of changesets in set, or the working directory.
"""
+ if x is None:
+ p = repo[x].parents()[0].rev()
+ return [r for r in subset if r == p]
+
ps = set()
cl = repo.changelog
for r in getset(repo, range(len(repo)), x):
@@ -212,9 +217,17 @@
return [r for r in subset if r in ps]
def p2(repo, subset, x):
- """``p2(set)``
- Second parent of changesets in set.
+ """``p2([set])``
+ Second parent of changesets in set, or the working directory.
"""
+ if x is None:
+ ps = repo[x].parents()
+ try:
+ p = ps[1].rev()
+ return [r for r in subset if r == p]
+ except IndexError:
+ return []
+
ps = set()
cl = repo.changelog
for r in getset(repo, range(len(repo)), x):
@@ -222,9 +235,13 @@
return [r for r in subset if r in ps]
def parents(repo, subset, x):
- """``parents(set)``
- The set of all parents for all changesets in set.
+ """``parents([set])``
+ The set of all parents for all changesets in set, or the working directory.
"""
+ if x is None:
+ ps = tuple(p.rev() for p in repo[x].parents())
+ return [r for r in subset if r in ps]
+
ps = set()
cl = repo.changelog
for r in getset(repo, range(len(repo)), x):
@@ -648,12 +665,31 @@
def tagged(repo, subset, x):
return tag(repo, subset, x)
+def bookmark(repo, subset, x):
+ """``bookmark([name])``
+ The named bookmark or all bookmarks.
+ """
+ # i18n: "bookmark" is a keyword
+ args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
+ if args:
+ bm = getstring(args[0],
+ # i18n: "bookmark" is a keyword
+ _('the argument to bookmark must be a string'))
+ bmrev = bookmarksmod.listbookmarks(repo).get(bm, None)
+ if bmrev:
+ bmrev = repo[bmrev].rev()
+ return [r for r in subset if r == bmrev]
+ bms = set([repo[r].rev()
+ for r in bookmarksmod.listbookmarks(repo).values()])
+ return [r for r in subset if r in bms]
+
symbols = {
"adds": adds,
"all": getall,
"ancestor": ancestor,
"ancestors": ancestors,
"author": author,
+ "bookmark": bookmark,
"branch": branch,
"children": children,
"closed": closed,
@@ -699,7 +735,7 @@
}
def optimize(x, small):
- if x == None:
+ if x is None:
return 0, x
smallbonus = 1
--- a/mercurial/sshrepo.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/sshrepo.py Wed Feb 16 14:13:22 2011 -0600
@@ -91,10 +91,11 @@
size = util.fstat(self.pipee).st_size
if size == 0:
break
- l = self.pipee.readline()
- if not l:
+ s = self.pipee.read(size)
+ if not s:
break
- self.ui.status(_("remote: "), l)
+ for l in s.splitlines():
+ self.ui.status(_("remote: "), l, '\n')
def _abort(self, exception):
self.cleanup()
--- a/mercurial/statichttprepo.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/statichttprepo.py Wed Feb 16 14:13:22 2011 -0600
@@ -77,7 +77,6 @@
return httprangereader(f, urlopener)
return o
- opener.options = {'nonlazy': 1}
return opener
class statichttprepository(localrepo.localrepository):
@@ -99,7 +98,9 @@
raise
# check if it is a non-empty old-style repository
try:
- self.opener("00changelog.i").read(1)
+ fp = self.opener("00changelog.i")
+ fp.read(1)
+ fp.close()
except IOError, inst:
if inst.errno != errno.ENOENT:
raise
@@ -114,9 +115,7 @@
raise error.RepoError(_("requirement '%s' not supported") % r)
# setup store
- def pjoin(a, b):
- return a + '/' + b
- self.store = store.store(requirements, self.path, opener, pjoin)
+ self.store = store.store(requirements, self.path, opener)
self.spath = self.store.path
self.sopener = self.store.opener
self.sjoin = self.store.join
--- a/mercurial/store.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/store.py Wed Feb 16 14:13:22 2011 -0600
@@ -169,8 +169,7 @@
class basicstore(object):
'''base class for local repository stores'''
- def __init__(self, path, opener, pathjoiner):
- self.pathjoiner = pathjoiner
+ def __init__(self, path, opener):
self.path = path
self.createmode = _calcmode(path)
op = opener(self.path)
@@ -178,19 +177,21 @@
self.opener = lambda f, *args, **kw: op(encodedir(f), *args, **kw)
def join(self, f):
- return self.pathjoiner(self.path, encodedir(f))
+ return self.path + '/' + encodedir(f)
def _walk(self, relpath, recurse):
'''yields (unencoded, encoded, size)'''
- path = self.pathjoiner(self.path, relpath)
- striplen = len(self.path) + len(os.sep)
+ path = self.path
+ if relpath:
+ path += '/' + relpath
+ striplen = len(self.path) + 1
l = []
if os.path.isdir(path):
visit = [path]
while visit:
p = visit.pop()
for f, kind, st in osutil.listdir(p, stat=True):
- fp = self.pathjoiner(p, f)
+ fp = p + '/' + f
if kind == stat.S_IFREG and f[-2:] in ('.d', '.i'):
n = util.pconvert(fp[striplen:])
l.append((decodedir(n), n, st.st_size))
@@ -213,10 +214,12 @@
def copylist(self):
return ['requires'] + _data.split()
+ def write(self):
+ pass
+
class encodedstore(basicstore):
- def __init__(self, path, opener, pathjoiner):
- self.pathjoiner = pathjoiner
- self.path = self.pathjoiner(path, 'store')
+ def __init__(self, path, opener):
+ self.path = path + '/store'
self.createmode = _calcmode(self.path)
op = opener(self.path)
op.createmode = self.createmode
@@ -231,11 +234,11 @@
yield a, b, size
def join(self, f):
- return self.pathjoiner(self.path, encodefilename(f))
+ return self.path + '/' + encodefilename(f)
def copylist(self):
return (['requires', '00changelog.i'] +
- [self.pathjoiner('store', f) for f in _data.split()])
+ ['store/' + f for f in _data.split()])
class fncache(object):
# the filename used to be partially encoded
@@ -243,10 +246,12 @@
def __init__(self, opener):
self.opener = opener
self.entries = None
+ self._dirty = False
def _load(self):
'''fill the entries from the fncache file'''
self.entries = set()
+ self._dirty = False
try:
fp = self.opener('fncache', mode='rb')
except IOError:
@@ -265,12 +270,22 @@
fp.write(encodedir(p) + '\n')
fp.close()
self.entries = set(files)
+ self._dirty = False
+
+ def write(self):
+ if not self._dirty:
+ return
+ fp = self.opener('fncache', mode='wb', atomictemp=True)
+ for p in self.entries:
+ fp.write(encodedir(p) + '\n')
+ fp.rename()
+ self._dirty = False
def add(self, fn):
if self.entries is None:
self._load()
if fn not in self.entries:
- self.opener('fncache', 'ab').write(encodedir(fn) + '\n')
+ self._dirty = True
self.entries.add(fn)
def __contains__(self, fn):
@@ -284,10 +299,9 @@
return iter(self.entries)
class fncachestore(basicstore):
- def __init__(self, path, opener, pathjoiner, encode):
+ def __init__(self, path, opener, encode):
self.encode = encode
- self.pathjoiner = pathjoiner
- self.path = self.pathjoiner(path, 'store')
+ self.path = path + '/store'
self.createmode = _calcmode(self.path)
op = opener(self.path)
op.createmode = self.createmode
@@ -301,17 +315,16 @@
self.opener = fncacheopener
def join(self, f):
- return self.pathjoiner(self.path, self.encode(f))
+ return self.path + '/' + self.encode(f)
def datafiles(self):
rewrite = False
existing = []
- pjoin = self.pathjoiner
spath = self.path
for f in self.fncache:
ef = self.encode(f)
try:
- st = os.stat(pjoin(spath, ef))
+ st = os.stat(spath + '/' + ef)
yield f, ef, st.st_size
existing.append(f)
except OSError:
@@ -326,14 +339,16 @@
d = ('data dh fncache'
' 00manifest.d 00manifest.i 00changelog.d 00changelog.i')
return (['requires', '00changelog.i'] +
- [self.pathjoiner('store', f) for f in d.split()])
+ ['store/' + f for f in d.split()])
-def store(requirements, path, opener, pathjoiner=None):
- pathjoiner = pathjoiner or os.path.join
+ def write(self):
+ self.fncache.write()
+
+def store(requirements, path, opener):
if 'store' in requirements:
if 'fncache' in requirements:
auxencode = lambda f: _auxencode(f, 'dotencode' in requirements)
encode = lambda f: _hybridencode(f, auxencode)
- return fncachestore(path, opener, pathjoiner, encode)
- return encodedstore(path, opener, pathjoiner)
- return basicstore(path, opener, pathjoiner)
+ return fncachestore(path, opener, encode)
+ return encodedstore(path, opener)
+ return basicstore(path, opener)
--- a/mercurial/subrepo.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/subrepo.py Wed Feb 16 14:13:22 2011 -0600
@@ -6,7 +6,7 @@
# GNU General Public License version 2 or any later version.
import errno, os, re, xml.dom.minidom, shutil, urlparse, posixpath
-import stat, subprocess
+import stat, subprocess, tarfile
from i18n import _
import config, util, node, error, cmdutil
hg = None
@@ -163,6 +163,17 @@
# record merged .hgsubstate
writestate(repo, sm)
+def _updateprompt(ui, sub, dirty, local, remote):
+ if dirty:
+ msg = (_(' subrepository sources for %s differ\n'
+ 'use (l)ocal source (%s) or (r)emote source (%s)?\n')
+ % (subrelpath(sub), local, remote))
+ else:
+ msg = (_(' subrepository sources for %s differ (in checked out version)\n'
+ 'use (l)ocal source (%s) or (r)emote source (%s)?\n')
+ % (subrelpath(sub), local, remote))
+ return ui.promptchoice(msg, (_('&Local'), _('&Remote')), 0)
+
def reporelpath(repo):
"""return path to this (sub)repo as seen from outermost repo"""
parent = repo
@@ -172,6 +183,8 @@
def subrelpath(sub):
"""return path to this subrepo as seen from outermost repo"""
+ if hasattr(sub, '_relpath'):
+ return sub._relpath
if not hasattr(sub, '_repo'):
return sub._path
return reporelpath(sub._repo)
@@ -236,9 +249,10 @@
class abstractsubrepo(object):
- def dirty(self):
- """returns true if the dirstate of the subrepo does not match
- current stored state
+ def dirty(self, ignoreupdate=False):
+ """returns true if the dirstate of the subrepo is dirty or does not
+ match current stored state. If ignoreupdate is true, only check
+ whether the subrepo has uncommitted changes in its dirstate.
"""
raise NotImplementedError
@@ -266,7 +280,7 @@
"""
raise NotImplementedError
- def merge(self, state, overwrite=False):
+ def merge(self, state):
"""merge currently-saved state with the new state."""
raise NotImplementedError
@@ -304,13 +318,21 @@
"""return file flags"""
return ''
- def archive(self, archiver, prefix):
- for name in self.files():
+ def archive(self, ui, archiver, prefix):
+ files = self.files()
+ total = len(files)
+ relpath = subrelpath(self)
+ ui.progress(_('archiving (%s)') % relpath, 0,
+ unit=_('files'), total=total)
+ for i, name in enumerate(files):
flags = self.fileflags(name)
mode = 'x' in flags and 0755 or 0644
symlink = 'l' in flags
archiver.addfile(os.path.join(prefix, self._path, name),
mode, symlink, self.filedata(name))
+ ui.progress(_('archiving (%s)') % relpath, i + 1,
+ unit=_('files'), total=total)
+ ui.progress(_('archiving (%s)') % relpath, None)
class hgsubrepo(abstractsubrepo):
@@ -373,21 +395,22 @@
self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
% (inst, subrelpath(self)))
- def archive(self, archiver, prefix):
- abstractsubrepo.archive(self, archiver, prefix)
+ def archive(self, ui, archiver, prefix):
+ abstractsubrepo.archive(self, ui, archiver, prefix)
rev = self._state[1]
ctx = self._repo[rev]
for subpath in ctx.substate:
s = subrepo(ctx, subpath)
- s.archive(archiver, os.path.join(prefix, self._path))
+ s.archive(ui, archiver, os.path.join(prefix, self._path))
- def dirty(self):
+ def dirty(self, ignoreupdate=False):
r = self._state[1]
- if r == '':
+ if r == '' and not ignoreupdate: # no state recorded
return True
w = self._repo[None]
- if w.p1() != self._repo[r]: # version checked out change
+ if w.p1() != self._repo[r] and not ignoreupdate:
+ # different version checked out
return True
return w.dirty() # working directory changed
@@ -430,14 +453,26 @@
cur = self._repo['.']
dst = self._repo[state[1]]
anc = dst.ancestor(cur)
- if anc == cur:
- self._repo.ui.debug("updating subrepo %s\n" % subrelpath(self))
- hg.update(self._repo, state[1])
- elif anc == dst:
- self._repo.ui.debug("skipping subrepo %s\n" % subrelpath(self))
+
+ def mergefunc():
+ if anc == cur:
+ self._repo.ui.debug("updating subrepo %s\n" % subrelpath(self))
+ hg.update(self._repo, state[1])
+ elif anc == dst:
+ self._repo.ui.debug("skipping subrepo %s\n" % subrelpath(self))
+ else:
+ self._repo.ui.debug("merging subrepo %s\n" % subrelpath(self))
+ hg.merge(self._repo, state[1], remind=False)
+
+ wctx = self._repo[None]
+ if self.dirty():
+ if anc != dst:
+ if _updateprompt(self._repo.ui, self, wctx.dirty(), cur, dst):
+ mergefunc()
+ else:
+ mergefunc()
else:
- self._repo.ui.debug("merging subrepo %s\n" % subrelpath(self))
- hg.merge(self._repo, state[1], remind=False)
+ mergefunc()
def push(self, force):
# push subrepos depth-first for coherent ordering
@@ -484,13 +519,10 @@
def _svncommand(self, commands, filename=''):
path = os.path.join(self._ctx._repo.origroot, self._path, filename)
cmd = ['svn'] + commands + [path]
- cmd = [util.shellquote(arg) for arg in cmd]
- cmd = util.quotecommand(' '.join(cmd))
env = dict(os.environ)
# Avoid localized output, preserve current locale for everything else.
env['LC_MESSAGES'] = 'C'
- p = subprocess.Popen(cmd, shell=True, bufsize=-1,
- close_fds=util.closefds,
+ p = subprocess.Popen(cmd, bufsize=-1, close_fds=util.closefds,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True, env=env)
stdout, stderr = p.communicate()
@@ -543,9 +575,10 @@
return True, True
return bool(changes), False
- def dirty(self):
- if self._state[1] in self._wcrevs() and not self._wcchanged()[0]:
- return False
+ def dirty(self, ignoreupdate=False):
+ if not self._wcchanged()[0]:
+ if self._state[1] in self._wcrevs() or ignoreupdate:
+ return False
return True
def commit(self, text, user, date):
@@ -598,10 +631,12 @@
self._ui.status(status)
def merge(self, state):
- old = int(self._state[1])
- new = int(state[1])
- if new > old:
- self.get(state)
+ old = self._state[1]
+ new = state[1]
+ if new != self._wcrev():
+ dirty = old == self._wcrev() or self._wcchanged()[0]
+ if _updateprompt(self._ui, self, dirty, self._wcrev(), new):
+ self.get(state, False)
def push(self, force):
# push is a no-op for SVN
@@ -616,7 +651,347 @@
return self._svncommand(['cat'], name)
+class gitsubrepo(abstractsubrepo):
+ def __init__(self, ctx, path, state):
+ # TODO add git version check.
+ self._state = state
+ self._ctx = ctx
+ self._path = path
+ self._relpath = os.path.join(reporelpath(ctx._repo), path)
+ self._abspath = ctx._repo.wjoin(path)
+ self._ui = ctx._repo.ui
+
+ def _gitcommand(self, commands, env=None, stream=False):
+ return self._gitdir(commands, env=env, stream=stream)[0]
+
+ def _gitdir(self, commands, env=None, stream=False):
+ return self._gitnodir(commands, env=env, stream=stream,
+ cwd=self._abspath)
+
+ def _gitnodir(self, commands, env=None, stream=False, cwd=None):
+ """Calls the git command
+
+ The methods tries to call the git command. versions previor to 1.6.0
+ are not supported and very probably fail.
+ """
+ self._ui.debug('%s: git %s\n' % (self._relpath, ' '.join(commands)))
+ # unless ui.quiet is set, print git's stderr,
+ # which is mostly progress and useful info
+ errpipe = None
+ if self._ui.quiet:
+ errpipe = open(os.devnull, 'w')
+ p = subprocess.Popen(['git'] + commands, bufsize=-1, cwd=cwd, env=env,
+ close_fds=util.closefds,
+ stdout=subprocess.PIPE, stderr=errpipe)
+ if stream:
+ return p.stdout, None
+
+ retdata = p.stdout.read().strip()
+ # wait for the child to exit to avoid race condition.
+ p.wait()
+
+ if p.returncode != 0 and p.returncode != 1:
+ # there are certain error codes that are ok
+ command = commands[0]
+ if command in ('cat-file', 'symbolic-ref'):
+ return retdata, p.returncode
+ # for all others, abort
+ raise util.Abort('git %s error %d in %s' %
+ (command, p.returncode, self._relpath))
+
+ return retdata, p.returncode
+
+ def _gitstate(self):
+ return self._gitcommand(['rev-parse', 'HEAD'])
+
+ def _gitcurrentbranch(self):
+ current, err = self._gitdir(['symbolic-ref', 'HEAD', '--quiet'])
+ if err:
+ current = None
+ return current
+
+ def _githavelocally(self, revision):
+ out, code = self._gitdir(['cat-file', '-e', revision])
+ return code == 0
+
+ def _gitisancestor(self, r1, r2):
+ base = self._gitcommand(['merge-base', r1, r2])
+ return base == r1
+
+ def _gitbranchmap(self):
+ '''returns 2 things:
+ a map from git branch to revision
+ a map from revision to branches'''
+ branch2rev = {}
+ rev2branch = {}
+
+ out = self._gitcommand(['for-each-ref', '--format',
+ '%(objectname) %(refname)'])
+ for line in out.split('\n'):
+ revision, ref = line.split(' ')
+ if ref.startswith('refs/tags/'):
+ continue
+ if ref.startswith('refs/remotes/') and ref.endswith('/HEAD'):
+ continue # ignore remote/HEAD redirects
+ branch2rev[ref] = revision
+ rev2branch.setdefault(revision, []).append(ref)
+ return branch2rev, rev2branch
+
+ def _gittracking(self, branches):
+ 'return map of remote branch to local tracking branch'
+ # assumes no more than one local tracking branch for each remote
+ tracking = {}
+ for b in branches:
+ if b.startswith('refs/remotes/'):
+ continue
+ remote = self._gitcommand(['config', 'branch.%s.remote' % b])
+ if remote:
+ ref = self._gitcommand(['config', 'branch.%s.merge' % b])
+ tracking['refs/remotes/%s/%s' %
+ (remote, ref.split('/', 2)[2])] = b
+ return tracking
+
+ def _fetch(self, source, revision):
+ if not os.path.exists(os.path.join(self._abspath, '.git')):
+ self._ui.status(_('cloning subrepo %s\n') % self._relpath)
+ self._gitnodir(['clone', source, self._abspath])
+ if self._githavelocally(revision):
+ return
+ self._ui.status(_('pulling subrepo %s\n') % self._relpath)
+ # first try from origin
+ self._gitcommand(['fetch'])
+ if self._githavelocally(revision):
+ return
+ # then try from known subrepo source
+ self._gitcommand(['fetch', source])
+ if not self._githavelocally(revision):
+ raise util.Abort(_("revision %s does not exist in subrepo %s\n") %
+ (revision, self._relpath))
+
+ def dirty(self, ignoreupdate=False):
+ if not ignoreupdate and self._state[1] != self._gitstate():
+ # different version checked out
+ return True
+ # check for staged changes or modified files; ignore untracked files
+ out, code = self._gitdir(['diff-index', '--quiet', 'HEAD'])
+ return code == 1
+
+ def get(self, state, overwrite=False):
+ source, revision, kind = state
+ self._fetch(source, revision)
+ # if the repo was set to be bare, unbare it
+ if self._gitcommand(['config', '--bool', 'core.bare']) == 'true':
+ self._gitcommand(['config', 'core.bare', 'false'])
+ if self._gitstate() == revision:
+ self._gitcommand(['reset', '--hard', 'HEAD'])
+ return
+ elif self._gitstate() == revision:
+ if overwrite:
+ # first reset the index to unmark new files for commit, because
+ # reset --hard will otherwise throw away files added for commit,
+ # not just unmark them.
+ self._gitcommand(['reset', 'HEAD'])
+ self._gitcommand(['reset', '--hard', 'HEAD'])
+ return
+ branch2rev, rev2branch = self._gitbranchmap()
+
+ def checkout(args):
+ cmd = ['checkout']
+ if overwrite:
+ # first reset the index to unmark new files for commit, because
+ # the -f option will otherwise throw away files added for
+ # commit, not just unmark them.
+ self._gitcommand(['reset', 'HEAD'])
+ cmd.append('-f')
+ self._gitcommand(cmd + args)
+
+ def rawcheckout():
+ # no branch to checkout, check it out with no branch
+ self._ui.warn(_('checking out detached HEAD in subrepo %s\n') %
+ self._relpath)
+ self._ui.warn(_('check out a git branch if you intend '
+ 'to make changes\n'))
+ checkout(['-q', revision])
+
+ if revision not in rev2branch:
+ rawcheckout()
+ return
+ branches = rev2branch[revision]
+ firstlocalbranch = None
+ for b in branches:
+ if b == 'refs/heads/master':
+ # master trumps all other branches
+ checkout(['refs/heads/master'])
+ return
+ if not firstlocalbranch and not b.startswith('refs/remotes/'):
+ firstlocalbranch = b
+ if firstlocalbranch:
+ checkout([firstlocalbranch])
+ return
+
+ tracking = self._gittracking(branch2rev.keys())
+ # choose a remote branch already tracked if possible
+ remote = branches[0]
+ if remote not in tracking:
+ for b in branches:
+ if b in tracking:
+ remote = b
+ break
+
+ if remote not in tracking:
+ # create a new local tracking branch
+ local = remote.split('/', 2)[2]
+ checkout(['-b', local, remote])
+ elif self._gitisancestor(branch2rev[tracking[remote]], remote):
+ # When updating to a tracked remote branch,
+ # if the local tracking branch is downstream of it,
+ # a normal `git pull` would have performed a "fast-forward merge"
+ # which is equivalent to updating the local branch to the remote.
+ # Since we are only looking at branching at update, we need to
+ # detect this situation and perform this action lazily.
+ if tracking[remote] != self._gitcurrentbranch():
+ checkout([tracking[remote]])
+ self._gitcommand(['merge', '--ff', remote])
+ else:
+ # a real merge would be required, just checkout the revision
+ rawcheckout()
+
+ def commit(self, text, user, date):
+ cmd = ['commit', '-a', '-m', text]
+ env = os.environ.copy()
+ if user:
+ cmd += ['--author', user]
+ if date:
+ # git's date parser silently ignores when seconds < 1e9
+ # convert to ISO8601
+ env['GIT_AUTHOR_DATE'] = util.datestr(date,
+ '%Y-%m-%dT%H:%M:%S %1%2')
+ self._gitcommand(cmd, env=env)
+ # make sure commit works otherwise HEAD might not exist under certain
+ # circumstances
+ return self._gitstate()
+
+ def merge(self, state):
+ source, revision, kind = state
+ self._fetch(source, revision)
+ base = self._gitcommand(['merge-base', revision, self._state[1]])
+ out, code = self._gitdir(['diff-index', '--quiet', 'HEAD'])
+
+ def mergefunc():
+ if base == revision:
+ self.get(state) # fast forward merge
+ elif base != self._state[1]:
+ self._gitcommand(['merge', '--no-commit', revision])
+
+ if self.dirty():
+ if self._gitstate() != revision:
+ dirty = self._gitstate() == self._state[1] or code != 0
+ if _updateprompt(self._ui, self, dirty, self._state[1], revision):
+ mergefunc()
+ else:
+ mergefunc()
+
+ def push(self, force):
+ # if a branch in origin contains the revision, nothing to do
+ branch2rev, rev2branch = self._gitbranchmap()
+ if self._state[1] in rev2branch:
+ for b in rev2branch[self._state[1]]:
+ if b.startswith('refs/remotes/origin/'):
+ return True
+ for b, revision in branch2rev.iteritems():
+ if b.startswith('refs/remotes/origin/'):
+ if self._gitisancestor(self._state[1], revision):
+ return True
+ # otherwise, try to push the currently checked out branch
+ cmd = ['push']
+ if force:
+ cmd.append('--force')
+
+ current = self._gitcurrentbranch()
+ if current:
+ # determine if the current branch is even useful
+ if not self._gitisancestor(self._state[1], current):
+ self._ui.warn(_('unrelated git branch checked out '
+ 'in subrepo %s\n') % self._relpath)
+ return False
+ self._ui.status(_('pushing branch %s of subrepo %s\n') %
+ (current.split('/', 2)[2], self._relpath))
+ self._gitcommand(cmd + ['origin', current])
+ return True
+ else:
+ self._ui.warn(_('no branch checked out in subrepo %s\n'
+ 'cannot push revision %s') %
+ (self._relpath, self._state[1]))
+ return False
+
+ def remove(self):
+ if self.dirty():
+ self._ui.warn(_('not removing repo %s because '
+ 'it has changes.\n') % self._relpath)
+ return
+ # we can't fully delete the repository as it may contain
+ # local-only history
+ self._ui.note(_('removing subrepo %s\n') % self._relpath)
+ self._gitcommand(['config', 'core.bare', 'true'])
+ for f in os.listdir(self._abspath):
+ if f == '.git':
+ continue
+ path = os.path.join(self._abspath, f)
+ if os.path.isdir(path) and not os.path.islink(path):
+ shutil.rmtree(path)
+ else:
+ os.remove(path)
+
+ def archive(self, ui, archiver, prefix):
+ source, revision = self._state
+ self._fetch(source, revision)
+
+ # Parse git's native archive command.
+ # This should be much faster than manually traversing the trees
+ # and objects with many subprocess calls.
+ tarstream = self._gitcommand(['archive', revision], stream=True)
+ tar = tarfile.open(fileobj=tarstream, mode='r|')
+ relpath = subrelpath(self)
+ ui.progress(_('archiving (%s)') % relpath, 0, unit=_('files'))
+ for i, info in enumerate(tar):
+ if info.isdir():
+ continue
+ if info.issym():
+ data = info.linkname
+ else:
+ data = tar.extractfile(info).read()
+ archiver.addfile(os.path.join(prefix, self._path, info.name),
+ info.mode, info.issym(), data)
+ ui.progress(_('archiving (%s)') % relpath, i + 1,
+ unit=_('files'))
+ ui.progress(_('archiving (%s)') % relpath, None)
+
+
+ def status(self, rev2, **opts):
+ rev1 = self._state[1]
+ modified, added, removed = [], [], []
+ if rev2:
+ command = ['diff-tree', rev1, rev2]
+ else:
+ command = ['diff-index', rev1]
+ out = self._gitcommand(command)
+ for line in out.split('\n'):
+ tab = line.find('\t')
+ if tab == -1:
+ continue
+ status, f = line[tab - 1], line[tab + 1:]
+ if status == 'M':
+ modified.append(f)
+ elif status == 'A':
+ added.append(f)
+ elif status == 'D':
+ removed.append(f)
+
+ deleted = unknown = ignored = clean = []
+ return modified, added, removed, deleted, unknown, ignored, clean
+
types = {
'hg': hgsubrepo,
'svn': svnsubrepo,
+ 'git': gitsubrepo,
}
--- a/mercurial/tags.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/tags.py Wed Feb 16 14:13:22 2011 -0600
@@ -12,6 +12,7 @@
from node import nullid, bin, hex, short
from i18n import _
+import os.path
import encoding
import error
@@ -99,9 +100,6 @@
except TypeError:
warn(_("node '%s' is not well formed") % nodehex)
continue
- if nodebin not in repo.changelog.nodemap:
- # silently ignore as pull -r might cause this
- continue
# update filetags
hist = []
@@ -154,7 +152,7 @@
set, caller is responsible for reading tag info from each head.'''
try:
- cachefile = repo.opener('tags.cache', 'r')
+ cachefile = repo.opener('cache/tags', 'r')
# force reading the file for static-http
cachelines = iter(cachefile)
except IOError:
@@ -188,8 +186,8 @@
fnode = bin(line[2])
cachefnode[headnode] = fnode
except (ValueError, TypeError):
- # corruption of tags.cache, just recompute it
- ui.warn(_('.hg/tags.cache is corrupt, rebuilding it\n'))
+ # corruption of the tags cache, just recompute it
+ ui.warn(_('.hg/cache/tags is corrupt, rebuilding it\n'))
cacheheads = []
cacherevs = []
cachefnode = {}
@@ -251,7 +249,7 @@
def _writetagcache(ui, repo, heads, tagfnode, cachetags):
try:
- cachefile = repo.opener('tags.cache', 'w', atomictemp=True)
+ cachefile = repo.opener('cache/tags', 'w', atomictemp=True)
except (OSError, IOError):
return
--- a/mercurial/templatekw.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/templatekw.py Wed Feb 16 14:13:22 2011 -0600
@@ -145,12 +145,18 @@
def showauthor(repo, ctx, templ, **args):
return ctx.user()
+def showbranch(**args):
+ return args['ctx'].branch()
+
def showbranches(**args):
branch = args['ctx'].branch()
if branch != 'default':
- branch = encoding.tolocal(branch)
return showlist('branch', [branch], plural='branches', **args)
+def showbookmarks(**args):
+ bookmarks = args['ctx'].bookmarks()
+ return showlist('bookmark', bookmarks, **args)
+
def showchildren(**args):
ctx = args['ctx']
childrevs = ['%d:%s' % (cctx, cctx) for cctx in ctx.children()]
@@ -163,9 +169,8 @@
return ctx.description().strip()
def showdiffstat(repo, ctx, templ, **args):
- diff = patch.diff(repo, ctx.parents()[0].node(), ctx.node())
files, adds, removes = 0, 0, 0
- for i in patch.diffstatdata(util.iterlines(diff)):
+ for i in patch.diffstatdata(util.iterlines(ctx.diff())):
files += 1
adds += i[1]
removes += i[2]
@@ -249,7 +254,9 @@
# revcache - a cache dictionary for the current revision
keywords = {
'author': showauthor,
+ 'branch': showbranch,
'branches': showbranches,
+ 'bookmarks': showbookmarks,
'children': showchildren,
'date': showdate,
'desc': showdescription,
--- a/mercurial/templater.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/templater.py Wed Feb 16 14:13:22 2011 -0600
@@ -7,7 +7,192 @@
from i18n import _
import sys, os
-import util, config, templatefilters
+import util, config, templatefilters, parser, error
+
+# template parsing
+
+elements = {
+ "(": (20, ("group", 1, ")"), ("func", 1, ")")),
+ ",": (2, None, ("list", 2)),
+ "|": (5, None, ("|", 5)),
+ "%": (6, None, ("%", 6)),
+ ")": (0, None, None),
+ "symbol": (0, ("symbol",), None),
+ "string": (0, ("string",), None),
+ "end": (0, None, None),
+}
+
+def tokenizer(data):
+ program, start, end = data
+ pos = start
+ while pos < end:
+ c = program[pos]
+ if c.isspace(): # skip inter-token whitespace
+ pass
+ elif c in "(,)%|": # handle simple operators
+ yield (c, None, pos)
+ elif (c in '"\'' or c == 'r' and
+ program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
+ if c == 'r':
+ pos += 1
+ c = program[pos]
+ decode = lambda x: x
+ else:
+ decode = lambda x: x.decode('string-escape')
+ pos += 1
+ s = pos
+ while pos < end: # find closing quote
+ d = program[pos]
+ if d == '\\': # skip over escaped characters
+ pos += 2
+ continue
+ if d == c:
+ yield ('string', decode(program[s:pos]), s)
+ break
+ pos += 1
+ else:
+ raise error.ParseError(_("unterminated string"), s)
+ elif c.isalnum() or c in '_':
+ s = pos
+ pos += 1
+ while pos < end: # find end of symbol
+ d = program[pos]
+ if not (d.isalnum() or d == "_"):
+ break
+ pos += 1
+ sym = program[s:pos]
+ yield ('symbol', sym, s)
+ pos -= 1
+ elif c == '}':
+ pos += 1
+ break
+ else:
+ raise error.ParseError(_("syntax error"), pos)
+ pos += 1
+ data[2] = pos
+ yield ('end', None, pos)
+
+def compiletemplate(tmpl, context):
+ parsed = []
+ pos, stop = 0, len(tmpl)
+ p = parser.parser(tokenizer, elements)
+
+ while pos < stop:
+ n = tmpl.find('{', pos)
+ if n < 0:
+ parsed.append(("string", tmpl[pos:]))
+ break
+ if n > 0 and tmpl[n - 1] == '\\':
+ # escaped
+ parsed.append(("string", tmpl[pos:n - 1] + "{"))
+ pos = n + 1
+ continue
+ if n > pos:
+ parsed.append(("string", tmpl[pos:n]))
+
+ pd = [tmpl, n + 1, stop]
+ parsed.append(p.parse(pd))
+ pos = pd[2]
+
+ return [compileexp(e, context) for e in parsed]
+
+def compileexp(exp, context):
+ t = exp[0]
+ if t in methods:
+ return methods[t](exp, context)
+ raise error.ParseError(_("unknown method '%s'") % t)
+
+# template evaluation
+
+def getsymbol(exp):
+ if exp[0] == 'symbol':
+ return exp[1]
+ raise error.ParseError(_("expected a symbol"))
+
+def getlist(x):
+ if not x:
+ return []
+ if x[0] == 'list':
+ return getlist(x[1]) + [x[2]]
+ return [x]
+
+def getfilter(exp, context):
+ f = getsymbol(exp)
+ if f not in context._filters:
+ raise error.ParseError(_("unknown function '%s'") % f)
+ return context._filters[f]
+
+def gettemplate(exp, context):
+ if exp[0] == 'string':
+ return compiletemplate(exp[1], context)
+ if exp[0] == 'symbol':
+ return context._load(exp[1])
+ raise error.ParseError(_("expected template specifier"))
+
+def runstring(context, mapping, data):
+ return data
+
+def runsymbol(context, mapping, key):
+ v = mapping.get(key)
+ if v is None:
+ v = context._defaults.get(key, '')
+ if hasattr(v, '__call__'):
+ return v(**mapping)
+ return v
+
+def buildfilter(exp, context):
+ func, data = compileexp(exp[1], context)
+ filt = getfilter(exp[2], context)
+ return (runfilter, (func, data, filt))
+
+def runfilter(context, mapping, data):
+ func, data, filt = data
+ return filt(func(context, mapping, data))
+
+def buildmap(exp, context):
+ func, data = compileexp(exp[1], context)
+ ctmpl = gettemplate(exp[2], context)
+ return (runmap, (func, data, ctmpl))
+
+def runmap(context, mapping, data):
+ func, data, ctmpl = data
+ d = func(context, mapping, data)
+ lm = mapping.copy()
+
+ for i in d:
+ if isinstance(i, dict):
+ lm.update(i)
+ for f, d in ctmpl:
+ yield f(context, lm, d)
+ else:
+ # v is not an iterable of dicts, this happen when 'key'
+ # has been fully expanded already and format is useless.
+ # If so, return the expanded value.
+ yield i
+
+def buildfunc(exp, context):
+ n = getsymbol(exp[1])
+ args = [compileexp(x, context) for x in getlist(exp[2])]
+ if n in context._filters:
+ if len(args) != 1:
+ raise error.ParseError(_("filter %s expects one argument") % n)
+ f = context._filters[n]
+ return (runfilter, (args[0][0], args[0][1], f))
+ elif n in context._funcs:
+ f = context._funcs[n]
+ return (f, args)
+
+methods = {
+ "string": lambda e, c: (runstring, e[1]),
+ "symbol": lambda e, c: (runsymbol, e[1]),
+ "group": lambda e, c: compileexp(e[1], c),
+# ".": buildmember,
+ "|": buildfilter,
+ "%": buildmap,
+ "func": buildfunc,
+ }
+
+# template engine
path = ['templates', '../templates']
stringify = templatefilters.stringify
@@ -66,104 +251,18 @@
self._defaults = defaults
self._cache = {}
+ def _load(self, t):
+ '''load, parse, and cache a template'''
+ if t not in self._cache:
+ self._cache[t] = compiletemplate(self._loader(t), self)
+ return self._cache[t]
+
def process(self, t, mapping):
'''Perform expansion. t is name of map element to expand.
mapping contains added elements for use during expansion. Is a
generator.'''
- return _flatten(self._process(self._load(t), mapping))
-
- def _load(self, t):
- '''load, parse, and cache a template'''
- if t not in self._cache:
- self._cache[t] = self._parse(self._loader(t))
- return self._cache[t]
-
- def _get(self, mapping, key):
- v = mapping.get(key)
- if v is None:
- v = self._defaults.get(key, '')
- if hasattr(v, '__call__'):
- v = v(**mapping)
- return v
-
- def _filter(self, mapping, parts):
- filters, val = parts
- x = self._get(mapping, val)
- for f in filters:
- x = f(x)
- return x
-
- def _format(self, mapping, args):
- key, parsed = args
- v = self._get(mapping, key)
- if not hasattr(v, '__iter__'):
- raise SyntaxError(_("error expanding '%s%%%s'")
- % (key, parsed))
- lm = mapping.copy()
- for i in v:
- if isinstance(i, dict):
- lm.update(i)
- yield self._process(parsed, lm)
- else:
- # v is not an iterable of dicts, this happen when 'key'
- # has been fully expanded already and format is useless.
- # If so, return the expanded value.
- yield i
-
- def _parse(self, tmpl):
- '''preparse a template'''
- parsed = []
- pos, stop = 0, len(tmpl)
- while pos < stop:
- n = tmpl.find('{', pos)
- if n < 0:
- parsed.append((None, tmpl[pos:stop]))
- break
- if n > 0 and tmpl[n - 1] == '\\':
- # escaped
- parsed.append((None, tmpl[pos:n - 1] + "{"))
- pos = n + 1
- continue
- if n > pos:
- parsed.append((None, tmpl[pos:n]))
-
- pos = n
- n = tmpl.find('}', pos)
- if n < 0:
- # no closing
- parsed.append((None, tmpl[pos:stop]))
- break
-
- expr = tmpl[pos + 1:n]
- pos = n + 1
-
- if '%' in expr:
- # the keyword should be formatted with a template
- key, t = expr.split('%')
- parsed.append((self._format, (key.strip(),
- self._load(t.strip()))))
- elif '|' in expr:
- # process the keyword value with one or more filters
- parts = expr.split('|')
- val = parts[0].strip()
- try:
- filters = [self._filters[f.strip()] for f in parts[1:]]
- except KeyError, i:
- raise SyntaxError(_("unknown filter '%s'") % i[0])
- parsed.append((self._filter, (filters, val)))
- else:
- # just get the keyword
- parsed.append((self._get, expr.strip()))
-
- return parsed
-
- def _process(self, parsed, mapping):
- '''Render a template. Returns a generator.'''
- for f, e in parsed:
- if f:
- yield f(mapping, e)
- else:
- yield e
+ return _flatten(func(self, mapping, data) for func, data in
+ self._load(t))
engines = {'default': engine}
@@ -183,7 +282,7 @@
self.filters.update(filters)
self.defaults = defaults
self.minchunk, self.maxchunk = minchunk, maxchunk
- self.engines = {}
+ self.ecache = {}
if not mapfile:
return
@@ -214,6 +313,8 @@
if not t in self.cache:
try:
self.cache[t] = open(self.map[t][1]).read()
+ except KeyError, inst:
+ raise util.Abort(_('"%s" not in template map') % inst.args[0])
except IOError, inst:
raise IOError(inst.args[0], _('template file %s: %s') %
(self.map[t][1], inst.args[1]))
@@ -221,10 +322,10 @@
def __call__(self, t, **mapping):
ttype = t in self.map and self.map[t][0] or 'default'
- proc = self.engines.get(ttype)
- if proc is None:
- proc = engines[ttype](self.load, self.filters, self.defaults)
- self.engines[ttype] = proc
+ if ttype not in self.ecache:
+ self.ecache[ttype] = engines[ttype](self.load,
+ self.filters, self.defaults)
+ proc = self.ecache[ttype]
stream = proc.process(t, mapping)
if self.minchunk:
--- a/mercurial/templates/map-cmdline.default Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/templates/map-cmdline.default Wed Feb 16 14:13:22 2011 -0600
@@ -1,7 +1,7 @@
-changeset = 'changeset: {rev}:{node|short}\n{branches}{tags}{parents}user: {author}\ndate: {date|date}\nsummary: {desc|firstline}\n\n'
+changeset = 'changeset: {rev}:{node|short}\n{branches}{bookmarks}{tags}{parents}user: {author}\ndate: {date|date}\nsummary: {desc|firstline}\n\n'
changeset_quiet = '{rev}:{node|short}\n'
-changeset_verbose = 'changeset: {rev}:{node|short}\n{branches}{tags}{parents}user: {author}\ndate: {date|date}\n{files}{file_copies_switch}description:\n{desc|strip}\n\n\n'
-changeset_debug = 'changeset: {rev}:{node}\n{branches}{tags}{parents}{manifest}user: {author}\ndate: {date|date}\n{file_mods}{file_adds}{file_dels}{file_copies_switch}{extras}description:\n{desc|strip}\n\n\n'
+changeset_verbose = 'changeset: {rev}:{node|short}\n{branches}{bookmarks}{tags}{parents}user: {author}\ndate: {date|date}\n{files}{file_copies_switch}description:\n{desc|strip}\n\n\n'
+changeset_debug = 'changeset: {rev}:{node}\n{branches}{bookmarks}{tags}{parents}{manifest}user: {author}\ndate: {date|date}\n{file_mods}{file_adds}{file_dels}{file_copies_switch}{extras}description:\n{desc|strip}\n\n\n'
start_files = 'files: '
file = ' {file}'
end_files = '\n'
@@ -21,4 +21,5 @@
manifest = 'manifest: {rev}:{node}\n'
branch = 'branch: {branch}\n'
tag = 'tag: {tag}\n'
+bookmark = 'bookmark: {bookmark}\n'
extra = 'extra: {key}={value|stringescape}\n'
--- a/mercurial/templates/map-cmdline.xml Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/templates/map-cmdline.xml Wed Feb 16 14:13:22 2011 -0600
@@ -1,9 +1,9 @@
header = '<?xml version="1.0"?>\n<log>\n'
footer = '</log>\n'
-changeset = '<logentry revision="{rev}" node="{node}">\n{branches}{tags}{parents}<author email="{author|email|xmlescape}">{author|person|xmlescape}</author>\n<date>{date|rfc3339date}</date>\n<msg xml:space="preserve">{desc|xmlescape}</msg>\n</logentry>\n'
-changeset_verbose = '<logentry revision="{rev}" node="{node}">\n{branches}{tags}{parents}<author email="{author|email|xmlescape}">{author|person|xmlescape}</author>\n<date>{date|rfc3339date}</date>\n<msg xml:space="preserve">{desc|xmlescape}</msg>\n<paths>\n{file_adds}{file_dels}{file_mods}</paths>\n{file_copies}</logentry>\n'
-changeset_debug = '<logentry revision="{rev}" node="{node}">\n{branches}{tags}{parents}<author email="{author|email|xmlescape}">{author|person|xmlescape}</author>\n<date>{date|rfc3339date}</date>\n<msg xml:space="preserve">{desc|xmlescape}</msg>\n<paths>\n{file_adds}{file_dels}{file_mods}</paths>\n{file_copies}{extras}</logentry>\n'
+changeset = '<logentry revision="{rev}" node="{node}">\n{branches}{bookmarks}{tags}{parents}<author email="{author|email|xmlescape}">{author|person|xmlescape}</author>\n<date>{date|rfc3339date}</date>\n<msg xml:space="preserve">{desc|xmlescape}</msg>\n</logentry>\n'
+changeset_verbose = '<logentry revision="{rev}" node="{node}">\n{branches}{bookmarks}{tags}{parents}<author email="{author|email|xmlescape}">{author|person|xmlescape}</author>\n<date>{date|rfc3339date}</date>\n<msg xml:space="preserve">{desc|xmlescape}</msg>\n<paths>\n{file_adds}{file_dels}{file_mods}</paths>\n{file_copies}</logentry>\n'
+changeset_debug = '<logentry revision="{rev}" node="{node}">\n{branches}{bookmarks}{tags}{parents}<author email="{author|email|xmlescape}">{author|person|xmlescape}</author>\n<date>{date|rfc3339date}</date>\n<msg xml:space="preserve">{desc|xmlescape}</msg>\n<paths>\n{file_adds}{file_dels}{file_mods}</paths>\n{file_copies}{extras}</logentry>\n'
file_add = '<path action="A">{file_add|xmlescape}</path>\n'
file_mod = '<path action="M">{file_mod|xmlescape}</path>\n'
@@ -16,4 +16,5 @@
parent = '<parent revision="{rev}" node="{node}" />\n'
branch = '<branch>{branch|xmlescape}</branch>\n'
tag = '<tag>{tag|xmlescape}</tag>\n'
+bookmark = '<bookmark>{bookmark|xmlescape}</bookmark>\n'
extra = '<extra key="{key|xmlescape}">{value|xmlescape}</extra>\n'
--- a/mercurial/templates/paper/branches.tmpl Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/templates/paper/branches.tmpl Wed Feb 16 14:13:22 2011 -0600
@@ -40,7 +40,18 @@
<th>branch</th>
<th>node</th>
</tr>
-{entries%branchentry}
+{entries %
+' <tr class="tagEntry parity{parity}">
+ <td>
+ <a href="{url}shortlog/{node|short}{sessionvars%urlparameter}" class="{status}">
+ {branch|escape}
+ </a>
+ </td>
+ <td class="node">
+ {node|short}
+ </td>
+ </tr>'
+}
</table>
</div>
</div>
--- a/mercurial/templates/paper/shortlogentry.tmpl Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/templates/paper/shortlogentry.tmpl Wed Feb 16 14:13:22 2011 -0600
@@ -1,5 +1,5 @@
<tr class="parity{parity}">
- <td class="age">{date|age}</td>
+ <td class="age">{age(date)}</td>
<td class="author">{author|person}</td>
- <td class="description"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{desc|strip|firstline|escape|nonempty}</a>{inbranch%changelogbranchname}{branches%changelogbranchhead}{tags%changelogtag}</td>
+ <td class="description"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{desc|strip|firstline|escape|nonempty}</a>{inbranch%changelogbranchname}{branches%changelogbranchhead}{tags % '<span class="tag">{name|escape}</span> '}</td>
</tr>
--- a/mercurial/transaction.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/transaction.py Wed Feb 16 14:13:22 2011 -0600
@@ -13,7 +13,7 @@
from i18n import _
import os, errno
-import error
+import error, util
def active(func):
def _active(self, *args, **kwds):
@@ -27,18 +27,22 @@
for f, o, ignore in entries:
if o or not unlink:
try:
- opener(f, 'a').truncate(o)
+ fp = opener(f, 'a')
+ fp.truncate(o)
+ fp.close()
except IOError:
report(_("failed to truncate %s\n") % f)
raise
else:
try:
- fn = opener(f).name
- os.unlink(fn)
+ fp = opener(f)
+ fn = fp.name
+ fp.close()
+ util.unlink(fn)
except (IOError, OSError), inst:
if inst.errno != errno.ENOENT:
raise
- os.unlink(journal)
+ util.unlink(journal)
class transaction(object):
def __init__(self, report, opener, journal, after=None, createmode=None):
@@ -52,7 +56,7 @@
self.journal = journal
self._queue = []
- self.file = open(self.journal, "w")
+ self.file = util.posixfile(self.journal, "w")
if createmode is not None:
os.chmod(self.journal, createmode & 0666)
@@ -133,7 +137,7 @@
if self.after:
self.after()
if os.path.isfile(self.journal):
- os.unlink(self.journal)
+ util.unlink(self.journal)
self.journal = None
@active
@@ -151,7 +155,7 @@
try:
if not self.entries:
if self.journal:
- os.unlink(self.journal)
+ util.unlink(self.journal)
return
self.report(_("transaction abort!\n"))
@@ -169,7 +173,10 @@
def rollback(opener, file, report):
entries = []
- for l in open(file).readlines():
+ fp = util.posixfile(file)
+ lines = fp.readlines()
+ fp.close()
+ for l in lines:
f, o = l.split('\0')
entries.append((f, int(o), None))
--- a/mercurial/ui.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/ui.py Wed Feb 16 14:13:22 2011 -0600
@@ -153,6 +153,16 @@
"%s.%s = %s\n") % (section, name, uvalue))
return value
+ def configpath(self, section, name, default=None, untrusted=False):
+ 'get a path config item, expanded relative to config file'
+ v = self.config(section, name, default, untrusted)
+ if not os.path.isabs(v) or "://" not in v:
+ src = self.configsource(section, name, untrusted)
+ if ':' in src:
+ base = os.path.dirname(src.rsplit(':'))
+ v = os.path.join(base, os.path.expanduser(v))
+ return v
+
def configbool(self, section, name, default=False, untrusted=False):
v = self.config(section, name, None, untrusted)
if v is None:
@@ -589,7 +599,7 @@
termination.
'''
- if pos == None or not self.debugflag:
+ if pos is None or not self.debugflag:
return
if unit:
--- a/mercurial/url.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/url.py Wed Feb 16 14:13:22 2011 -0600
@@ -71,6 +71,38 @@
return userpass + '@' + hostport
return hostport
+def readauthforuri(ui, uri):
+ # Read configuration
+ config = dict()
+ for key, val in ui.configitems('auth'):
+ if '.' not in key:
+ ui.warn(_("ignoring invalid [auth] key '%s'\n") % key)
+ continue
+ group, setting = key.rsplit('.', 1)
+ gdict = config.setdefault(group, dict())
+ if setting in ('username', 'cert', 'key'):
+ val = util.expandpath(val)
+ gdict[setting] = val
+
+ # Find the best match
+ scheme, hostpath = uri.split('://', 1)
+ bestlen = 0
+ bestauth = None
+ for group, auth in config.iteritems():
+ prefix = auth.get('prefix')
+ if not prefix:
+ continue
+ p = prefix.split('://', 1)
+ if len(p) > 1:
+ schemes, prefix = [p[0]], p[1]
+ else:
+ schemes = (auth.get('schemes') or 'https').split()
+ if (prefix == '*' or hostpath.startswith(prefix)) and \
+ len(prefix) > bestlen and scheme in schemes:
+ bestlen = len(prefix)
+ bestauth = group, auth
+ return bestauth
+
_safe = ('abcdefghijklmnopqrstuvwxyz'
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
'0123456789' '_.-/')
@@ -123,9 +155,11 @@
return (user, passwd)
if not user:
- auth = self.readauthtoken(authuri)
- if auth:
+ res = readauthforuri(self.ui, authuri)
+ if res:
+ group, auth = res
user, passwd = auth.get('username'), auth.get('password')
+ self.ui.debug("using auth.%s.* for authentication\n" % group)
if not user or not passwd:
if not self.ui.interactive():
raise util.Abort(_('http authorization required'))
@@ -148,38 +182,6 @@
msg = _('http auth: user %s, password %s\n')
self.ui.debug(msg % (user, passwd and '*' * len(passwd) or 'not set'))
- def readauthtoken(self, uri):
- # Read configuration
- config = dict()
- for key, val in self.ui.configitems('auth'):
- if '.' not in key:
- self.ui.warn(_("ignoring invalid [auth] key '%s'\n") % key)
- continue
- group, setting = key.split('.', 1)
- gdict = config.setdefault(group, dict())
- if setting in ('username', 'cert', 'key'):
- val = util.expandpath(val)
- gdict[setting] = val
-
- # Find the best match
- scheme, hostpath = uri.split('://', 1)
- bestlen = 0
- bestauth = None
- for auth in config.itervalues():
- prefix = auth.get('prefix')
- if not prefix:
- continue
- p = prefix.split('://', 1)
- if len(p) > 1:
- schemes, prefix = [p[0]], p[1]
- else:
- schemes = (auth.get('schemes') or 'https').split()
- if (prefix == '*' or hostpath.startswith(prefix)) and \
- len(prefix) > bestlen and scheme in schemes:
- bestlen = len(prefix)
- bestauth = auth
- return bestauth
-
class proxyhandler(urllib2.ProxyHandler):
def __init__(self, ui):
proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy')
@@ -258,29 +260,47 @@
defines a __len__ attribute to feed the Content-Length header.
"""
- def __init__(self, *args, **kwargs):
+ def __init__(self, ui, *args, **kwargs):
# We can't just "self._data = open(*args, **kwargs)" here because there
# is an "open" function defined in this module that shadows the global
# one
+ self.ui = ui
self._data = __builtin__.open(*args, **kwargs)
- self.read = self._data.read
self.seek = self._data.seek
self.close = self._data.close
self.write = self._data.write
+ self._len = os.fstat(self._data.fileno()).st_size
+ self._pos = 0
+ self._total = len(self) / 1024 * 2
+
+ def read(self, *args, **kwargs):
+ try:
+ ret = self._data.read(*args, **kwargs)
+ except EOFError:
+ self.ui.progress(_('sending'), None)
+ self._pos += len(ret)
+ # We pass double the max for total because we currently have
+ # to send the bundle twice in the case of a server that
+ # requires authentication. Since we can't know until we try
+ # once whether authentication will be required, just lie to
+ # the user and maybe the push succeeds suddenly at 50%.
+ self.ui.progress(_('sending'), self._pos / 1024,
+ unit=_('kb'), total=self._total)
+ return ret
def __len__(self):
- return os.fstat(self._data.fileno()).st_size
+ return self._len
-def _gen_sendfile(connection):
+def _gen_sendfile(orgsend):
def _sendfile(self, data):
# send a file
if isinstance(data, httpsendfile):
# if auth required, some data sent twice, so rewind here
data.seek(0)
for chunk in util.filechunkiter(data):
- connection.send(self, chunk)
+ orgsend(self, chunk)
else:
- connection.send(self, data)
+ orgsend(self, data)
return _sendfile
has_https = hasattr(urllib2, 'HTTPSHandler')
@@ -333,7 +353,7 @@
class httpconnection(keepalive.HTTPConnection):
# must be able to send big bundle as stream.
- send = _gen_sendfile(keepalive.HTTPConnection)
+ send = _gen_sendfile(keepalive.HTTPConnection.send)
def connect(self):
if has_https and self.realhostport: # use CONNECT proxy
@@ -522,32 +542,36 @@
return _('no commonName or subjectAltName found in certificate')
if has_https:
- class BetterHTTPS(httplib.HTTPSConnection):
- send = keepalive.safesend
+ class httpsconnection(httplib.HTTPSConnection):
+ response_class = keepalive.HTTPResponse
+ # must be able to send big bundle as stream.
+ send = _gen_sendfile(keepalive.safesend)
+ getresponse = keepalive.wrapgetresponse(httplib.HTTPSConnection)
def connect(self):
- if hasattr(self, 'ui'):
- cacerts = self.ui.config('web', 'cacerts')
- if cacerts:
- cacerts = util.expandpath(cacerts)
- else:
- cacerts = None
+ self.sock = _create_connection((self.host, self.port))
+
+ host = self.host
+ if self.realhostport: # use CONNECT proxy
+ something = _generic_proxytunnel(self)
+ host = self.realhostport.rsplit(':', 1)[0]
- hostfingerprint = self.ui.config('hostfingerprints', self.host)
+ cacerts = self.ui.config('web', 'cacerts')
+ hostfingerprint = self.ui.config('hostfingerprints', host)
+
if cacerts and not hostfingerprint:
- sock = _create_connection((self.host, self.port))
- self.sock = _ssl_wrap_socket(sock, self.key_file,
- self.cert_file, cert_reqs=CERT_REQUIRED,
- ca_certs=cacerts)
- msg = _verifycert(self.sock.getpeercert(), self.host)
+ self.sock = _ssl_wrap_socket(self.sock, self.key_file,
+ self.cert_file, cert_reqs=CERT_REQUIRED,
+ ca_certs=util.expandpath(cacerts))
+ msg = _verifycert(self.sock.getpeercert(), host)
if msg:
raise util.Abort(_('%s certificate error: %s '
'(use --insecure to connect '
- 'insecurely)') % (self.host, msg))
- self.ui.debug('%s certificate successfully verified\n' %
- self.host)
+ 'insecurely)') % (host, msg))
+ self.ui.debug('%s certificate successfully verified\n' % host)
else:
- httplib.HTTPSConnection.connect(self)
+ self.sock = _ssl_wrap_socket(self.sock, self.key_file,
+ self.cert_file)
if hasattr(self.sock, 'getpeercert'):
peercert = self.sock.getpeercert(True)
peerfingerprint = util.sha1(peercert).hexdigest()
@@ -558,38 +582,22 @@
hostfingerprint.replace(':', '').lower():
raise util.Abort(_('invalid certificate for %s '
'with fingerprint %s') %
- (self.host, nicefingerprint))
+ (host, nicefingerprint))
self.ui.debug('%s certificate matched fingerprint %s\n' %
- (self.host, nicefingerprint))
+ (host, nicefingerprint))
else:
self.ui.warn(_('warning: %s certificate '
'with fingerprint %s not verified '
'(check hostfingerprints or web.cacerts '
'config setting)\n') %
- (self.host, nicefingerprint))
+ (host, nicefingerprint))
else: # python 2.5 ?
if hostfingerprint:
- raise util.Abort(_('no certificate for %s '
- 'with fingerprint') % self.host)
+ raise util.Abort(_('no certificate for %s with '
+ 'configured hostfingerprint') % host)
self.ui.warn(_('warning: %s certificate not verified '
'(check web.cacerts config setting)\n') %
- self.host)
-
- class httpsconnection(BetterHTTPS):
- response_class = keepalive.HTTPResponse
- # must be able to send big bundle as stream.
- send = _gen_sendfile(BetterHTTPS)
- getresponse = keepalive.wrapgetresponse(httplib.HTTPSConnection)
-
- def connect(self):
- if self.realhostport: # use CONNECT proxy
- self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- self.sock.connect((self.host, self.port))
- if _generic_proxytunnel(self):
- self.sock = _ssl_wrap_socket(self.sock, self.key_file,
- self.cert_file)
- else:
- BetterHTTPS.connect(self)
+ host)
class httpshandler(keepalive.KeepAliveHandler, urllib2.HTTPSHandler):
def __init__(self, ui):
@@ -603,7 +611,13 @@
return keepalive.KeepAliveHandler._start_transaction(self, h, req)
def https_open(self, req):
- self.auth = self.pwmgr.readauthtoken(req.get_full_url())
+ res = readauthforuri(self.ui, req.get_full_url())
+ if res:
+ group, auth = res
+ self.auth = auth
+ self.ui.debug("using auth.%s.* for authentication\n" % group)
+ else:
+ self.auth = None
return self.do_open(self._makeconnection, req)
def _makeconnection(self, host, port=None, *args, **kwargs):
--- a/mercurial/util.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/util.py Wed Feb 16 14:13:22 2011 -0600
@@ -198,7 +198,10 @@
if code:
raise Abort(_("command '%s' failed: %s") %
(cmd, explain_exit(code)))
- return open(outname, 'rb').read()
+ fp = open(outname, 'rb')
+ r = fp.read()
+ fp.close()
+ return r
finally:
try:
if inname:
@@ -431,7 +434,7 @@
return check
-def unlink(f):
+def unlinkpath(f):
"""unlink and remove the directory if it is empty"""
os.unlink(f)
# try removing directories that might now be empty
@@ -451,7 +454,7 @@
else:
try:
shutil.copyfile(src, dest)
- shutil.copystat(src, dest)
+ shutil.copymode(src, dest)
except shutil.Error, inst:
raise Abort(str(inst))
@@ -487,6 +490,7 @@
'''ensure that a filesystem path contains no banned components.
the following properties of a path are checked:
+ - ends with a directory separator
- under top-level .hg
- starts at the root of a windows drive
- contains ".."
@@ -504,6 +508,9 @@
def __call__(self, path):
if path in self.audited:
return
+ # AIX ignores "/" at end of path, others raise EISDIR.
+ if endswithsep(path):
+ raise Abort(_("path ends in directory separator: %s") % path)
normpath = os.path.normcase(path)
parts = splitpath(normpath)
if (os.path.splitdrive(path)[0]
@@ -550,16 +557,6 @@
# want to add "foo/bar/baz" before checking if there's a "foo/.hg"
self.auditeddir.update(prefixes)
-def nlinks(pathname):
- """Return number of hardlinks for the given file."""
- return os.lstat(pathname).st_nlink
-
-if hasattr(os, 'link'):
- os_link = os.link
-else:
- def os_link(src, dst):
- raise OSError(0, _("Hardlinks not supported"))
-
def lookup_reg(key, name=None, scope=None):
return None
@@ -597,7 +594,10 @@
raise
except AttributeError: # no symlink in os
pass
- return posixfile(pathname).read()
+ fp = posixfile(pathname)
+ r = fp.read()
+ fp.close()
+ return r
def fstat(fp):
'''stat file object that may not have fileno method.'''
@@ -738,7 +738,7 @@
# nlinks() may behave differently for files on Windows shares if
# the file is open.
- fd = open(f2)
+ fd = posixfile(f2)
return nlinks(f2) > 1
finally:
if fd is not None:
@@ -837,7 +837,7 @@
self._fp.close()
rename(self.temp, localpath(self.__name))
- def __del__(self):
+ def close(self):
if not self._fp:
return
if not self._fp.closed:
@@ -846,6 +846,9 @@
except: pass
self._fp.close()
+ def __del__(self):
+ self.close()
+
def makedirs(name, mode=None):
"""recursive directory creation with parent mode inheritance"""
parent = os.path.abspath(os.path.dirname(name))
@@ -894,7 +897,6 @@
mode += "b" # for that other OS
nlink = -1
- st_mode = None
dirname, basename = os.path.split(f)
# If basename is empty, then the path is malformed because it points
# to a directory. Let the posixfile() call below raise IOError.
@@ -905,18 +907,19 @@
return atomictempfile(f, mode, self.createmode)
try:
if 'w' in mode:
- st_mode = os.lstat(f).st_mode & 0777
- os.unlink(f)
+ unlink(f)
nlink = 0
else:
# nlinks() may behave differently for files on Windows
# shares if the file is open.
- fd = open(f)
+ fd = posixfile(f)
nlink = nlinks(f)
if nlink < 1:
nlink = 2 # force mktempcopy (issue1922)
fd.close()
- except (OSError, IOError):
+ except (OSError, IOError), e:
+ if e.errno != errno.ENOENT:
+ raise
nlink = 0
if not os.path.isdir(dirname):
makedirs(dirname, self.createmode)
@@ -927,10 +930,7 @@
rename(mktempcopy(f), f)
fp = posixfile(f, mode)
if nlink == 0:
- if st_mode is None:
- self._fixfilemode(f)
- else:
- os.chmod(f, st_mode)
+ self._fixfilemode(f)
return fp
def symlink(self, src, dst):
@@ -1075,7 +1075,7 @@
# NOTE: unixtime = localunixtime + offset
offset, date = timezone(string), string
- if offset != None:
+ if offset is not None:
date = " ".join(string.split()[:-1])
# add missing elements from defaults
@@ -1120,7 +1120,7 @@
now = makedate()
defaults = {}
nowmap = {}
- for part in "d mb yY HI M S".split():
+ for part in ("d", "mb", "yY", "HI", "M", "S"):
# this piece is for rounding the specific end of unknowns
b = bias.get(part)
if b is None:
@@ -1190,7 +1190,7 @@
def upper(date):
d = dict(mb="12", HI="23", M="59", S="59")
- for days in "31 30 29".split():
+ for days in ("31", "30", "29"):
try:
d["d"] = days
return parsedate(date, extendeddateformats, d)[0]
@@ -1387,37 +1387,48 @@
# Avoid double backslash in Windows path repr()
return repr(s).replace('\\\\', '\\')
-#### naming convention of below implementation follows 'textwrap' module
+# delay import of textwrap
+def MBTextWrapper(**kwargs):
+ class tw(textwrap.TextWrapper):
+ """
+ Extend TextWrapper for double-width characters.
-class MBTextWrapper(textwrap.TextWrapper):
- def __init__(self, **kwargs):
- textwrap.TextWrapper.__init__(self, **kwargs)
+ Some Asian characters use two terminal columns instead of one.
+ A good example of this behavior can be seen with u'\u65e5\u672c',
+ the two Japanese characters for "Japan":
+ len() returns 2, but when printed to a terminal, they eat 4 columns.
+
+ (Note that this has nothing to do whatsoever with unicode
+ representation, or encoding of the underlying string)
+ """
+ def __init__(self, **kwargs):
+ textwrap.TextWrapper.__init__(self, **kwargs)
- def _cutdown(self, str, space_left):
- l = 0
- ucstr = unicode(str, encoding.encoding)
- w = unicodedata.east_asian_width
- for i in xrange(len(ucstr)):
- l += w(ucstr[i]) in 'WFA' and 2 or 1
- if space_left < l:
- return (ucstr[:i].encode(encoding.encoding),
- ucstr[i:].encode(encoding.encoding))
- return str, ''
+ def _cutdown(self, str, space_left):
+ l = 0
+ ucstr = unicode(str, encoding.encoding)
+ colwidth = unicodedata.east_asian_width
+ for i in xrange(len(ucstr)):
+ l += colwidth(ucstr[i]) in 'WFA' and 2 or 1
+ if space_left < l:
+ return (ucstr[:i].encode(encoding.encoding),
+ ucstr[i:].encode(encoding.encoding))
+ return str, ''
- # ----------------------------------------
- # overriding of base class
-
- def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width):
- space_left = max(width - cur_len, 1)
+ # overriding of base class
+ def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width):
+ space_left = max(width - cur_len, 1)
- if self.break_long_words:
- cut, res = self._cutdown(reversed_chunks[-1], space_left)
- cur_line.append(cut)
- reversed_chunks[-1] = res
- elif not cur_line:
- cur_line.append(reversed_chunks.pop())
+ if self.break_long_words:
+ cut, res = self._cutdown(reversed_chunks[-1], space_left)
+ cur_line.append(cut)
+ reversed_chunks[-1] = res
+ elif not cur_line:
+ cur_line.append(reversed_chunks.pop())
-#### naming convention of above implementation follows 'textwrap' module
+ global MBTextWrapper
+ MBTextWrapper = tw
+ return tw(**kwargs)
def wrap(line, width, initindent='', hangindent=''):
maxindent = max(len(hangindent), len(initindent))
@@ -1497,7 +1508,7 @@
return False
return True
-def interpolate(prefix, mapping, s, fn=None):
+def interpolate(prefix, mapping, s, fn=None, escape_prefix=False):
"""Return the result of interpolating items in the mapping into string s.
prefix is a single character string, or a two character string with
@@ -1506,9 +1517,20 @@
fn is an optional function that will be applied to the replacement text
just before replacement.
+
+ escape_prefix is an optional flag that allows using doubled prefix for
+ its escaping.
"""
fn = fn or (lambda s: s)
- r = re.compile(r'%s(%s)' % (prefix, '|'.join(mapping.keys())))
+ patterns = '|'.join(mapping.keys())
+ if escape_prefix:
+ patterns += '|' + prefix
+ if len(prefix) > 1:
+ prefix_char = prefix[1:]
+ else:
+ prefix_char = prefix
+ mapping[prefix_char] = prefix_char
+ r = re.compile(r'%s(%s)' % (prefix, patterns))
return r.sub(lambda x: fn(mapping[x.group()[1:]]), s)
def getport(port):
--- a/mercurial/verify.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/verify.py Wed Feb 16 14:13:22 2011 -0600
@@ -34,7 +34,7 @@
raise util.Abort(_("cannot verify bundle or remote repos"))
def err(linkrev, msg, filename=None):
- if linkrev != None:
+ if linkrev is not None:
badrevs.add(linkrev)
else:
linkrev = '?'
--- a/mercurial/win32.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/win32.py Wed Feb 16 14:13:22 2011 -0600
@@ -5,73 +5,173 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-"""Utility functions that use win32 API.
+import encoding
+import ctypes, errno, os, struct, subprocess
+
+_kernel32 = ctypes.windll.kernel32
+
+_BOOL = ctypes.c_long
+_WORD = ctypes.c_ushort
+_DWORD = ctypes.c_ulong
+_LPCSTR = _LPSTR = ctypes.c_char_p
+_HANDLE = ctypes.c_void_p
+_HWND = _HANDLE
+
+_INVALID_HANDLE_VALUE = -1
+
+# GetLastError
+_ERROR_SUCCESS = 0
+_ERROR_INVALID_PARAMETER = 87
+_ERROR_INSUFFICIENT_BUFFER = 122
+
+# WPARAM is defined as UINT_PTR (unsigned type)
+# LPARAM is defined as LONG_PTR (signed type)
+if ctypes.sizeof(ctypes.c_long) == ctypes.sizeof(ctypes.c_void_p):
+ _WPARAM = ctypes.c_ulong
+ _LPARAM = ctypes.c_long
+elif ctypes.sizeof(ctypes.c_longlong) == ctypes.sizeof(ctypes.c_void_p):
+ _WPARAM = ctypes.c_ulonglong
+ _LPARAM = ctypes.c_longlong
+
+class _FILETIME(ctypes.Structure):
+ _fields_ = [('dwLowDateTime', _DWORD),
+ ('dwHighDateTime', _DWORD)]
+
+class _BY_HANDLE_FILE_INFORMATION(ctypes.Structure):
+ _fields_ = [('dwFileAttributes', _DWORD),
+ ('ftCreationTime', _FILETIME),
+ ('ftLastAccessTime', _FILETIME),
+ ('ftLastWriteTime', _FILETIME),
+ ('dwVolumeSerialNumber', _DWORD),
+ ('nFileSizeHigh', _DWORD),
+ ('nFileSizeLow', _DWORD),
+ ('nNumberOfLinks', _DWORD),
+ ('nFileIndexHigh', _DWORD),
+ ('nFileIndexLow', _DWORD)]
+
+# CreateFile
+_FILE_SHARE_READ = 0x00000001
+_FILE_SHARE_WRITE = 0x00000002
+_FILE_SHARE_DELETE = 0x00000004
+
+_OPEN_EXISTING = 3
+
+# Process Security and Access Rights
+_PROCESS_QUERY_INFORMATION = 0x0400
+
+# GetExitCodeProcess
+_STILL_ACTIVE = 259
+
+# registry
+_HKEY_CURRENT_USER = 0x80000001L
+_HKEY_LOCAL_MACHINE = 0x80000002L
+_KEY_READ = 0x20019
+_REG_SZ = 1
+_REG_DWORD = 4
-Mark Hammond's win32all package allows better functionality on
-Windows. This module overrides definitions in util.py. If not
-available, import of this module will fail, and generic code will be
-used.
-"""
+class _STARTUPINFO(ctypes.Structure):
+ _fields_ = [('cb', _DWORD),
+ ('lpReserved', _LPSTR),
+ ('lpDesktop', _LPSTR),
+ ('lpTitle', _LPSTR),
+ ('dwX', _DWORD),
+ ('dwY', _DWORD),
+ ('dwXSize', _DWORD),
+ ('dwYSize', _DWORD),
+ ('dwXCountChars', _DWORD),
+ ('dwYCountChars', _DWORD),
+ ('dwFillAttribute', _DWORD),
+ ('dwFlags', _DWORD),
+ ('wShowWindow', _WORD),
+ ('cbReserved2', _WORD),
+ ('lpReserved2', ctypes.c_char_p),
+ ('hStdInput', _HANDLE),
+ ('hStdOutput', _HANDLE),
+ ('hStdError', _HANDLE)]
+
+class _PROCESS_INFORMATION(ctypes.Structure):
+ _fields_ = [('hProcess', _HANDLE),
+ ('hThread', _HANDLE),
+ ('dwProcessId', _DWORD),
+ ('dwThreadId', _DWORD)]
+
+_DETACHED_PROCESS = 0x00000008
+_STARTF_USESHOWWINDOW = 0x00000001
+_SW_HIDE = 0
-import win32api
+class _COORD(ctypes.Structure):
+ _fields_ = [('X', ctypes.c_short),
+ ('Y', ctypes.c_short)]
+
+class _SMALL_RECT(ctypes.Structure):
+ _fields_ = [('Left', ctypes.c_short),
+ ('Top', ctypes.c_short),
+ ('Right', ctypes.c_short),
+ ('Bottom', ctypes.c_short)]
+
+class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
+ _fields_ = [('dwSize', _COORD),
+ ('dwCursorPosition', _COORD),
+ ('wAttributes', _WORD),
+ ('srWindow', _SMALL_RECT),
+ ('dwMaximumWindowSize', _COORD)]
-import errno, os, sys, pywintypes, win32con, win32file, win32process
-import winerror, win32gui, win32console
-import osutil, encoding
-from win32com.shell import shell, shellcon
+_STD_ERROR_HANDLE = 0xfffffff4L # (DWORD)-12
+
+def _raiseoserror(name):
+ err = ctypes.WinError()
+ raise OSError(err.errno, '%s: %s' % (name, err.strerror))
+
+def _getfileinfo(name):
+ fh = _kernel32.CreateFileA(name, 0,
+ _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
+ None, _OPEN_EXISTING, 0, None)
+ if fh == _INVALID_HANDLE_VALUE:
+ _raiseoserror(name)
+ try:
+ fi = _BY_HANDLE_FILE_INFORMATION()
+ if not _kernel32.GetFileInformationByHandle(fh, ctypes.byref(fi)):
+ _raiseoserror(name)
+ return fi
+ finally:
+ _kernel32.CloseHandle(fh)
def os_link(src, dst):
- try:
- win32file.CreateHardLink(dst, src)
- except pywintypes.error:
- raise OSError(errno.EINVAL, 'target implements hardlinks improperly')
- except NotImplementedError: # Another fake error win Win98
- raise OSError(errno.EINVAL, 'Hardlinking not supported')
+ if not _kernel32.CreateHardLinkA(dst, src, None):
+ _raiseoserror(src)
-def _getfileinfo(pathname):
- """Return number of hardlinks for the given file."""
- try:
- fh = win32file.CreateFile(pathname,
- win32file.GENERIC_READ, win32file.FILE_SHARE_READ,
- None, win32file.OPEN_EXISTING, 0, None)
- except pywintypes.error:
- raise OSError(errno.ENOENT, 'The system cannot find the file specified')
- try:
- return win32file.GetFileInformationByHandle(fh)
- finally:
- fh.Close()
-
-def nlinks(pathname):
- """Return number of hardlinks for the given file."""
- return _getfileinfo(pathname)[7]
+def nlinks(name):
+ '''return number of hardlinks for the given file'''
+ return _getfileinfo(name).nNumberOfLinks
def samefile(fpath1, fpath2):
- """Returns whether fpath1 and fpath2 refer to the same file. This is only
- guaranteed to work for files, not directories."""
+ '''Returns whether fpath1 and fpath2 refer to the same file. This is only
+ guaranteed to work for files, not directories.'''
res1 = _getfileinfo(fpath1)
res2 = _getfileinfo(fpath2)
- # Index 4 is the volume serial number, and 8 and 9 contain the file ID
- return res1[4] == res2[4] and res1[8] == res2[8] and res1[9] == res2[9]
+ return (res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
+ and res1.nFileIndexHigh == res2.nFileIndexHigh
+ and res1.nFileIndexLow == res2.nFileIndexLow)
def samedevice(fpath1, fpath2):
- """Returns whether fpath1 and fpath2 are on the same device. This is only
- guaranteed to work for files, not directories."""
+ '''Returns whether fpath1 and fpath2 are on the same device. This is only
+ guaranteed to work for files, not directories.'''
res1 = _getfileinfo(fpath1)
res2 = _getfileinfo(fpath2)
- return res1[4] == res2[4]
+ return res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
def testpid(pid):
'''return True if pid is still running or unable to
determine, False otherwise'''
- try:
- handle = win32api.OpenProcess(
- win32con.PROCESS_QUERY_INFORMATION, False, pid)
- if handle:
- status = win32process.GetExitCodeProcess(handle)
- return status == win32con.STILL_ACTIVE
- except pywintypes.error, details:
- return details[0] != winerror.ERROR_INVALID_PARAMETER
- return True
+ h = _kernel32.OpenProcess(_PROCESS_QUERY_INFORMATION, False, pid)
+ if h:
+ try:
+ status = _DWORD()
+ if _kernel32.GetExitCodeProcess(h, ctypes.byref(status)):
+ return status.value == _STILL_ACTIVE
+ finally:
+ _kernel32.CloseHandle(h)
+ return _kernel32.GetLastError() != _ERROR_INVALID_PARAMETER
def lookup_reg(key, valname=None, scope=None):
''' Look up a key/value name in the Windows registry.
@@ -82,101 +182,137 @@
a sequence of scopes to look up in order. Default (CURRENT_USER,
LOCAL_MACHINE).
'''
- try:
- from _winreg import HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, \
- QueryValueEx, OpenKey
- except ImportError:
- return None
-
+ adv = ctypes.windll.advapi32
+ byref = ctypes.byref
if scope is None:
- scope = (HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE)
+ scope = (_HKEY_CURRENT_USER, _HKEY_LOCAL_MACHINE)
elif not isinstance(scope, (list, tuple)):
scope = (scope,)
for s in scope:
+ kh = _HANDLE()
+ res = adv.RegOpenKeyExA(s, key, 0, _KEY_READ, ctypes.byref(kh))
+ if res != _ERROR_SUCCESS:
+ continue
try:
- val = QueryValueEx(OpenKey(s, key), valname)[0]
- # never let a Unicode string escape into the wild
- return encoding.tolocal(val.encode('UTF-8'))
- except EnvironmentError:
- pass
+ size = _DWORD(600)
+ type = _DWORD()
+ buf = ctypes.create_string_buffer(size.value + 1)
+ res = adv.RegQueryValueExA(kh.value, valname, None,
+ byref(type), buf, byref(size))
+ if res != _ERROR_SUCCESS:
+ continue
+ if type.value == _REG_SZ:
+ # never let a Unicode string escape into the wild
+ return encoding.tolocal(buf.value.encode('UTF-8'))
+ elif type.value == _REG_DWORD:
+ fmt = '<L'
+ s = ctypes.string_at(byref(buf), struct.calcsize(fmt))
+ return struct.unpack(fmt, s)[0]
+ finally:
+ adv.RegCloseKey(kh.value)
-def system_rcpath_win32():
- '''return default os-specific hgrc search path'''
- filename = win32api.GetModuleFileName(0)
- # Use mercurial.ini found in directory with hg.exe
- progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
- if os.path.isfile(progrc):
- return [progrc]
- # Use hgrc.d found in directory with hg.exe
- progrcd = os.path.join(os.path.dirname(filename), 'hgrc.d')
- if os.path.isdir(progrcd):
- rcpath = []
- for f, kind in osutil.listdir(progrcd):
- if f.endswith('.rc'):
- rcpath.append(os.path.join(progrcd, f))
- return rcpath
- # else look for a system rcpath in the registry
- try:
- value = win32api.RegQueryValue(
- win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Mercurial')
- rcpath = []
- for p in value.split(os.pathsep):
- if p.lower().endswith('mercurial.ini'):
- rcpath.append(p)
- elif os.path.isdir(p):
- for f, kind in osutil.listdir(p):
- if f.endswith('.rc'):
- rcpath.append(os.path.join(p, f))
- return rcpath
- except pywintypes.error:
- return []
-
-def user_rcpath_win32():
- '''return os-specific hgrc search path to the user dir'''
- userdir = os.path.expanduser('~')
- if sys.getwindowsversion()[3] != 2 and userdir == '~':
- # We are on win < nt: fetch the APPDATA directory location and use
- # the parent directory as the user home dir.
- appdir = shell.SHGetPathFromIDList(
- shell.SHGetSpecialFolderLocation(0, shellcon.CSIDL_APPDATA))
- userdir = os.path.dirname(appdir)
- return [os.path.join(userdir, 'mercurial.ini'),
- os.path.join(userdir, '.hgrc')]
+def executable_path():
+ '''return full path of hg.exe'''
+ size = 600
+ buf = ctypes.create_string_buffer(size + 1)
+ len = _kernel32.GetModuleFileNameA(None, ctypes.byref(buf), size)
+ if len == 0:
+ raise ctypes.WinError()
+ elif len == size:
+ raise ctypes.WinError(_ERROR_INSUFFICIENT_BUFFER)
+ return buf.value
def getuser():
'''return name of current user'''
- return win32api.GetUserName()
+ adv = ctypes.windll.advapi32
+ size = _DWORD(300)
+ buf = ctypes.create_string_buffer(size.value + 1)
+ if not adv.GetUserNameA(ctypes.byref(buf), ctypes.byref(size)):
+ raise ctypes.WinError()
+ return buf.value
-def set_signal_handler_win32():
- """Register a termination handler for console events including
+_SIGNAL_HANDLER = ctypes.WINFUNCTYPE(_BOOL, _DWORD)
+_signal_handler = []
+
+def set_signal_handler():
+ '''Register a termination handler for console events including
CTRL+C. python signal handlers do not work well with socket
operations.
- """
+ '''
def handler(event):
- win32process.ExitProcess(1)
- win32api.SetConsoleCtrlHandler(handler)
+ _kernel32.ExitProcess(1)
+
+ if _signal_handler:
+ return # already registered
+ h = _SIGNAL_HANDLER(handler)
+ _signal_handler.append(h) # needed to prevent garbage collection
+ if not _kernel32.SetConsoleCtrlHandler(h, True):
+ raise ctypes.WinError()
+
+_WNDENUMPROC = ctypes.WINFUNCTYPE(_BOOL, _HWND, _LPARAM)
def hidewindow():
- def callback(*args, **kwargs):
- hwnd, pid = args
- wpid = win32process.GetWindowThreadProcessId(hwnd)[1]
- if pid == wpid:
- win32gui.ShowWindow(hwnd, win32con.SW_HIDE)
+ user32 = ctypes.windll.user32
- pid = win32process.GetCurrentProcessId()
- win32gui.EnumWindows(callback, pid)
+ def callback(hwnd, pid):
+ wpid = _DWORD()
+ user32.GetWindowThreadProcessId(hwnd, ctypes.byref(wpid))
+ if pid == wpid.value:
+ user32.ShowWindow(hwnd, _SW_HIDE)
+ return False # stop enumerating windows
+ return True
+
+ pid = _kernel32.GetCurrentProcessId()
+ user32.EnumWindows(_WNDENUMPROC(callback), pid)
def termwidth():
- try:
- # Query stderr to avoid problems with redirections
- screenbuf = win32console.GetStdHandle(win32console.STD_ERROR_HANDLE)
- if screenbuf is None:
- return 79
- try:
- window = screenbuf.GetConsoleScreenBufferInfo()['Window']
- width = window.Right - window.Left
- return width
- finally:
- screenbuf.Detach()
- except pywintypes.error:
- return 79
+ # cmd.exe does not handle CR like a unix console, the CR is
+ # counted in the line length. On 80 columns consoles, if 80
+ # characters are written, the following CR won't apply on the
+ # current line but on the new one. Keep room for it.
+ width = 79
+ # Query stderr to avoid problems with redirections
+ screenbuf = _kernel32.GetStdHandle(
+ _STD_ERROR_HANDLE) # don't close the handle returned
+ if screenbuf is None or screenbuf == _INVALID_HANDLE_VALUE:
+ return width
+ csbi = _CONSOLE_SCREEN_BUFFER_INFO()
+ if not _kernel32.GetConsoleScreenBufferInfo(
+ screenbuf, ctypes.byref(csbi)):
+ return width
+ width = csbi.srWindow.Right - csbi.srWindow.Left
+ return width
+
+def spawndetached(args):
+ # No standard library function really spawns a fully detached
+ # process under win32 because they allocate pipes or other objects
+ # to handle standard streams communications. Passing these objects
+ # to the child process requires handle inheritance to be enabled
+ # which makes really detached processes impossible.
+ si = _STARTUPINFO()
+ si.cb = ctypes.sizeof(_STARTUPINFO)
+ si.dwFlags = _STARTF_USESHOWWINDOW
+ si.wShowWindow = _SW_HIDE
+
+ pi = _PROCESS_INFORMATION()
+
+ env = ''
+ for k in os.environ:
+ env += "%s=%s\0" % (k, os.environ[k])
+ if not env:
+ env = '\0'
+ env += '\0'
+
+ args = subprocess.list2cmdline(args)
+ # Not running the command in shell mode makes python26 hang when
+ # writing to hgweb output socket.
+ comspec = os.environ.get("COMSPEC", "cmd.exe")
+ args = comspec + " /c " + args
+
+ res = _kernel32.CreateProcessA(
+ None, args, None, None, False, _DETACHED_PROCESS,
+ env, os.getcwd(), ctypes.byref(si), ctypes.byref(pi))
+ if not res:
+ raise ctypes.WinError()
+
+ return pi.dwProcessId
--- a/mercurial/windows.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/windows.py Wed Feb 16 14:13:22 2011 -0600
@@ -71,22 +71,45 @@
return 'command' in os.environ.get('comspec', '')
def openhardlinks():
- return not _is_win_9x() and "win32api" in globals()
+ return not _is_win_9x()
+
+_HKEY_LOCAL_MACHINE = 0x80000002L
def system_rcpath():
- try:
- return system_rcpath_win32()
- except:
- return [r'c:\mercurial\mercurial.ini']
+ '''return default os-specific hgrc search path'''
+ rcpath = []
+ filename = executable_path()
+ # Use mercurial.ini found in directory with hg.exe
+ progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
+ if os.path.isfile(progrc):
+ rcpath.append(progrc)
+ return rcpath
+ # Use hgrc.d found in directory with hg.exe
+ progrcd = os.path.join(os.path.dirname(filename), 'hgrc.d')
+ if os.path.isdir(progrcd):
+ for f, kind in osutil.listdir(progrcd):
+ if f.endswith('.rc'):
+ rcpath.append(os.path.join(progrcd, f))
+ return rcpath
+ # else look for a system rcpath in the registry
+ value = lookup_reg('SOFTWARE\\Mercurial', None, _HKEY_LOCAL_MACHINE)
+ if not isinstance(value, str) or not value:
+ return rcpath
+ value = value.replace('/', os.sep)
+ for p in value.split(os.pathsep):
+ if p.lower().endswith('mercurial.ini'):
+ rcpath.append(p)
+ elif os.path.isdir(p):
+ for f, kind in osutil.listdir(p):
+ if f.endswith('.rc'):
+ rcpath.append(os.path.join(p, f))
+ return rcpath
def user_rcpath():
'''return os-specific hgrc search path to the user dir'''
- try:
- path = user_rcpath_win32()
- except:
- home = os.path.expanduser('~')
- path = [os.path.join(home, 'mercurial.ini'),
- os.path.join(home, '.hgrc')]
+ home = os.path.expanduser('~')
+ path = [os.path.join(home, 'mercurial.ini'),
+ os.path.join(home, '.hgrc')]
userprofile = os.environ.get('USERPROFILE')
if userprofile:
path.append(os.path.join(userprofile, 'mercurial.ini'))
@@ -106,10 +129,6 @@
args = user and ("%s@%s" % (user, host)) or host
return port and ("%s %s %s" % (args, pflag, port)) or args
-def testpid(pid):
- '''return False if pid dead, True if running or not known'''
- return True
-
def set_flags(f, l, x):
pass
@@ -208,12 +227,6 @@
return executable
return findexisting(os.path.expanduser(os.path.expandvars(command)))
-def set_signal_handler():
- try:
- set_signal_handler_win32()
- except NameError:
- pass
-
def statfiles(files):
'''Stat each file in files and yield stat or None if file does not exist.
Cluster and cache stat per directory to minimize number of OS stat calls.'''
@@ -241,11 +254,6 @@
cache = dircache.setdefault(dir, dmap)
yield cache.get(base, None)
-def getuser():
- '''return name of current user'''
- raise error.Abort(_('user name not available - set USERNAME '
- 'environment variable'))
-
def username(uid=None):
"""Return the name of the user with the given uid.
@@ -276,7 +284,7 @@
break
head, tail = os.path.split(head)
-def unlink(f):
+def unlinkpath(f):
"""unlink and remove the directory if it is empty"""
os.unlink(f)
# try removing directories that might now be empty
@@ -285,73 +293,56 @@
except OSError:
pass
+def unlink(f):
+ '''try to implement POSIX' unlink semantics on Windows'''
+
+ # POSIX allows to unlink and rename open files. Windows has serious
+ # problems with doing that:
+ # - Calling os.unlink (or os.rename) on a file f fails if f or any
+ # hardlinked copy of f has been opened with Python's open(). There is no
+ # way such a file can be deleted or renamed on Windows (other than
+ # scheduling the delete or rename for the next reboot).
+ # - Calling os.unlink on a file that has been opened with Mercurial's
+ # posixfile (or comparable methods) will delay the actual deletion of
+ # the file for as long as the file is held open. The filename is blocked
+ # during that time and cannot be used for recreating a new file under
+ # that same name ("zombie file"). Directories containing such zombie files
+ # cannot be removed or moved.
+ # A file that has been opened with posixfile can be renamed, so we rename
+ # f to a random temporary name before calling os.unlink on it. This allows
+ # callers to recreate f immediately while having other readers do their
+ # implicit zombie filename blocking on a temporary name.
+
+ for tries in xrange(10):
+ temp = '%s-%08x' % (f, random.randint(0, 0xffffffff))
+ try:
+ os.rename(f, temp) # raises OSError EEXIST if temp exists
+ break
+ except OSError, e:
+ if e.errno != errno.EEXIST:
+ raise
+ else:
+ raise IOError, (errno.EEXIST, "No usable temporary filename found")
+
+ try:
+ os.unlink(temp)
+ except:
+ # Some very rude AV-scanners on Windows may cause this unlink to fail.
+ # Not aborting here just leaks the temp file, whereas aborting at this
+ # point may leave serious inconsistencies. Ideally, we would notify
+ # the user in this case here.
+ pass
+
def rename(src, dst):
'''atomically rename file src to dst, replacing dst if it exists'''
try:
os.rename(src, dst)
- except OSError: # FIXME: check err (EEXIST ?)
-
- # On windows, rename to existing file is not allowed, so we
- # must delete destination first. But if a file is open, unlink
- # schedules it for delete but does not delete it. Rename
- # happens immediately even for open files, so we rename
- # destination to a temporary name, then delete that. Then
- # rename is safe to do.
- # The temporary name is chosen at random to avoid the situation
- # where a file is left lying around from a previous aborted run.
-
- for tries in xrange(10):
- temp = '%s-%08x' % (dst, random.randint(0, 0xffffffff))
- try:
- os.rename(dst, temp) # raises OSError EEXIST if temp exists
- break
- except OSError, e:
- if e.errno != errno.EEXIST:
- raise
- else:
- raise IOError, (errno.EEXIST, "No usable temporary filename found")
-
- try:
- os.unlink(temp)
- except:
- # Some rude AV-scanners on Windows may cause the unlink to
- # fail. Not aborting here just leaks the temp file, whereas
- # aborting at this point may leave serious inconsistencies.
- # Ideally, we would notify the user here.
- pass
+ except OSError, e:
+ if e.errno != errno.EEXIST:
+ raise
+ unlink(dst)
os.rename(src, dst)
-def spawndetached(args):
- # No standard library function really spawns a fully detached
- # process under win32 because they allocate pipes or other objects
- # to handle standard streams communications. Passing these objects
- # to the child process requires handle inheritance to be enabled
- # which makes really detached processes impossible.
- class STARTUPINFO:
- dwFlags = subprocess.STARTF_USESHOWWINDOW
- hStdInput = None
- hStdOutput = None
- hStdError = None
- wShowWindow = subprocess.SW_HIDE
-
- args = subprocess.list2cmdline(args)
- # Not running the command in shell mode makes python26 hang when
- # writing to hgweb output socket.
- comspec = os.environ.get("COMSPEC", "cmd.exe")
- args = comspec + " /c " + args
- hp, ht, pid, tid = subprocess.CreateProcess(
- None, args,
- # no special security
- None, None,
- # Do not inherit handles
- 0,
- # DETACHED_PROCESS
- 0x00000008,
- os.environ,
- os.getcwd(),
- STARTUPINFO())
- return pid
-
def gethgcmd():
return [sys.executable] + sys.argv[:1]
@@ -366,10 +357,6 @@
# Don't support groups on Windows for now
raise KeyError()
-try:
- # override functions with win32 versions if possible
- from win32 import *
-except ImportError:
- pass
+from win32 import *
expandglobs = True
--- a/mercurial/wireproto.py Sat Feb 12 16:08:41 2011 +0800
+++ b/mercurial/wireproto.py Wed Feb 16 14:13:22 2011 -0600
@@ -25,7 +25,7 @@
class wirerepository(repo.repository):
def lookup(self, key):
self.requirecap('lookup', _('look up remote revision'))
- d = self._call("lookup", key=key)
+ d = self._call("lookup", key=encoding.fromlocal(key))
success, data = d[:-1].split(" ", 1)
if int(success):
return bin(data)
@@ -44,14 +44,7 @@
branchmap = {}
for branchpart in d.splitlines():
branchname, branchheads = branchpart.split(' ', 1)
- branchname = urllib.unquote(branchname)
- # Earlier servers (1.3.x) send branch names in (their) local
- # charset. The best we can do is assume it's identical to our
- # own local charset, in case it's not utf-8.
- try:
- branchname.decode('utf-8')
- except UnicodeDecodeError:
- branchname = encoding.fromlocal(branchname)
+ branchname = encoding.tolocal(urllib.unquote(branchname))
branchheads = decodelist(branchheads)
branchmap[branchname] = branchheads
return branchmap
@@ -83,17 +76,20 @@
if not self.capable('pushkey'):
return False
d = self._call("pushkey",
- namespace=namespace, key=key, old=old, new=new)
+ namespace=encoding.fromlocal(namespace),
+ key=encoding.fromlocal(key),
+ old=encoding.fromlocal(old),
+ new=encoding.fromlocal(new))
return bool(int(d))
def listkeys(self, namespace):
if not self.capable('pushkey'):
return {}
- d = self._call("listkeys", namespace=namespace)
+ d = self._call("listkeys", namespace=encoding.fromlocal(namespace))
r = {}
for l in d.splitlines():
k, v = l.split('\t')
- r[k.decode('string-escape')] = v.decode('string-escape')
+ r[encoding.tolocal(k)] = encoding.tolocal(v)
return r
def stream_out(self):
@@ -162,7 +158,7 @@
branchmap = repo.branchmap()
heads = []
for branch, nodes in branchmap.iteritems():
- branchname = urllib.quote(branch)
+ branchname = urllib.quote(encoding.fromlocal(branch))
branchnodes = encodelist(nodes)
heads.append('%s %s' % (branchname, branchnodes))
return '\n'.join(heads)
@@ -213,14 +209,14 @@
return "capabilities: %s\n" % (capabilities(repo, proto))
def listkeys(repo, proto, namespace):
- d = pushkeymod.list(repo, namespace).items()
- t = '\n'.join(['%s\t%s' % (k.encode('string-escape'),
- v.encode('string-escape')) for k, v in d])
+ d = pushkeymod.list(repo, encoding.tolocal(namespace)).items()
+ t = '\n'.join(['%s\t%s' % (encoding.fromlocal(k), encoding.fromlocal(v))
+ for k, v in d])
return t
def lookup(repo, proto, key):
try:
- r = hex(repo.lookup(key))
+ r = hex(repo.lookup(encoding.tolocal(key)))
success = 1
except Exception, inst:
r = str(inst)
@@ -228,7 +224,21 @@
return "%s %s\n" % (success, r)
def pushkey(repo, proto, namespace, key, old, new):
- r = pushkeymod.push(repo, namespace, key, old, new)
+ # compatibility with pre-1.8 clients which were accidentally
+ # sending raw binary nodes rather than utf-8-encoded hex
+ if len(new) == 20 and new.encode('string-escape') != new:
+ # looks like it could be a binary node
+ try:
+ u = new.decode('utf-8')
+ new = encoding.tolocal(new) # but cleanly decodes as UTF-8
+ except UnicodeDecodeError:
+ pass # binary, leave unmodified
+ else:
+ new = encoding.tolocal(new) # normal path
+
+ r = pushkeymod.push(repo,
+ encoding.tolocal(namespace), encoding.tolocal(key),
+ encoding.tolocal(old), new)
return '%s\n' % int(r)
def _allowstream(ui):
--- a/setup.py Sat Feb 12 16:08:41 2011 +0800
+++ b/setup.py Wed Feb 16 14:13:22 2011 -0600
@@ -294,14 +294,18 @@
libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
for outfile in self.outfiles:
- data = open(outfile, 'rb').read()
+ fp = open(outfile, 'rb')
+ data = fp.read()
+ fp.close()
# skip binary files
if '\0' in data:
continue
data = data.replace('@LIBDIR@', libdir.encode('string_escape'))
- open(outfile, 'wb').write(data)
+ fp = open(outfile, 'wb')
+ fp.write(data)
+ fp.close()
cmdclass = {'build_mo': hgbuildmo,
'build_ext': hgbuildext,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/cgienv Wed Feb 16 14:13:22 2011 -0600
@@ -0,0 +1,29 @@
+DOCUMENT_ROOT="/var/www/hg"; export DOCUMENT_ROOT
+GATEWAY_INTERFACE="CGI/1.1"; export GATEWAY_INTERFACE
+HTTP_ACCEPT="text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"; export HTTP_ACCEPT
+HTTP_ACCEPT_CHARSET="ISO-8859-1,utf-8;q=0.7,*;q=0.7"; export HTTP_ACCEPT_CHARSET
+HTTP_ACCEPT_ENCODING="gzip,deflate"; export HTTP_ACCEPT_ENCODING
+HTTP_ACCEPT_LANGUAGE="en-us,en;q=0.5"; export HTTP_ACCEPT_LANGUAGE
+HTTP_CACHE_CONTROL="max-age=0"; export HTTP_CACHE_CONTROL
+HTTP_CONNECTION="keep-alive"; export HTTP_CONNECTION
+HTTP_HOST="hg.omnifarious.org"; export HTTP_HOST
+HTTP_KEEP_ALIVE="300"; export HTTP_KEEP_ALIVE
+HTTP_USER_AGENT="Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.0.4) Gecko/20060608 Ubuntu/dapper-security Firefox/1.5.0.4"; export HTTP_USER_AGENT
+PATH_INFO="/"; export PATH_INFO
+PATH_TRANSLATED="/var/www/hg/index.html"; export PATH_TRANSLATED
+QUERY_STRING=""; export QUERY_STRING
+REMOTE_ADDR="127.0.0.2"; export REMOTE_ADDR
+REMOTE_PORT="44703"; export REMOTE_PORT
+REQUEST_METHOD="GET"; export REQUEST_METHOD
+REQUEST_URI="/test/"; export REQUEST_URI
+SCRIPT_FILENAME="/home/hopper/hg_public/test.cgi"; export SCRIPT_FILENAME
+SCRIPT_NAME="/test"; export SCRIPT_NAME
+SCRIPT_URI="http://hg.omnifarious.org/test/"; export SCRIPT_URI
+SCRIPT_URL="/test/"; export SCRIPT_URL
+SERVER_ADDR="127.0.0.1"; export SERVER_ADDR
+SERVER_ADMIN="eric@localhost"; export SERVER_ADMIN
+SERVER_NAME="hg.omnifarious.org"; export SERVER_NAME
+SERVER_PORT="80"; export SERVER_PORT
+SERVER_PROTOCOL="HTTP/1.1"; export SERVER_PROTOCOL
+SERVER_SIGNATURE="<address>Apache/2.0.53 (Fedora) Server at hg.omnifarious.org Port 80</address>"; export SERVER_SIGNATURE
+SERVER_SOFTWARE="Apache/2.0.53 (Fedora)"; export SERVER_SOFTWARE
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/filtercr.py Wed Feb 16 14:13:22 2011 -0600
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+
+# Filter output by the progress extension to make it readable in tests
+
+import sys, re
+
+for line in sys.stdin:
+ line = re.sub(r'\r+[^\n]', lambda m: '\n' + m.group()[-1:], line)
+ sys.stdout.write(line)
+print
--- a/tests/hghave Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/hghave Wed Feb 16 14:13:22 2011 -0600
@@ -101,15 +101,6 @@
def has_fifo():
return hasattr(os, "mkfifo")
-def has_hotshot():
- try:
- # hotshot.stats tests hotshot and many problematic dependencies
- # like profile.
- import hotshot.stats
- return True
- except ImportError:
- return False
-
def has_lsprof():
try:
import _lsprof
@@ -182,6 +173,8 @@
def has_ssl():
try:
import ssl
+ import OpenSSL
+ OpenSSL.SSL.Context
return True
except ImportError:
return False
@@ -198,7 +191,6 @@
"fifo": (has_fifo, "named pipes"),
"git": (has_git, "git command line client"),
"gpg": (has_gpg, "gpg client"),
- "hotshot": (has_hotshot, "python hotshot module"),
"icasefs": (has_icasefs, "case insensitive file system"),
"inotify": (has_inotify, "inotify extension support"),
"lsprof": (has_lsprof, "python lsprof module"),
--- a/tests/printenv.py Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/printenv.py Wed Feb 16 14:13:22 2011 -0600
@@ -1,12 +1,9 @@
# simple script to be used in hooks
-# copy it to the current directory when the test starts:
-#
-# cp "$TESTDIR"/printenv.py .
#
# put something like this in the repo .hg/hgrc:
#
# [hooks]
-# changegroup = python ../printenv.py <hookname> [exit] [output]
+# changegroup = python "$TESTDIR"/printenv.py <hookname> [exit] [output]
#
# - <hookname> is a mandatory argument (e.g. "changegroup")
# - [exit] is the exit code of the hook (default: 0)
@@ -39,13 +36,6 @@
if k.startswith("HG_") and v]
env.sort()
-# edit the variable part of the variable
-url = os.environ.get("HG_URL", "")
-if url.startswith("file:"):
- os.environ["HG_URL"] = "file:"
-elif url.startswith("remote:http"):
- os.environ["HG_URL"] = "remote:http"
-
out.write("%s hook: " % name)
for v in env:
out.write("%s=%s " % (v, os.environ[v]))
--- a/tests/run-tests.py Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/run-tests.py Wed Feb 16 14:13:22 2011 -0600
@@ -231,6 +231,8 @@
if line and not line.startswith('#'):
blacklist[line] = filename
+ f.close()
+
options.blacklist = blacklist
return (options, args)
@@ -491,6 +493,8 @@
# non-command/result - queue up for merged output
after.setdefault(pos, []).append(l)
+ t.close()
+
script.append('echo %s %s $?\n' % (salt, n + 1))
fd, name = tempfile.mkstemp(suffix='hg-tst')
@@ -504,7 +508,8 @@
vlog("# Running", cmd)
exitcode, output = run(cmd, options, replacements)
# do not merge output if skipped, return hghave message instead
- if exitcode == SKIPPED_STATUS:
+ # similarly, with --debug, output is None
+ if exitcode == SKIPPED_STATUS or output is None:
return exitcode, output
finally:
os.remove(name)
@@ -579,6 +584,7 @@
return exitcode, postout
+wifexited = getattr(os, "WIFEXITED", lambda x: False)
def run(cmd, options, replacements):
"""Run command in a sub-process, capturing the output (stdout and stderr).
Return a tuple (exitcode, output). output is None in debug mode."""
@@ -593,7 +599,7 @@
tochild.close()
output = fromchild.read()
ret = fromchild.close()
- if ret == None:
+ if ret is None:
ret = 0
else:
proc = Popen4(cmd)
@@ -610,7 +616,7 @@
proc.tochild.close()
output = proc.fromchild.read()
ret = proc.wait()
- if os.WIFEXITED(ret):
+ if wifexited(ret):
ret = os.WEXITSTATUS(ret)
except Timeout:
vlog('# Process %d timed out - killing it' % proc.pid)
@@ -713,7 +719,7 @@
# If we're not in --debug mode and reference output file exists,
# check test output against it.
if options.debug:
- refout = None # to match out == None
+ refout = None # to match "out is None"
elif os.path.exists(ref):
f = open(ref, "r")
refout = splitnewlines(f.read())
@@ -925,7 +931,9 @@
continue
if options.keywords:
- t = open(test).read().lower() + test.lower()
+ fp = open(test)
+ t = fp.read().lower() + test.lower()
+ fp.close()
for k in options.keywords.lower().split():
if k in t:
break
@@ -1108,4 +1116,5 @@
time.sleep(1)
cleanup(options)
-main()
+if __name__ == '__main__':
+ main()
--- a/tests/test-acl.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-acl.t Wed Feb 16 14:13:22 2011 -0600
@@ -90,38 +90,38 @@
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
adding changesets
- bundling changes: 0 chunks
- bundling changes: 1 chunks
- bundling changes: 2 chunks
- bundling changes: 3 chunks
- bundling changes: 4 chunks
- bundling changes: 5 chunks
- bundling changes: 6 chunks
- bundling changes: 7 chunks
- bundling changes: 8 chunks
- bundling changes: 9 chunks
- bundling manifests: 0 chunks
- bundling manifests: 1 chunks
- bundling manifests: 2 chunks
- bundling manifests: 3 chunks
- bundling manifests: 4 chunks
- bundling manifests: 5 chunks
- bundling manifests: 6 chunks
- bundling manifests: 7 chunks
- bundling manifests: 8 chunks
- bundling manifests: 9 chunks
- bundling files: foo/Bar/file.txt 0 chunks
- bundling files: foo/Bar/file.txt 1 chunks
- bundling files: foo/Bar/file.txt 2 chunks
- bundling files: foo/Bar/file.txt 3 chunks
- bundling files: foo/file.txt 4 chunks
- bundling files: foo/file.txt 5 chunks
- bundling files: foo/file.txt 6 chunks
- bundling files: foo/file.txt 7 chunks
- bundling files: quux/file.py 8 chunks
- bundling files: quux/file.py 9 chunks
- bundling files: quux/file.py 10 chunks
- bundling files: quux/file.py 11 chunks
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 3 changesets
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
changesets: 1 chunks
add changeset ef1ea85a6374
changesets: 2 chunks
@@ -141,6 +141,7 @@
files: 3/3 chunks (100.00%)
added 3 changesets with 3 changes to 3 files
updating the branch cache
+ checking for updated bookmarks
rolling back to revision 0 (undo push)
0:6675d58eff77
@@ -166,38 +167,38 @@
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
adding changesets
- bundling changes: 0 chunks
- bundling changes: 1 chunks
- bundling changes: 2 chunks
- bundling changes: 3 chunks
- bundling changes: 4 chunks
- bundling changes: 5 chunks
- bundling changes: 6 chunks
- bundling changes: 7 chunks
- bundling changes: 8 chunks
- bundling changes: 9 chunks
- bundling manifests: 0 chunks
- bundling manifests: 1 chunks
- bundling manifests: 2 chunks
- bundling manifests: 3 chunks
- bundling manifests: 4 chunks
- bundling manifests: 5 chunks
- bundling manifests: 6 chunks
- bundling manifests: 7 chunks
- bundling manifests: 8 chunks
- bundling manifests: 9 chunks
- bundling files: foo/Bar/file.txt 0 chunks
- bundling files: foo/Bar/file.txt 1 chunks
- bundling files: foo/Bar/file.txt 2 chunks
- bundling files: foo/Bar/file.txt 3 chunks
- bundling files: foo/file.txt 4 chunks
- bundling files: foo/file.txt 5 chunks
- bundling files: foo/file.txt 6 chunks
- bundling files: foo/file.txt 7 chunks
- bundling files: quux/file.py 8 chunks
- bundling files: quux/file.py 9 chunks
- bundling files: quux/file.py 10 chunks
- bundling files: quux/file.py 11 chunks
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 3 changesets
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
changesets: 1 chunks
add changeset ef1ea85a6374
changesets: 2 chunks
@@ -219,6 +220,7 @@
calling hook pretxnchangegroup.acl: hgext.acl.hook
acl: changes have source "push" - skipping
updating the branch cache
+ checking for updated bookmarks
rolling back to revision 0 (undo push)
0:6675d58eff77
@@ -245,38 +247,38 @@
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
adding changesets
- bundling changes: 0 chunks
- bundling changes: 1 chunks
- bundling changes: 2 chunks
- bundling changes: 3 chunks
- bundling changes: 4 chunks
- bundling changes: 5 chunks
- bundling changes: 6 chunks
- bundling changes: 7 chunks
- bundling changes: 8 chunks
- bundling changes: 9 chunks
- bundling manifests: 0 chunks
- bundling manifests: 1 chunks
- bundling manifests: 2 chunks
- bundling manifests: 3 chunks
- bundling manifests: 4 chunks
- bundling manifests: 5 chunks
- bundling manifests: 6 chunks
- bundling manifests: 7 chunks
- bundling manifests: 8 chunks
- bundling manifests: 9 chunks
- bundling files: foo/Bar/file.txt 0 chunks
- bundling files: foo/Bar/file.txt 1 chunks
- bundling files: foo/Bar/file.txt 2 chunks
- bundling files: foo/Bar/file.txt 3 chunks
- bundling files: foo/file.txt 4 chunks
- bundling files: foo/file.txt 5 chunks
- bundling files: foo/file.txt 6 chunks
- bundling files: foo/file.txt 7 chunks
- bundling files: quux/file.py 8 chunks
- bundling files: quux/file.py 9 chunks
- bundling files: quux/file.py 10 chunks
- bundling files: quux/file.py 11 chunks
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 3 changesets
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
changesets: 1 chunks
add changeset ef1ea85a6374
changesets: 2 chunks
@@ -307,6 +309,7 @@
acl: branch access granted: "911600dab2ae" on branch "default"
acl: allowing changeset 911600dab2ae
updating the branch cache
+ checking for updated bookmarks
rolling back to revision 0 (undo push)
0:6675d58eff77
@@ -333,38 +336,38 @@
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
adding changesets
- bundling changes: 0 chunks
- bundling changes: 1 chunks
- bundling changes: 2 chunks
- bundling changes: 3 chunks
- bundling changes: 4 chunks
- bundling changes: 5 chunks
- bundling changes: 6 chunks
- bundling changes: 7 chunks
- bundling changes: 8 chunks
- bundling changes: 9 chunks
- bundling manifests: 0 chunks
- bundling manifests: 1 chunks
- bundling manifests: 2 chunks
- bundling manifests: 3 chunks
- bundling manifests: 4 chunks
- bundling manifests: 5 chunks
- bundling manifests: 6 chunks
- bundling manifests: 7 chunks
- bundling manifests: 8 chunks
- bundling manifests: 9 chunks
- bundling files: foo/Bar/file.txt 0 chunks
- bundling files: foo/Bar/file.txt 1 chunks
- bundling files: foo/Bar/file.txt 2 chunks
- bundling files: foo/Bar/file.txt 3 chunks
- bundling files: foo/file.txt 4 chunks
- bundling files: foo/file.txt 5 chunks
- bundling files: foo/file.txt 6 chunks
- bundling files: foo/file.txt 7 chunks
- bundling files: quux/file.py 8 chunks
- bundling files: quux/file.py 9 chunks
- bundling files: quux/file.py 10 chunks
- bundling files: quux/file.py 11 chunks
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 3 changesets
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
changesets: 1 chunks
add changeset ef1ea85a6374
changesets: 2 chunks
@@ -420,38 +423,38 @@
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
adding changesets
- bundling changes: 0 chunks
- bundling changes: 1 chunks
- bundling changes: 2 chunks
- bundling changes: 3 chunks
- bundling changes: 4 chunks
- bundling changes: 5 chunks
- bundling changes: 6 chunks
- bundling changes: 7 chunks
- bundling changes: 8 chunks
- bundling changes: 9 chunks
- bundling manifests: 0 chunks
- bundling manifests: 1 chunks
- bundling manifests: 2 chunks
- bundling manifests: 3 chunks
- bundling manifests: 4 chunks
- bundling manifests: 5 chunks
- bundling manifests: 6 chunks
- bundling manifests: 7 chunks
- bundling manifests: 8 chunks
- bundling manifests: 9 chunks
- bundling files: foo/Bar/file.txt 0 chunks
- bundling files: foo/Bar/file.txt 1 chunks
- bundling files: foo/Bar/file.txt 2 chunks
- bundling files: foo/Bar/file.txt 3 chunks
- bundling files: foo/file.txt 4 chunks
- bundling files: foo/file.txt 5 chunks
- bundling files: foo/file.txt 6 chunks
- bundling files: foo/file.txt 7 chunks
- bundling files: quux/file.py 8 chunks
- bundling files: quux/file.py 9 chunks
- bundling files: quux/file.py 10 chunks
- bundling files: quux/file.py 11 chunks
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 3 changesets
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
changesets: 1 chunks
add changeset ef1ea85a6374
changesets: 2 chunks
@@ -512,38 +515,38 @@
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
adding changesets
- bundling changes: 0 chunks
- bundling changes: 1 chunks
- bundling changes: 2 chunks
- bundling changes: 3 chunks
- bundling changes: 4 chunks
- bundling changes: 5 chunks
- bundling changes: 6 chunks
- bundling changes: 7 chunks
- bundling changes: 8 chunks
- bundling changes: 9 chunks
- bundling manifests: 0 chunks
- bundling manifests: 1 chunks
- bundling manifests: 2 chunks
- bundling manifests: 3 chunks
- bundling manifests: 4 chunks
- bundling manifests: 5 chunks
- bundling manifests: 6 chunks
- bundling manifests: 7 chunks
- bundling manifests: 8 chunks
- bundling manifests: 9 chunks
- bundling files: foo/Bar/file.txt 0 chunks
- bundling files: foo/Bar/file.txt 1 chunks
- bundling files: foo/Bar/file.txt 2 chunks
- bundling files: foo/Bar/file.txt 3 chunks
- bundling files: foo/file.txt 4 chunks
- bundling files: foo/file.txt 5 chunks
- bundling files: foo/file.txt 6 chunks
- bundling files: foo/file.txt 7 chunks
- bundling files: quux/file.py 8 chunks
- bundling files: quux/file.py 9 chunks
- bundling files: quux/file.py 10 chunks
- bundling files: quux/file.py 11 chunks
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 3 changesets
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
changesets: 1 chunks
add changeset ef1ea85a6374
changesets: 2 chunks
@@ -601,38 +604,38 @@
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
adding changesets
- bundling changes: 0 chunks
- bundling changes: 1 chunks
- bundling changes: 2 chunks
- bundling changes: 3 chunks
- bundling changes: 4 chunks
- bundling changes: 5 chunks
- bundling changes: 6 chunks
- bundling changes: 7 chunks
- bundling changes: 8 chunks
- bundling changes: 9 chunks
- bundling manifests: 0 chunks
- bundling manifests: 1 chunks
- bundling manifests: 2 chunks
- bundling manifests: 3 chunks
- bundling manifests: 4 chunks
- bundling manifests: 5 chunks
- bundling manifests: 6 chunks
- bundling manifests: 7 chunks
- bundling manifests: 8 chunks
- bundling manifests: 9 chunks
- bundling files: foo/Bar/file.txt 0 chunks
- bundling files: foo/Bar/file.txt 1 chunks
- bundling files: foo/Bar/file.txt 2 chunks
- bundling files: foo/Bar/file.txt 3 chunks
- bundling files: foo/file.txt 4 chunks
- bundling files: foo/file.txt 5 chunks
- bundling files: foo/file.txt 6 chunks
- bundling files: foo/file.txt 7 chunks
- bundling files: quux/file.py 8 chunks
- bundling files: quux/file.py 9 chunks
- bundling files: quux/file.py 10 chunks
- bundling files: quux/file.py 11 chunks
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 3 changesets
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
changesets: 1 chunks
add changeset ef1ea85a6374
changesets: 2 chunks
@@ -695,38 +698,38 @@
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
adding changesets
- bundling changes: 0 chunks
- bundling changes: 1 chunks
- bundling changes: 2 chunks
- bundling changes: 3 chunks
- bundling changes: 4 chunks
- bundling changes: 5 chunks
- bundling changes: 6 chunks
- bundling changes: 7 chunks
- bundling changes: 8 chunks
- bundling changes: 9 chunks
- bundling manifests: 0 chunks
- bundling manifests: 1 chunks
- bundling manifests: 2 chunks
- bundling manifests: 3 chunks
- bundling manifests: 4 chunks
- bundling manifests: 5 chunks
- bundling manifests: 6 chunks
- bundling manifests: 7 chunks
- bundling manifests: 8 chunks
- bundling manifests: 9 chunks
- bundling files: foo/Bar/file.txt 0 chunks
- bundling files: foo/Bar/file.txt 1 chunks
- bundling files: foo/Bar/file.txt 2 chunks
- bundling files: foo/Bar/file.txt 3 chunks
- bundling files: foo/file.txt 4 chunks
- bundling files: foo/file.txt 5 chunks
- bundling files: foo/file.txt 6 chunks
- bundling files: foo/file.txt 7 chunks
- bundling files: quux/file.py 8 chunks
- bundling files: quux/file.py 9 chunks
- bundling files: quux/file.py 10 chunks
- bundling files: quux/file.py 11 chunks
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 3 changesets
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
changesets: 1 chunks
add changeset ef1ea85a6374
changesets: 2 chunks
@@ -786,38 +789,38 @@
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
adding changesets
- bundling changes: 0 chunks
- bundling changes: 1 chunks
- bundling changes: 2 chunks
- bundling changes: 3 chunks
- bundling changes: 4 chunks
- bundling changes: 5 chunks
- bundling changes: 6 chunks
- bundling changes: 7 chunks
- bundling changes: 8 chunks
- bundling changes: 9 chunks
- bundling manifests: 0 chunks
- bundling manifests: 1 chunks
- bundling manifests: 2 chunks
- bundling manifests: 3 chunks
- bundling manifests: 4 chunks
- bundling manifests: 5 chunks
- bundling manifests: 6 chunks
- bundling manifests: 7 chunks
- bundling manifests: 8 chunks
- bundling manifests: 9 chunks
- bundling files: foo/Bar/file.txt 0 chunks
- bundling files: foo/Bar/file.txt 1 chunks
- bundling files: foo/Bar/file.txt 2 chunks
- bundling files: foo/Bar/file.txt 3 chunks
- bundling files: foo/file.txt 4 chunks
- bundling files: foo/file.txt 5 chunks
- bundling files: foo/file.txt 6 chunks
- bundling files: foo/file.txt 7 chunks
- bundling files: quux/file.py 8 chunks
- bundling files: quux/file.py 9 chunks
- bundling files: quux/file.py 10 chunks
- bundling files: quux/file.py 11 chunks
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 3 changesets
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
changesets: 1 chunks
add changeset ef1ea85a6374
changesets: 2 chunks
@@ -879,38 +882,38 @@
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
adding changesets
- bundling changes: 0 chunks
- bundling changes: 1 chunks
- bundling changes: 2 chunks
- bundling changes: 3 chunks
- bundling changes: 4 chunks
- bundling changes: 5 chunks
- bundling changes: 6 chunks
- bundling changes: 7 chunks
- bundling changes: 8 chunks
- bundling changes: 9 chunks
- bundling manifests: 0 chunks
- bundling manifests: 1 chunks
- bundling manifests: 2 chunks
- bundling manifests: 3 chunks
- bundling manifests: 4 chunks
- bundling manifests: 5 chunks
- bundling manifests: 6 chunks
- bundling manifests: 7 chunks
- bundling manifests: 8 chunks
- bundling manifests: 9 chunks
- bundling files: foo/Bar/file.txt 0 chunks
- bundling files: foo/Bar/file.txt 1 chunks
- bundling files: foo/Bar/file.txt 2 chunks
- bundling files: foo/Bar/file.txt 3 chunks
- bundling files: foo/file.txt 4 chunks
- bundling files: foo/file.txt 5 chunks
- bundling files: foo/file.txt 6 chunks
- bundling files: foo/file.txt 7 chunks
- bundling files: quux/file.py 8 chunks
- bundling files: quux/file.py 9 chunks
- bundling files: quux/file.py 10 chunks
- bundling files: quux/file.py 11 chunks
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 3 changesets
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
changesets: 1 chunks
add changeset ef1ea85a6374
changesets: 2 chunks
@@ -941,6 +944,7 @@
acl: branch access granted: "911600dab2ae" on branch "default"
acl: allowing changeset 911600dab2ae
updating the branch cache
+ checking for updated bookmarks
rolling back to revision 0 (undo push)
0:6675d58eff77
@@ -974,38 +978,38 @@
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
adding changesets
- bundling changes: 0 chunks
- bundling changes: 1 chunks
- bundling changes: 2 chunks
- bundling changes: 3 chunks
- bundling changes: 4 chunks
- bundling changes: 5 chunks
- bundling changes: 6 chunks
- bundling changes: 7 chunks
- bundling changes: 8 chunks
- bundling changes: 9 chunks
- bundling manifests: 0 chunks
- bundling manifests: 1 chunks
- bundling manifests: 2 chunks
- bundling manifests: 3 chunks
- bundling manifests: 4 chunks
- bundling manifests: 5 chunks
- bundling manifests: 6 chunks
- bundling manifests: 7 chunks
- bundling manifests: 8 chunks
- bundling manifests: 9 chunks
- bundling files: foo/Bar/file.txt 0 chunks
- bundling files: foo/Bar/file.txt 1 chunks
- bundling files: foo/Bar/file.txt 2 chunks
- bundling files: foo/Bar/file.txt 3 chunks
- bundling files: foo/file.txt 4 chunks
- bundling files: foo/file.txt 5 chunks
- bundling files: foo/file.txt 6 chunks
- bundling files: foo/file.txt 7 chunks
- bundling files: quux/file.py 8 chunks
- bundling files: quux/file.py 9 chunks
- bundling files: quux/file.py 10 chunks
- bundling files: quux/file.py 11 chunks
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 3 changesets
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
changesets: 1 chunks
add changeset ef1ea85a6374
changesets: 2 chunks
@@ -1074,38 +1078,38 @@
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
adding changesets
- bundling changes: 0 chunks
- bundling changes: 1 chunks
- bundling changes: 2 chunks
- bundling changes: 3 chunks
- bundling changes: 4 chunks
- bundling changes: 5 chunks
- bundling changes: 6 chunks
- bundling changes: 7 chunks
- bundling changes: 8 chunks
- bundling changes: 9 chunks
- bundling manifests: 0 chunks
- bundling manifests: 1 chunks
- bundling manifests: 2 chunks
- bundling manifests: 3 chunks
- bundling manifests: 4 chunks
- bundling manifests: 5 chunks
- bundling manifests: 6 chunks
- bundling manifests: 7 chunks
- bundling manifests: 8 chunks
- bundling manifests: 9 chunks
- bundling files: foo/Bar/file.txt 0 chunks
- bundling files: foo/Bar/file.txt 1 chunks
- bundling files: foo/Bar/file.txt 2 chunks
- bundling files: foo/Bar/file.txt 3 chunks
- bundling files: foo/file.txt 4 chunks
- bundling files: foo/file.txt 5 chunks
- bundling files: foo/file.txt 6 chunks
- bundling files: foo/file.txt 7 chunks
- bundling files: quux/file.py 8 chunks
- bundling files: quux/file.py 9 chunks
- bundling files: quux/file.py 10 chunks
- bundling files: quux/file.py 11 chunks
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 3 changesets
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
changesets: 1 chunks
add changeset ef1ea85a6374
changesets: 2 chunks
@@ -1168,38 +1172,38 @@
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
adding changesets
- bundling changes: 0 chunks
- bundling changes: 1 chunks
- bundling changes: 2 chunks
- bundling changes: 3 chunks
- bundling changes: 4 chunks
- bundling changes: 5 chunks
- bundling changes: 6 chunks
- bundling changes: 7 chunks
- bundling changes: 8 chunks
- bundling changes: 9 chunks
- bundling manifests: 0 chunks
- bundling manifests: 1 chunks
- bundling manifests: 2 chunks
- bundling manifests: 3 chunks
- bundling manifests: 4 chunks
- bundling manifests: 5 chunks
- bundling manifests: 6 chunks
- bundling manifests: 7 chunks
- bundling manifests: 8 chunks
- bundling manifests: 9 chunks
- bundling files: foo/Bar/file.txt 0 chunks
- bundling files: foo/Bar/file.txt 1 chunks
- bundling files: foo/Bar/file.txt 2 chunks
- bundling files: foo/Bar/file.txt 3 chunks
- bundling files: foo/file.txt 4 chunks
- bundling files: foo/file.txt 5 chunks
- bundling files: foo/file.txt 6 chunks
- bundling files: foo/file.txt 7 chunks
- bundling files: quux/file.py 8 chunks
- bundling files: quux/file.py 9 chunks
- bundling files: quux/file.py 10 chunks
- bundling files: quux/file.py 11 chunks
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 3 changesets
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
changesets: 1 chunks
add changeset ef1ea85a6374
changesets: 2 chunks
@@ -1274,38 +1278,38 @@
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
adding changesets
- bundling changes: 0 chunks
- bundling changes: 1 chunks
- bundling changes: 2 chunks
- bundling changes: 3 chunks
- bundling changes: 4 chunks
- bundling changes: 5 chunks
- bundling changes: 6 chunks
- bundling changes: 7 chunks
- bundling changes: 8 chunks
- bundling changes: 9 chunks
- bundling manifests: 0 chunks
- bundling manifests: 1 chunks
- bundling manifests: 2 chunks
- bundling manifests: 3 chunks
- bundling manifests: 4 chunks
- bundling manifests: 5 chunks
- bundling manifests: 6 chunks
- bundling manifests: 7 chunks
- bundling manifests: 8 chunks
- bundling manifests: 9 chunks
- bundling files: foo/Bar/file.txt 0 chunks
- bundling files: foo/Bar/file.txt 1 chunks
- bundling files: foo/Bar/file.txt 2 chunks
- bundling files: foo/Bar/file.txt 3 chunks
- bundling files: foo/file.txt 4 chunks
- bundling files: foo/file.txt 5 chunks
- bundling files: foo/file.txt 6 chunks
- bundling files: foo/file.txt 7 chunks
- bundling files: quux/file.py 8 chunks
- bundling files: quux/file.py 9 chunks
- bundling files: quux/file.py 10 chunks
- bundling files: quux/file.py 11 chunks
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 3 changesets
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
changesets: 1 chunks
add changeset ef1ea85a6374
changesets: 2 chunks
@@ -1336,6 +1340,7 @@
acl: branch access granted: "911600dab2ae" on branch "default"
acl: allowing changeset 911600dab2ae
updating the branch cache
+ checking for updated bookmarks
rolling back to revision 0 (undo push)
0:6675d58eff77
@@ -1370,38 +1375,38 @@
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
adding changesets
- bundling changes: 0 chunks
- bundling changes: 1 chunks
- bundling changes: 2 chunks
- bundling changes: 3 chunks
- bundling changes: 4 chunks
- bundling changes: 5 chunks
- bundling changes: 6 chunks
- bundling changes: 7 chunks
- bundling changes: 8 chunks
- bundling changes: 9 chunks
- bundling manifests: 0 chunks
- bundling manifests: 1 chunks
- bundling manifests: 2 chunks
- bundling manifests: 3 chunks
- bundling manifests: 4 chunks
- bundling manifests: 5 chunks
- bundling manifests: 6 chunks
- bundling manifests: 7 chunks
- bundling manifests: 8 chunks
- bundling manifests: 9 chunks
- bundling files: foo/Bar/file.txt 0 chunks
- bundling files: foo/Bar/file.txt 1 chunks
- bundling files: foo/Bar/file.txt 2 chunks
- bundling files: foo/Bar/file.txt 3 chunks
- bundling files: foo/file.txt 4 chunks
- bundling files: foo/file.txt 5 chunks
- bundling files: foo/file.txt 6 chunks
- bundling files: foo/file.txt 7 chunks
- bundling files: quux/file.py 8 chunks
- bundling files: quux/file.py 9 chunks
- bundling files: quux/file.py 10 chunks
- bundling files: quux/file.py 11 chunks
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 3 changesets
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
changesets: 1 chunks
add changeset ef1ea85a6374
changesets: 2 chunks
@@ -1432,6 +1437,7 @@
acl: branch access granted: "911600dab2ae" on branch "default"
acl: allowing changeset 911600dab2ae
updating the branch cache
+ checking for updated bookmarks
rolling back to revision 0 (undo push)
0:6675d58eff77
@@ -1462,38 +1468,38 @@
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
adding changesets
- bundling changes: 0 chunks
- bundling changes: 1 chunks
- bundling changes: 2 chunks
- bundling changes: 3 chunks
- bundling changes: 4 chunks
- bundling changes: 5 chunks
- bundling changes: 6 chunks
- bundling changes: 7 chunks
- bundling changes: 8 chunks
- bundling changes: 9 chunks
- bundling manifests: 0 chunks
- bundling manifests: 1 chunks
- bundling manifests: 2 chunks
- bundling manifests: 3 chunks
- bundling manifests: 4 chunks
- bundling manifests: 5 chunks
- bundling manifests: 6 chunks
- bundling manifests: 7 chunks
- bundling manifests: 8 chunks
- bundling manifests: 9 chunks
- bundling files: foo/Bar/file.txt 0 chunks
- bundling files: foo/Bar/file.txt 1 chunks
- bundling files: foo/Bar/file.txt 2 chunks
- bundling files: foo/Bar/file.txt 3 chunks
- bundling files: foo/file.txt 4 chunks
- bundling files: foo/file.txt 5 chunks
- bundling files: foo/file.txt 6 chunks
- bundling files: foo/file.txt 7 chunks
- bundling files: quux/file.py 8 chunks
- bundling files: quux/file.py 9 chunks
- bundling files: quux/file.py 10 chunks
- bundling files: quux/file.py 11 chunks
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 3 changesets
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
changesets: 1 chunks
add changeset ef1ea85a6374
changesets: 2 chunks
@@ -1558,38 +1564,38 @@
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
adding changesets
- bundling changes: 0 chunks
- bundling changes: 1 chunks
- bundling changes: 2 chunks
- bundling changes: 3 chunks
- bundling changes: 4 chunks
- bundling changes: 5 chunks
- bundling changes: 6 chunks
- bundling changes: 7 chunks
- bundling changes: 8 chunks
- bundling changes: 9 chunks
- bundling manifests: 0 chunks
- bundling manifests: 1 chunks
- bundling manifests: 2 chunks
- bundling manifests: 3 chunks
- bundling manifests: 4 chunks
- bundling manifests: 5 chunks
- bundling manifests: 6 chunks
- bundling manifests: 7 chunks
- bundling manifests: 8 chunks
- bundling manifests: 9 chunks
- bundling files: foo/Bar/file.txt 0 chunks
- bundling files: foo/Bar/file.txt 1 chunks
- bundling files: foo/Bar/file.txt 2 chunks
- bundling files: foo/Bar/file.txt 3 chunks
- bundling files: foo/file.txt 4 chunks
- bundling files: foo/file.txt 5 chunks
- bundling files: foo/file.txt 6 chunks
- bundling files: foo/file.txt 7 chunks
- bundling files: quux/file.py 8 chunks
- bundling files: quux/file.py 9 chunks
- bundling files: quux/file.py 10 chunks
- bundling files: quux/file.py 11 chunks
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 3 changesets
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
changesets: 1 chunks
add changeset ef1ea85a6374
changesets: 2 chunks
@@ -1621,6 +1627,7 @@
acl: branch access granted: "911600dab2ae" on branch "default"
acl: allowing changeset 911600dab2ae
updating the branch cache
+ checking for updated bookmarks
rolling back to revision 0 (undo push)
0:6675d58eff77
@@ -1651,38 +1658,38 @@
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
adding changesets
- bundling changes: 0 chunks
- bundling changes: 1 chunks
- bundling changes: 2 chunks
- bundling changes: 3 chunks
- bundling changes: 4 chunks
- bundling changes: 5 chunks
- bundling changes: 6 chunks
- bundling changes: 7 chunks
- bundling changes: 8 chunks
- bundling changes: 9 chunks
- bundling manifests: 0 chunks
- bundling manifests: 1 chunks
- bundling manifests: 2 chunks
- bundling manifests: 3 chunks
- bundling manifests: 4 chunks
- bundling manifests: 5 chunks
- bundling manifests: 6 chunks
- bundling manifests: 7 chunks
- bundling manifests: 8 chunks
- bundling manifests: 9 chunks
- bundling files: foo/Bar/file.txt 0 chunks
- bundling files: foo/Bar/file.txt 1 chunks
- bundling files: foo/Bar/file.txt 2 chunks
- bundling files: foo/Bar/file.txt 3 chunks
- bundling files: foo/file.txt 4 chunks
- bundling files: foo/file.txt 5 chunks
- bundling files: foo/file.txt 6 chunks
- bundling files: foo/file.txt 7 chunks
- bundling files: quux/file.py 8 chunks
- bundling files: quux/file.py 9 chunks
- bundling files: quux/file.py 10 chunks
- bundling files: quux/file.py 11 chunks
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 2 changesets
+ bundling: 3 changesets
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 0/3 manifests (0.00%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 1/3 manifests (33.33%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 2/3 manifests (66.67%)
+ bundling: 3/3 manifests (100.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/Bar/file.txt 0/3 files (0.00%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: foo/file.txt 1/3 files (33.33%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
+ bundling: quux/file.py 2/3 files (66.67%)
changesets: 1 chunks
add changeset ef1ea85a6374
changesets: 2 chunks
--- a/tests/test-archive.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-archive.t Wed Feb 16 14:13:22 2011 -0600
@@ -30,7 +30,6 @@
check http return codes
-
$ test_archtype gz tar.gz tar.bz2 zip
% gz allowed should give 200
200 Script output follows
@@ -150,9 +149,8 @@
> print h1 == h2 or "md5 differ: " + repr((h1, h2))
> EOF
-archive name is stored in the archive, so create similar
-
-archives and rename them afterwards.
+archive name is stored in the archive, so create similar archives and
+rename them afterwards.
$ hg archive -t tgz tip.tar.gz
$ mv tip.tar.gz tip1.tar.gz
@@ -208,6 +206,38 @@
abort: unknown archive type 'bogus'
[255]
+enable progress extension:
+
+ $ cp $HGRCPATH $HGRCPATH.no-progress
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > progress =
+ > [progress]
+ > assume-tty = 1
+ > format = topic bar number
+ > delay = 0
+ > refresh = 0
+ > width = 60
+ > EOF
+
+ $ hg archive ../with-progress 2>&1 | $TESTDIR/filtercr.py
+
+ archiving [ ] 0/4
+ archiving [ ] 0/4
+ archiving [=========> ] 1/4
+ archiving [=========> ] 1/4
+ archiving [====================> ] 2/4
+ archiving [====================> ] 2/4
+ archiving [===============================> ] 3/4
+ archiving [===============================> ] 3/4
+ archiving [==========================================>] 4/4
+ archiving [==========================================>] 4/4
+ \r (esc)
+
+cleanup after progress extension test:
+
+ $ cp $HGRCPATH.no-progress $HGRCPATH
+
server errors
$ cat errors.log
@@ -219,6 +249,7 @@
$ hg archive ../test-empty
abort: no working directory: please specify a revision
[255]
+
old file -- date clamped to 1980
$ touch -t 197501010000 old
--- a/tests/test-bookmarks-current.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-bookmarks-current.t Wed Feb 16 14:13:22 2011 -0600
@@ -2,7 +2,6 @@
$ echo "bookmarks=" >> $HGRCPATH
$ echo "[bookmarks]" >> $HGRCPATH
- $ echo "track.current = True" >> $HGRCPATH
$ hg init
--- a/tests/test-bookmarks-pushpull.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-bookmarks-pushpull.t Wed Feb 16 14:13:22 2011 -0600
@@ -1,9 +1,6 @@
$ echo "[extensions]" >> $HGRCPATH
$ echo "bookmarks=" >> $HGRCPATH
- $ echo "[bookmarks]" >> $HGRCPATH
- $ echo "track.current = True" >> $HGRCPATH
-
initialize
$ hg init a
@@ -48,8 +45,8 @@
no changes found
importing bookmark X
$ hg bookmark
+ X 0:4e3505fd9583
Y 0:4e3505fd9583
- X 0:4e3505fd9583
export bookmark by name
@@ -62,23 +59,30 @@
no changes found
exporting bookmark W
$ hg -R ../a bookmarks
- Y 0:4e3505fd9583
+ W -1:000000000000
X 0:4e3505fd9583
+ Y 0:4e3505fd9583
* Z 0:4e3505fd9583
- W -1:000000000000
delete a remote bookmark
$ hg book -d W
$ hg push -B W ../a
+ pushing to ../a
+ searching for changes
+ no changes found
deleting remote bookmark W
push/pull name that doesn't exist
$ hg push -B badname ../a
+ pushing to ../a
+ searching for changes
+ no changes found
bookmark badname does not exist on the local or remote repository!
[2]
$ hg pull -B anotherbadname ../a
+ pulling from ../a
abort: remote bookmark anotherbadname not found!
[255]
@@ -90,8 +94,8 @@
adding f1
$ hg book -f X
$ hg book
+ * X 1:0d2164f0ce0d
Y 0:4e3505fd9583
- * X 1:0d2164f0ce0d
Z 1:0d2164f0ce0d
$ cd ../b
@@ -102,8 +106,8 @@
adding f2
$ hg book -f X
$ hg book
+ * X 1:9b140be10808
Y 0:4e3505fd9583
- * X 1:9b140be10808
foo -1:000000000000
foobar -1:000000000000
@@ -117,8 +121,8 @@
not updating divergent bookmark X
(run 'hg heads' to see heads, 'hg merge' to merge)
$ hg book
+ * X 1:9b140be10808
Y 0:4e3505fd9583
- * X 1:9b140be10808
foo -1:000000000000
foobar -1:000000000000
$ hg push -f ../a
@@ -129,8 +133,8 @@
adding file changes
added 1 changesets with 1 changes to 1 files (+1 heads)
$ hg -R ../a book
+ * X 1:0d2164f0ce0d
Y 0:4e3505fd9583
- * X 1:0d2164f0ce0d
Z 1:0d2164f0ce0d
hgweb
--- a/tests/test-bookmarks-rebase.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-bookmarks-rebase.t Wed Feb 16 14:13:22 2011 -0600
@@ -31,8 +31,8 @@
bookmark list
$ hg bookmark
+ one 1:925d80f479bb
* two 3:2ae46b1d99a7
- one 1:925d80f479bb
rebase
@@ -41,9 +41,8 @@
$ hg log
changeset: 3:9163974d1cb5
- tag: one
+ bookmark: two
tag: tip
- tag: two
parent: 1:925d80f479bb
parent: 2:db815d6d32e6
user: test
@@ -57,6 +56,7 @@
summary: 2
changeset: 1:925d80f479bb
+ bookmark: one
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: 1
--- a/tests/test-bookmarks-strip.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-bookmarks-strip.t Wed Feb 16 14:13:22 2011 -0600
@@ -61,7 +61,7 @@
list bookmarks
$ hg book
- * test 1:8cf31af87a2b
+ test 1:8cf31af87a2b
* test2 1:8cf31af87a2b
immediate rollback and reentrancy issue
@@ -93,6 +93,8 @@
rollback dry run with rollback information
$ hg rollback -n
+ no rollback information available
+ [1]
$ hg bookmarks
* markb 0:07f494440405
--- a/tests/test-bookmarks.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-bookmarks.t Wed Feb 16 14:13:22 2011 -0600
@@ -36,7 +36,7 @@
$ hg log -r X
changeset: 0:f7b1eb17ad24
- tag: X
+ bookmark: X
tag: tip
user: test
date: Thu Jan 01 00:00:00 1970 +0000
@@ -54,8 +54,8 @@
list bookmarks
$ hg bookmarks
- * X2 0:f7b1eb17ad24
- * X 0:f7b1eb17ad24
+ X 0:f7b1eb17ad24
+ X2 0:f7b1eb17ad24
Y -1:000000000000
$ echo b > b
@@ -65,23 +65,21 @@
bookmarks revset
$ hg log -r 'bookmark()'
- changeset: 1:925d80f479bb
- tag: X
- tag: X2
- tag: tip
+ changeset: 0:f7b1eb17ad24
+ bookmark: X
+ bookmark: X2
user: test
date: Thu Jan 01 00:00:00 1970 +0000
- summary: 1
+ summary: 0
$ hg log -r 'bookmark(Y)'
$ hg log -r 'bookmark(X2)'
- changeset: 1:925d80f479bb
- tag: X
- tag: X2
- tag: tip
+ changeset: 0:f7b1eb17ad24
+ bookmark: X
+ bookmark: X2
user: test
date: Thu Jan 01 00:00:00 1970 +0000
- summary: 1
+ summary: 0
$ hg help revsets | grep 'bookmark('
"bookmark([name])"
@@ -89,25 +87,28 @@
bookmarks X and X2 moved to rev 1, Y at rev -1
$ hg bookmarks
- * X2 1:925d80f479bb
- * X 1:925d80f479bb
+ X 0:f7b1eb17ad24
+ X2 0:f7b1eb17ad24
Y -1:000000000000
bookmark rev 0 again
$ hg bookmark -r 0 Z
+ $ hg update X
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ echo c > c
$ hg add c
$ hg commit -m 2
+ created new head
-bookmarks X and X2 moved to rev 2, Y at rev -1, Z at rev 0
+bookmarks X moved to rev 2, Y at rev -1, Z at rev 0
$ hg bookmarks
- * X2 2:0316ce92851d
- * X 2:0316ce92851d
+ * X 2:db815d6d32e6
+ X2 0:f7b1eb17ad24
+ Y -1:000000000000
Z 0:f7b1eb17ad24
- Y -1:000000000000
rename nonexistent bookmark
@@ -128,8 +129,8 @@
list bookmarks
$ hg bookmark
- * X2 2:0316ce92851d
- * Y 2:0316ce92851d
+ X2 0:f7b1eb17ad24
+ * Y 2:db815d6d32e6
Z 0:f7b1eb17ad24
rename without new name
@@ -157,19 +158,19 @@
list bookmarks
$ hg bookmarks
- * X2 2:0316ce92851d
- * Y 2:0316ce92851d
+ X2 0:f7b1eb17ad24
+ Y 2:db815d6d32e6
Z 0:f7b1eb17ad24
- * x y 2:0316ce92851d
+ * x y 2:db815d6d32e6
look up stripped bookmark name
$ hg log -r '"x y"'
- changeset: 2:0316ce92851d
- tag: X2
- tag: Y
+ changeset: 2:db815d6d32e6
+ bookmark: Y
+ bookmark: x y
tag: tip
- tag: x y
+ parent: 0:f7b1eb17ad24
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: 2
@@ -195,10 +196,10 @@
list bookmarks
$ hg bookmark
- * X2 2:0316ce92851d
- * Y 2:0316ce92851d
- * Z 2:0316ce92851d
- * x y 2:0316ce92851d
+ X2 0:f7b1eb17ad24
+ Y 2:db815d6d32e6
+ * Z 2:db815d6d32e6
+ x y 2:db815d6d32e6
revision but no bookmark name
@@ -211,3 +212,10 @@
$ hg bookmark ' '
abort: bookmark names cannot consist entirely of whitespace
[255]
+
+invalid bookmark
+
+ $ hg bookmark 'foo:bar'
+ abort: bookmark 'foo:bar' contains illegal character
+ [255]
+
--- a/tests/test-bundle.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-bundle.t Wed Feb 16 14:13:22 2011 -0600
@@ -1,5 +1,3 @@
- $ cp "$TESTDIR"/printenv.py .
-
Setting up test
$ hg init test
@@ -188,11 +186,18 @@
date: Thu Jan 01 00:00:00 1970 +0000
summary: 0.0
+Make sure bundlerepo doesn't leak tempfiles (issue2491)
+
+ $ ls .hg
+ 00changelog.i
+ cache
+ requires
+ store
Pull ../full.hg into empty (with hook)
$ echo '[hooks]' >> .hg/hgrc
- $ echo 'changegroup = python ../printenv.py changegroup' >> .hg/hgrc
+ $ echo 'changegroup = python "$TESTDIR"/printenv.py changegroup' >> .hg/hgrc
doesn't work (yet ?)
@@ -543,26 +548,26 @@
list of changesets:
d2ae7f538514cd87c17547b0de4cea71fe1af9fb
5ece8e77363e2b5269e27c66828b72da29e4341a
- bundling changes: 0 chunks
- bundling changes: 1 chunks
- bundling changes: 2 chunks
- bundling changes: 3 chunks
- bundling changes: 4 chunks
- bundling changes: 5 chunks
- bundling changes: 6 chunks
- bundling manifests: 0 chunks
- bundling manifests: 1 chunks
- bundling manifests: 2 chunks
- bundling manifests: 3 chunks
- bundling manifests: 4 chunks
- bundling manifests: 5 chunks
- bundling manifests: 6 chunks
- bundling files: b 0 chunks
- bundling files: b 1 chunks
- bundling files: b 2 chunks
- bundling files: b 3 chunks
- bundling files: b1 4 chunks
- bundling files: b1 5 chunks
- bundling files: b1 6 chunks
- bundling files: b1 7 chunks
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 0 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 1 changesets
+ bundling: 2 changesets
+ bundling: 0/2 manifests (0.00%)
+ bundling: 0/2 manifests (0.00%)
+ bundling: 0/2 manifests (0.00%)
+ bundling: 1/2 manifests (50.00%)
+ bundling: 1/2 manifests (50.00%)
+ bundling: 1/2 manifests (50.00%)
+ bundling: 2/2 manifests (100.00%)
+ bundling: b 0/2 files (0.00%)
+ bundling: b 0/2 files (0.00%)
+ bundling: b 0/2 files (0.00%)
+ bundling: b 0/2 files (0.00%)
+ bundling: b1 1/2 files (50.00%)
+ bundling: b1 1/2 files (50.00%)
+ bundling: b1 1/2 files (50.00%)
+ bundling: b1 1/2 files (50.00%)
--- a/tests/test-check-code.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-check-code.t Wed Feb 16 14:13:22 2011 -0600
@@ -34,7 +34,7 @@
gratuitous whitespace in () or []
./wrong.py:2:
> del(arg2)
- del isn't a function
+ Python keyword is not a function
./wrong.py:3:
> return ( 5+6, 9)
missing whitespace in expression
@@ -52,3 +52,44 @@
> y = format(x)
any/all/format not available in Python 2.4
[1]
+
+ $ cat > is-op.py <<EOF
+ > # is-operator comparing number or string literal
+ > x = None
+ > y = x is 'foo'
+ > y = x is "foo"
+ > y = x is 5346
+ > y = x is -6
+ > y = x is not 'foo'
+ > y = x is not "foo"
+ > y = x is not 5346
+ > y = x is not -6
+ > EOF
+
+ $ "$check_code" ./is-op.py
+ ./is-op.py:3:
+ > y = x is 'foo'
+ object comparison with literal
+ ./is-op.py:4:
+ > y = x is "foo"
+ object comparison with literal
+ ./is-op.py:5:
+ > y = x is 5346
+ object comparison with literal
+ ./is-op.py:6:
+ > y = x is -6
+ object comparison with literal
+ ./is-op.py:7:
+ > y = x is not 'foo'
+ object comparison with literal
+ ./is-op.py:8:
+ > y = x is not "foo"
+ object comparison with literal
+ ./is-op.py:9:
+ > y = x is not 5346
+ object comparison with literal
+ ./is-op.py:10:
+ > y = x is not -6
+ object comparison with literal
+ [1]
+
--- a/tests/test-clone-cgi.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-clone-cgi.t Wed Feb 16 14:13:22 2011 -0600
@@ -19,37 +19,10 @@
> wsgicgi.launch(application)
> HGWEB
$ chmod 755 hgweb.cgi
- $ DOCUMENT_ROOT="/var/www/hg"; export DOCUMENT_ROOT
- $ GATEWAY_INTERFACE="CGI/1.1"; export GATEWAY_INTERFACE
- $ HTTP_ACCEPT="text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"; export HTTP_ACCEPT
- $ HTTP_ACCEPT_CHARSET="ISO-8859-1,utf-8;q=0.7,*;q=0.7"; export HTTP_ACCEPT_CHARSET
- $ HTTP_ACCEPT_ENCODING="gzip,deflate"; export HTTP_ACCEPT_ENCODING
- $ HTTP_ACCEPT_LANGUAGE="en-us,en;q=0.5"; export HTTP_ACCEPT_LANGUAGE
- $ HTTP_CACHE_CONTROL="max-age=0"; export HTTP_CACHE_CONTROL
- $ HTTP_CONNECTION="keep-alive"; export HTTP_CONNECTION
- $ HTTP_HOST="hg.omnifarious.org"; export HTTP_HOST
- $ HTTP_KEEP_ALIVE="300"; export HTTP_KEEP_ALIVE
- $ HTTP_USER_AGENT="Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.0.4) Gecko/20060608 Ubuntu/dapper-security Firefox/1.5.0.4"; export HTTP_USER_AGENT
- $ PATH_INFO="/"; export PATH_INFO
- $ PATH_TRANSLATED="/var/www/hg/index.html"; export PATH_TRANSLATED
- $ REMOTE_ADDR="127.0.0.2"; export REMOTE_ADDR
- $ REMOTE_PORT="44703"; export REMOTE_PORT
- $ REQUEST_METHOD="GET"; export REQUEST_METHOD
- $ REQUEST_URI="/test/"; export REQUEST_URI
- $ SCRIPT_FILENAME="/home/hopper/hg_public/test.cgi"; export SCRIPT_FILENAME
- $ SCRIPT_NAME="/test"; export SCRIPT_NAME
- $ SCRIPT_URI="http://hg.omnifarious.org/test/"; export SCRIPT_URI
- $ SCRIPT_URL="/test/"; export SCRIPT_URL
- $ SERVER_ADDR="127.0.0.1"; export SERVER_ADDR
- $ SERVER_ADMIN="eric@localhost"; export SERVER_ADMIN
- $ SERVER_NAME="hg.omnifarious.org"; export SERVER_NAME
- $ SERVER_PORT="80"; export SERVER_PORT
- $ SERVER_PROTOCOL="HTTP/1.1"; export SERVER_PROTOCOL
- $ SERVER_SIGNATURE="<address>Apache/2.0.53 (Fedora) Server at hg.omnifarious.org Port 80</address>"; export SERVER_SIGNATURE
- $ SERVER_SOFTWARE="Apache/2.0.53 (Fedora)"; export SERVER_SOFTWARE
try hgweb request
+ $ . "$TESTDIR/cgienv"
$ QUERY_STRING="cmd=changegroup&roots=0000000000000000000000000000000000000000"; export QUERY_STRING
$ python hgweb.cgi >page1 2>&1
$ python "$TESTDIR/md5sum.py" page1
--- a/tests/test-clone-failure.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-clone-failure.t Wed Feb 16 14:13:22 2011 -0600
@@ -39,7 +39,6 @@
> rm a
> else
> echo "abort: repository a not found!"
- > echo 255
> fi
abort: repository a not found!
--- a/tests/test-command-template.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-command-template.t Wed Feb 16 14:13:22 2011 -0600
@@ -449,7 +449,7 @@
$ echo 'q = q' > t
$ hg log --style ./t
- abort: ./t: no key named 'changeset'
+ abort: "changeset" not in template map
[255]
Error if include fails:
@@ -570,7 +570,7 @@
Keys work:
- $ for key in author branches date desc file_adds file_dels file_mods \
+ $ for key in author branch branches date desc file_adds file_dels file_mods \
> file_copies file_copies_switch files \
> manifest node parents rev tags diffstat extras; do
> for mode in '' --verbose --debug; do
@@ -604,6 +604,33 @@
author--debug: other@place
author--debug: A. N. Other <other@place>
author--debug: User Name <user@hostname>
+ branch: default
+ branch: default
+ branch: default
+ branch: default
+ branch: foo
+ branch: default
+ branch: default
+ branch: default
+ branch: default
+ branch--verbose: default
+ branch--verbose: default
+ branch--verbose: default
+ branch--verbose: default
+ branch--verbose: foo
+ branch--verbose: default
+ branch--verbose: default
+ branch--verbose: default
+ branch--verbose: default
+ branch--debug: default
+ branch--debug: default
+ branch--debug: default
+ branch--debug: default
+ branch--debug: foo
+ branch--debug: default
+ branch--debug: default
+ branch--debug: default
+ branch--debug: default
branches:
branches:
branches:
--- a/tests/test-confused-revert.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-confused-revert.t Wed Feb 16 14:13:22 2011 -0600
@@ -58,8 +58,8 @@
Revert should fail:
- $ hg revert --all
- abort: uncommitted merge - please provide a specific revision
+ $ hg revert
+ abort: uncommitted merge - use "hg update", see "hg help revert"
[255]
Revert should be ok now:
--- a/tests/test-convert-svn-move.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-convert-svn-move.t Wed Feb 16 14:13:22 2011 -0600
@@ -167,83 +167,73 @@
> [progress]
> assume-tty = 1
> delay = 0
+ > format = topic bar number
> refresh = 0
- > EOF
- $ cat > filtercr.py <<EOF
- > import sys, re
- > for line in sys.stdin:
- > line = re.sub(r'\r+[^\n]', lambda m: '\n' + m.group()[-1:], line)
- > sys.stdout.write(line)
+ > width = 60
> EOF
- $ hg convert svn-repo hg-progress 2>&1 | python filtercr.py
+ $ hg convert svn-repo hg-progress 2>&1 | $TESTDIR/filtercr.py
- scanning [ <=> ] 1
- scanning [ <=> ] 2
- scanning [ <=> ] 3
- scanning [ <=> ] 4
- scanning [ <=> ] 5
- scanning [ <=> ] 6
- scanning [ <=> ] 7
-
- converting [ ] 0/7
- getting files [========> ] 1/6
- getting files [==================> ] 2/6
- getting files [============================> ] 3/6
- getting files [======================================> ] 4/6
- getting files [================================================> ] 5/6
- getting files [==========================================================>] 6/6
-
- converting [=======> ] 1/7
- scanning paths [ ] 0/1
-
- getting files [==========================================================>] 1/1
-
- converting [================> ] 2/7
- scanning paths [ ] 0/2
- scanning paths [============================> ] 1/2
-
- getting files [=============> ] 1/4
- getting files [============================> ] 2/4
- getting files [===========================================> ] 3/4
- getting files [==========================================================>] 4/4
-
- converting [=========================> ] 3/7
- scanning paths [ ] 0/1
-
- getting files [==========================================================>] 1/1
-
- converting [==================================> ] 4/7
- scanning paths [ ] 0/1
-
- getting files [==========================================================>] 1/1
-
- converting [===========================================> ] 5/7
- scanning paths [ ] 0/3
- scanning paths [==================> ] 1/3
- scanning paths [=====================================> ] 2/3
-
- getting files [======> ] 1/8
- getting files [=============> ] 2/8
- getting files [=====================> ] 3/8
- getting files [============================> ] 4/8
- getting files [===================================> ] 5/8
- getting files [===========================================> ] 6/8
- getting files [==================================================> ] 7/8
- getting files [==========================================================>] 8/8
-
- converting [====================================================> ] 6/7
- scanning paths [ ] 0/1
-
- getting files [======> ] 1/8
- getting files [=============> ] 2/8
- getting files [=====================> ] 3/8
- getting files [============================> ] 4/8
- getting files [===================================> ] 5/8
- getting files [===========================================> ] 6/8
- getting files [==================================================> ] 7/8
- getting files [==========================================================>] 8/8
-
+ scanning [ <=> ] 1
+ scanning [ <=> ] 2
+ scanning [ <=> ] 3
+ scanning [ <=> ] 4
+ scanning [ <=> ] 5
+ scanning [ <=> ] 6
+ scanning [ <=> ] 7
+
+ converting [ ] 0/7
+ getting files [=====> ] 1/6
+ getting files [============> ] 2/6
+ getting files [==================> ] 3/6
+ getting files [=========================> ] 4/6
+ getting files [===============================> ] 5/6
+ getting files [======================================>] 6/6
+
+ converting [=====> ] 1/7
+ scanning paths [ ] 0/1
+ getting files [======================================>] 1/1
+
+ converting [===========> ] 2/7
+ scanning paths [ ] 0/2
+ scanning paths [==================> ] 1/2
+ getting files [========> ] 1/4
+ getting files [==================> ] 2/4
+ getting files [============================> ] 3/4
+ getting files [======================================>] 4/4
+
+ converting [=================> ] 3/7
+ scanning paths [ ] 0/1
+ getting files [======================================>] 1/1
+
+ converting [=======================> ] 4/7
+ scanning paths [ ] 0/1
+ getting files [======================================>] 1/1
+
+ converting [=============================> ] 5/7
+ scanning paths [ ] 0/3
+ scanning paths [===========> ] 1/3
+ scanning paths [========================> ] 2/3
+ getting files [===> ] 1/8
+ getting files [========> ] 2/8
+ getting files [=============> ] 3/8
+ getting files [==================> ] 4/8
+ getting files [=======================> ] 5/8
+ getting files [============================> ] 6/8
+ getting files [=================================> ] 7/8
+ getting files [======================================>] 8/8
+
+ converting [===================================> ] 6/7
+ scanning paths [ ] 0/1
+ getting files [===> ] 1/8
+ getting files [========> ] 2/8
+ getting files [=============> ] 3/8
+ getting files [==================> ] 4/8
+ getting files [=======================> ] 5/8
+ getting files [============================> ] 6/8
+ getting files [=================================> ] 7/8
+ getting files [======================================>] 8/8
+
initializing destination hg-progress repository
scanning source...
sorting...
@@ -255,3 +245,4 @@
2 adddb
1 branch
0 clobberdir
+
--- a/tests/test-convert.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-convert.t Wed Feb 16 14:13:22 2011 -0600
@@ -40,16 +40,16 @@
have the following effects:
--branchsort convert from parent to child revision when possible, which
- means branches are usually converted one after the other. It
- generates more compact repositories.
+ means branches are usually converted one after the other.
+ It generates more compact repositories.
--datesort sort revisions by date. Converted repositories have good-
looking changelogs but are often an order of magnitude
larger than the same ones generated by --branchsort.
--sourcesort try to preserve source revisions order, only supported by
Mercurial sources.
- If <REVMAP> isn't given, it will be put in a default location
- (<dest>/.hg/shamap by default). The <REVMAP> is a simple text file that
+ If "REVMAP" isn't given, it will be put in a default location
+ ("<dest>/.hg/shamap" by default). The "REVMAP" is a simple text file that
maps each source commit ID to the destination ID for that revision, like
so:
@@ -123,16 +123,19 @@
Mercurial Source
''''''''''''''''
- --config convert.hg.ignoreerrors=False (boolean)
- ignore integrity errors when reading. Use it to fix Mercurial
- repositories with missing revlogs, by converting from and to
- Mercurial.
+ The Mercurial source recognizes the following configuration options, which
+ you can set on the command line with "--config":
- --config convert.hg.saverev=False (boolean)
- store original revision ID in changeset (forces target IDs to change)
-
- --config convert.hg.startrev=0 (hg revision identifier)
- convert start revision and its descendants
+ convert.hg.ignoreerrors
+ ignore integrity errors when reading. Use it to fix Mercurial
+ repositories with missing revlogs, by converting from and to
+ Mercurial. Default is False.
+ convert.hg.saverev
+ store original. revision ID in changeset (forces target IDs to
+ change). It takes and boolean argument and defaults to False.
+ convert.hg.startrev
+ convert start revision and its descendants. It takes a hg
+ revision identifier and defaults to 0.
CVS Source
''''''''''
@@ -140,46 +143,45 @@
CVS source will use a sandbox (i.e. a checked-out copy) from CVS to
indicate the starting point of what will be converted. Direct access to
the repository files is not needed, unless of course the repository is
- :local:. The conversion uses the top level directory in the sandbox to
+ ":local:". The conversion uses the top level directory in the sandbox to
find the CVS repository, and then uses CVS rlog commands to find files to
convert. This means that unless a filemap is given, all files under the
starting directory will be converted, and that any directory
reorganization in the CVS sandbox is ignored.
- The options shown are the defaults.
-
- --config convert.cvsps.cache=True (boolean)
- Set to False to disable remote log caching, for testing and debugging
- purposes.
-
- --config convert.cvsps.fuzz=60 (integer)
- Specify the maximum time (in seconds) that is allowed between commits
- with identical user and log message in a single changeset. When very
- large files were checked in as part of a changeset then the default
- may not be long enough.
+ The following options can be used with "--config":
- --config convert.cvsps.mergeto='{{mergetobranch ([-\w]+)}}'
- Specify a regular expression to which commit log messages are matched.
- If a match occurs, then the conversion process will insert a dummy
- revision merging the branch on which this log message occurs to the
- branch indicated in the regex.
-
- --config convert.cvsps.mergefrom='{{mergefrombranch ([-\w]+)}}'
- Specify a regular expression to which commit log messages are matched.
- If a match occurs, then the conversion process will add the most
- recent revision on the branch indicated in the regex as the second
- parent of the changeset.
-
- --config hook.cvslog
- Specify a Python function to be called at the end of gathering the CVS
- log. The function is passed a list with the log entries, and can
- modify the entries in-place, or add or delete them.
-
- --config hook.cvschangesets
- Specify a Python function to be called after the changesets are
- calculated from the the CVS log. The function is passed a list with
- the changeset entries, and can modify the changesets in-place, or add
- or delete them.
+ convert.cvsps.cache
+ Set to False to disable remote log caching, for testing and
+ debugging purposes. Default is True.
+ convert.cvsps.fuzz
+ Specify the maximum time (in seconds) that is allowed between
+ commits with identical user and log message in a single
+ changeset. When very large files were checked in as part of a
+ changeset then the default may not be long enough. The default
+ is 60.
+ convert.cvsps.mergeto
+ Specify a regular expression to which commit log messages are
+ matched. If a match occurs, then the conversion process will
+ insert a dummy revision merging the branch on which this log
+ message occurs to the branch indicated in the regex. Default
+ is "{{mergetobranch ([-\w]+)}}"
+ convert.cvsps.mergefrom
+ Specify a regular expression to which commit log messages are
+ matched. If a match occurs, then the conversion process will
+ add the most recent revision on the branch indicated in the
+ regex as the second parent of the changeset. Default is
+ "{{mergefrombranch ([-\w]+)}}"
+ hook.cvslog
+ Specify a Python function to be called at the end of gathering
+ the CVS log. The function is passed a list with the log
+ entries, and can modify the entries in-place, or add or delete
+ them.
+ hook.cvschangesets
+ Specify a Python function to be called after the changesets
+ are calculated from the the CVS log. The function is passed a
+ list with the changeset entries, and can modify the changesets
+ in-place, or add or delete them.
An additional "debugcvsps" Mercurial command allows the builtin changeset
merging code to be run without doing a conversion. Its parameters and
@@ -199,21 +201,22 @@
them to paths relative to the source URL, or leave them blank to disable
auto detection.
- --config convert.svn.branches=branches (directory name)
- specify the directory containing branches
+ The following options can be set with "--config":
- --config convert.svn.tags=tags (directory name)
- specify the directory containing tags
-
- --config convert.svn.trunk=trunk (directory name)
- specify the name of the trunk branch
+ convert.svn.branches
+ specify the directory containing branches. The defaults is
+ "branches".
+ convert.svn.tags
+ specify the directory containing tags. The default is "tags".
+ convert.svn.trunk
+ specify the name of the trunk branch The defauls is "trunk".
Source history can be retrieved starting at a specific revision, instead
of being integrally converted. Only single branch conversions are
supported.
- --config convert.svn.startrev=0 (svn revision number)
- specify start Subversion revision.
+ convert.svn.startrev
+ specify start Subversion revision number. The default is 0.
Perforce Source
'''''''''''''''
@@ -222,25 +225,27 @@
specification as source. It will convert all files in the source to a flat
Mercurial repository, ignoring labels, branches and integrations. Note
that when a depot path is given you then usually should specify a target
- directory, because otherwise the target may be named ...-hg.
+ directory, because otherwise the target may be named "...-hg".
It is possible to limit the amount of source history to be converted by
- specifying an initial Perforce revision.
+ specifying an initial Perforce revision:
- --config convert.p4.startrev=0 (perforce changelist number)
- specify initial Perforce revision.
+ convert.p4.startrev
+ specify initial Perforce revision, a Perforce changelist
+ number).
Mercurial Destination
'''''''''''''''''''''
- --config convert.hg.clonebranches=False (boolean)
- dispatch source branches in separate clones.
+ The following options are supported:
- --config convert.hg.tagsbranch=default (branch name)
- tag revisions branch name
-
- --config convert.hg.usebranchnames=True (boolean)
- preserve branch names
+ convert.hg.clonebranches
+ dispatch source branches in separate clones. The default is
+ False.
+ convert.hg.tagsbranch
+ branch name for tag revisions, defaults to "default".
+ convert.hg.usebranchnames
+ preserve branch names. The default is True
options:
@@ -376,7 +381,7 @@
contents of fncache file:
- $ cat b/.hg/store/fncache
+ $ cat b/.hg/store/fncache | sort
data/a.i
data/b.i
--- a/tests/test-debugcomplete.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-debugcomplete.t Wed Feb 16 14:13:22 2011 -0600
@@ -6,6 +6,7 @@
archive
backout
bisect
+ bookmarks
branch
branches
bundle
@@ -74,6 +75,7 @@
debugdata
debugdate
debugfsinfo
+ debugignore
debugindex
debugindexdot
debuginstall
@@ -187,8 +189,8 @@
init: ssh, remotecmd, insecure
log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, patch, git, limit, no-merges, stat, style, template, include, exclude
merge: force, tool, rev, preview
- pull: update, force, rev, branch, ssh, remotecmd, insecure
- push: force, rev, branch, new-branch, ssh, remotecmd, insecure
+ pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
+ push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure
remove: after, force, include, exclude
serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, templates, style, ipv6, certificate
status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos
@@ -198,6 +200,7 @@
archive: no-decode, prefix, rev, type, subrepos, include, exclude
backout: merge, parent, tool, rev, include, exclude, message, logfile, date, user
bisect: reset, good, bad, skip, command, noupdate
+ bookmarks: force, rev, delete, rename
branch: force, clean
branches: active, closed
bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
@@ -212,6 +215,7 @@
debugdata:
debugdate: extended
debugfsinfo:
+ debugignore:
debugindex: format
debugindexdot:
debuginstall:
@@ -228,10 +232,10 @@
help:
identify: rev, num, id, branch, tags
import: strip, base, force, no-commit, exact, import-branch, message, logfile, date, user, similarity
- incoming: force, newest-first, bundle, rev, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, insecure, subrepos
+ incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, insecure, subrepos
locate: rev, print0, fullpath, include, exclude
manifest: rev
- outgoing: force, rev, newest-first, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, insecure, subrepos
+ outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, insecure, subrepos
parents: rev, style, template
paths:
recover:
--- a/tests/test-demandimport.py Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-demandimport.py Wed Feb 16 14:13:22 2011 -0600
@@ -8,6 +8,7 @@
l = repr(obj)
l = rsub("0x[0-9a-fA-F]+", "0x?", l)
l = rsub("from '.*'", "from '?'", l)
+ l = rsub("'<[a-z]*>'", "'<whatever>'", l)
return l
import os
--- a/tests/test-demandimport.py.out Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-demandimport.py.out Wed Feb 16 14:13:22 2011 -0600
@@ -11,5 +11,5 @@
fred.sub = <function sub at 0x?>
fred = <proxied module 're'>
re = <unloaded module 'sys'>
-re.stderr = <open file '<stderr>', mode 'w' at 0x?>
+re.stderr = <open file '<whatever>', mode 'w' at 0x?>
re = <proxied module 'sys'>
--- a/tests/test-diffstat.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-diffstat.t Wed Feb 16 14:13:22 2011 -0600
@@ -46,3 +46,20 @@
b | Bin
1 files changed, 0 insertions(+), 0 deletions(-)
+ $ hg ci -m createb
+
+ $ printf '\0' > "file with spaces"
+ $ hg add "file with spaces"
+
+Filename with spaces diffstat:
+
+ $ hg diff --stat
+ file with spaces | 0
+ 1 files changed, 0 insertions(+), 0 deletions(-)
+
+Filename with spaces git diffstat:
+
+ $ hg diff --stat --git
+ file with spaces | Bin
+ 1 files changed, 0 insertions(+), 0 deletions(-)
+
--- a/tests/test-doctest.py Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-doctest.py Wed Feb 16 14:13:22 2011 -0600
@@ -19,5 +19,11 @@
import mercurial.util
doctest.testmod(mercurial.util)
+import mercurial.encoding
+doctest.testmod(mercurial.encoding)
+
+import mercurial.hgweb.hgwebdir_mod
+doctest.testmod(mercurial.hgweb.hgwebdir_mod)
+
import hgext.convert.cvsps
doctest.testmod(hgext.convert.cvsps)
--- a/tests/test-encoding.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-encoding.t Wed Feb 16 14:13:22 2011 -0600
@@ -240,6 +240,4 @@
abort: decoding near '\xe9': 'ascii' codec can't decode byte 0xe9 in position 0: ordinal not in range(128)! (esc)
[255]
$ cp latin-1-tag .hg/branch
- $ HGENCODING=latin-1 hg ci -m 'should fail'
- abort: branch name not in UTF-8!
- [255]
+ $ HGENCODING=latin-1 hg ci -m 'auto-promote legacy name'
--- a/tests/test-extension.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-extension.t Wed Feb 16 14:13:22 2011 -0600
@@ -315,6 +315,11 @@
use "hg help extensions" for information on enabling extensions
+ $ cat > hgext/forest.py <<EOF
+ > cmdtable = None
+ > EOF
$ hg --config extensions.path=./path.py help foo > /dev/null
+ warning: error finding commands in $TESTTMP/hgext/forest.py
hg: unknown command 'foo'
+ warning: error finding commands in $TESTTMP/hgext/forest.py
[255]
--- a/tests/test-fncache.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-fncache.t Wed Feb 16 14:13:22 2011 -0600
@@ -6,7 +6,7 @@
$ hg add
adding a
$ hg ci -m first
- $ cat .hg/store/fncache
+ $ cat .hg/store/fncache | sort
data/a.i
Testing a.i/b:
@@ -16,7 +16,7 @@
$ hg add
adding a.i/b
$ hg ci -m second
- $ cat .hg/store/fncache
+ $ cat .hg/store/fncache | sort
data/a.i
data/a.i.hg/b.i
@@ -27,10 +27,10 @@
$ hg add
adding a.i.hg/c
$ hg ci -m third
- $ cat .hg/store/fncache
+ $ cat .hg/store/fncache | sort
data/a.i
+ data/a.i.hg.hg/c.i
data/a.i.hg/b.i
- data/a.i.hg.hg/c.i
Testing verify:
--- a/tests/test-globalopts.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-globalopts.t Wed Feb 16 14:13:22 2011 -0600
@@ -284,6 +284,7 @@
archive create an unversioned archive of a repository revision
backout reverse effect of earlier changeset
bisect subdivision search of changesets
+ bookmarks track a line of development with movable markers
branch set or show the current branch name
branches list repository named branches
bundle create a changegroup file
@@ -360,6 +361,7 @@
archive create an unversioned archive of a repository revision
backout reverse effect of earlier changeset
bisect subdivision search of changesets
+ bookmarks track a line of development with movable markers
branch set or show the current branch name
branches list repository named branches
bundle create a changegroup file
--- a/tests/test-hardlinks-safety.t Sat Feb 12 16:08:41 2011 +0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
-some implementations of cp can't create hardlinks
-
- $ cat > cp.py <<EOF
- > from mercurial import util
- > import sys
- > util.copyfiles(sys.argv[1], sys.argv[2], hardlink=True)
- > EOF
-
-Test hardlinking outside hg:
-
- $ mkdir x
- $ echo foo > x/a
-
- $ python cp.py x y
- $ echo bar >> y/a
-
-No diff if hardlink:
-
- $ diff x/a y/a
-
-Test mq hardlinking:
-
- $ echo "[extensions]" >> $HGRCPATH
- $ echo "mq=" >> $HGRCPATH
-
- $ hg init a
- $ cd a
-
- $ hg qimport -n foo - << EOF
- > # HG changeset patch
- > # Date 1 0
- > diff -r 2588a8b53d66 a
- > --- /dev/null Thu Jan 01 00:00:00 1970 +0000
- > +++ b/a Wed Jul 23 15:54:29 2008 +0200
- > @@ -0,0 +1,1 @@
- > +a
- > EOF
- adding foo to series file
-
- $ hg qpush
- applying foo
- now at: foo
-
- $ cd ..
- $ python cp.py a b
- $ cd b
-
- $ hg qimport -n bar - << EOF
- > # HG changeset patch
- > # Date 2 0
- > diff -r 2588a8b53d66 a
- > --- /dev/null Thu Jan 01 00:00:00 1970 +0000
- > +++ b/b Wed Jul 23 15:54:29 2008 +0200
- > @@ -0,0 +1,1 @@
- > +b
- > EOF
- adding bar to series file
-
- $ hg qpush
- applying bar
- now at: bar
-
- $ cat .hg/patches/status
- 430ed4828a74fa4047bc816a25500f7472ab4bfe:foo
- 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c:bar
-
- $ cat .hg/patches/series
- foo
- bar
-
- $ cat ../a/.hg/patches/status
- 430ed4828a74fa4047bc816a25500f7472ab4bfe:foo
-
- $ cat ../a/.hg/patches/series
- foo
-
-Test tags hardlinking:
-
- $ hg qdel -r qbase:qtip
- patch foo finalized without changeset message
- patch bar finalized without changeset message
-
- $ hg tag -l lfoo
- $ hg tag foo
-
- $ cd ..
- $ python cp.py b c
- $ cd c
-
- $ hg tag -l -r 0 lbar
- $ hg tag -r 0 bar
-
- $ cat .hgtags
- 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c foo
- 430ed4828a74fa4047bc816a25500f7472ab4bfe bar
-
- $ cat .hg/localtags
- 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c lfoo
- 430ed4828a74fa4047bc816a25500f7472ab4bfe lbar
-
- $ cat ../b/.hgtags
- 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c foo
-
- $ cat ../b/.hg/localtags
- 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c lfoo
-
--- a/tests/test-hardlinks.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-hardlinks.t Wed Feb 16 14:13:22 2011 -0600
@@ -10,6 +10,19 @@
> find $1 -type f | python $TESTTMP/nlinks.py
> }
+Some implementations of cp can't create hardlinks (replaces 'cp -al' on Linux):
+
+ $ cat > linkcp.py <<EOF
+ > from mercurial import util
+ > import sys
+ > util.copyfiles(sys.argv[1], sys.argv[2], hardlink=True)
+ > EOF
+
+ $ linkcp()
+ > {
+ > python $TESTTMP/linkcp.py $1 $2
+ > }
+
Prepare repo r1:
$ mkdir r1
@@ -152,3 +165,167 @@
1 r2/.hg/store/data/f1.i
1 r2/.hg/store/fncache
+
+ $ cd r3
+ $ hg tip --template '{rev}:{node|short}\n'
+ 11:a6451b6bc41f
+ $ echo bla > f1
+ $ hg ci -m1
+ $ cd ..
+
+Create hardlinked copy r4 of r3 (on Linux, we would call 'cp -al'):
+
+ $ linkcp r3 r4
+
+r4 has hardlinks in the working dir (not just inside .hg):
+
+ $ nlinksdir r4
+ 2 r4/.hg/00changelog.i
+ 2 r4/.hg/branch
+ 2 r4/.hg/cache/branchheads
+ 2 r4/.hg/cache/tags
+ 2 r4/.hg/dirstate
+ 2 r4/.hg/hgrc
+ 2 r4/.hg/last-message.txt
+ 2 r4/.hg/requires
+ 2 r4/.hg/store/00changelog.i
+ 2 r4/.hg/store/00manifest.i
+ 2 r4/.hg/store/data/d1/f2.d
+ 2 r4/.hg/store/data/d1/f2.i
+ 2 r4/.hg/store/data/f1.i
+ 2 r4/.hg/store/fncache
+ 2 r4/.hg/store/undo
+ 2 r4/.hg/undo.branch
+ 2 r4/.hg/undo.desc
+ 2 r4/.hg/undo.dirstate
+ 2 r4/d1/data1
+ 2 r4/d1/f2
+ 2 r4/f1
+
+Update back to revision 11 in r4 should break hardlink of file f1:
+
+ $ hg -R r4 up 11
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ nlinksdir r4
+ 2 r4/.hg/00changelog.i
+ 1 r4/.hg/branch
+ 2 r4/.hg/cache/branchheads
+ 2 r4/.hg/cache/tags
+ 1 r4/.hg/dirstate
+ 2 r4/.hg/hgrc
+ 2 r4/.hg/last-message.txt
+ 2 r4/.hg/requires
+ 2 r4/.hg/store/00changelog.i
+ 2 r4/.hg/store/00manifest.i
+ 2 r4/.hg/store/data/d1/f2.d
+ 2 r4/.hg/store/data/d1/f2.i
+ 2 r4/.hg/store/data/f1.i
+ 2 r4/.hg/store/fncache
+ 2 r4/.hg/store/undo
+ 2 r4/.hg/undo.branch
+ 2 r4/.hg/undo.desc
+ 2 r4/.hg/undo.dirstate
+ 2 r4/d1/data1
+ 2 r4/d1/f2
+ 1 r4/f1
+
+
+Test hardlinking outside hg:
+
+ $ mkdir x
+ $ echo foo > x/a
+
+ $ linkcp x y
+ $ echo bar >> y/a
+
+No diff if hardlink:
+
+ $ diff x/a y/a
+
+Test mq hardlinking:
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+
+ $ hg init a
+ $ cd a
+
+ $ hg qimport -n foo - << EOF
+ > # HG changeset patch
+ > # Date 1 0
+ > diff -r 2588a8b53d66 a
+ > --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ > +++ b/a Wed Jul 23 15:54:29 2008 +0200
+ > @@ -0,0 +1,1 @@
+ > +a
+ > EOF
+ adding foo to series file
+
+ $ hg qpush
+ applying foo
+ now at: foo
+
+ $ cd ..
+ $ linkcp a b
+ $ cd b
+
+ $ hg qimport -n bar - << EOF
+ > # HG changeset patch
+ > # Date 2 0
+ > diff -r 2588a8b53d66 a
+ > --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ > +++ b/b Wed Jul 23 15:54:29 2008 +0200
+ > @@ -0,0 +1,1 @@
+ > +b
+ > EOF
+ adding bar to series file
+
+ $ hg qpush
+ applying bar
+ now at: bar
+
+ $ cat .hg/patches/status
+ 430ed4828a74fa4047bc816a25500f7472ab4bfe:foo
+ 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c:bar
+
+ $ cat .hg/patches/series
+ foo
+ bar
+
+ $ cat ../a/.hg/patches/status
+ 430ed4828a74fa4047bc816a25500f7472ab4bfe:foo
+
+ $ cat ../a/.hg/patches/series
+ foo
+
+Test tags hardlinking:
+
+ $ hg qdel -r qbase:qtip
+ patch foo finalized without changeset message
+ patch bar finalized without changeset message
+
+ $ hg tag -l lfoo
+ $ hg tag foo
+
+ $ cd ..
+ $ linkcp b c
+ $ cd c
+
+ $ hg tag -l -r 0 lbar
+ $ hg tag -r 0 bar
+
+ $ cat .hgtags
+ 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c foo
+ 430ed4828a74fa4047bc816a25500f7472ab4bfe bar
+
+ $ cat .hg/localtags
+ 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c lfoo
+ 430ed4828a74fa4047bc816a25500f7472ab4bfe lbar
+
+ $ cat ../b/.hgtags
+ 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c foo
+
+ $ cat ../b/.hg/localtags
+ 4e7abb4840c46a910f6d7b4d3c3fc7e5209e684c lfoo
+
--- a/tests/test-help.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-help.t Wed Feb 16 14:13:22 2011 -0600
@@ -55,6 +55,7 @@
archive create an unversioned archive of a repository revision
backout reverse effect of earlier changeset
bisect subdivision search of changesets
+ bookmarks track a line of development with movable markers
branch set or show the current branch name
branches list repository named branches
bundle create a changegroup file
@@ -127,6 +128,7 @@
archive create an unversioned archive of a repository revision
backout reverse effect of earlier changeset
bisect subdivision search of changesets
+ bookmarks track a line of development with movable markers
branch set or show the current branch name
branches list repository named branches
bundle create a changegroup file
@@ -649,6 +651,7 @@
archive create an unversioned archive of a repository revision
backout reverse effect of earlier changeset
bisect subdivision search of changesets
+ bookmarks track a line of development with movable markers
branch set or show the current branch name
branches list repository named branches
bundle create a changegroup file
--- a/tests/test-hgignore.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-hgignore.t Wed Feb 16 14:13:22 2011 -0600
@@ -120,3 +120,5 @@
$ hg status .
A b.o
+ $ hg debugignore
+ (?:(?:|.*/)[^/]*(?:/|$))
--- a/tests/test-hgwebdir.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-hgwebdir.t Wed Feb 16 14:13:22 2011 -0600
@@ -99,6 +99,7 @@
> rcoll=$root/**
> star=*
> starstar=**
+ > astar=webdir/a/*
> EOF
$ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
> -A access-paths.log -E error-paths-2.log
@@ -130,6 +131,8 @@
/starstar/webdir/b/
/starstar/webdir/b/d/
/starstar/webdir/c/
+ /astar/
+ /astar/.hg/patches/
$ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/?style=paper'
200 Script output follows
@@ -322,6 +325,22 @@
<td class="indexlinks"></td>
</tr>
+ <tr class="parity0">
+ <td><a href="/astar/?style=paper">astar</a></td>
+ <td>unknown</td>
+ <td>Foo Bar <foo.bar@example.com></td>
+ <td class="age">* ago</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
+ <tr class="parity1">
+ <td><a href="/astar/.hg/patches/?style=paper">astar/.hg/patches</a></td>
+ <td>unknown</td>
+ <td>Foo Bar <foo.bar@example.com></td>
+ <td class="age">* ago</td> (glob)
+ <td class="indexlinks"></td>
+ </tr>
+
</table>
</div>
</div>
@@ -470,7 +489,7 @@
a
-est [paths] '**' extension
+Test [paths] '**' extension
$ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/rcoll/?style=raw'
200 Script output follows
@@ -486,6 +505,12 @@
200 Script output follows
d
+
+Test [paths] '*' in a repo root
+
+ $ hg id http://localhost:$HGPORT1/astar
+ 8580ff50825a
+
$ "$TESTDIR/killdaemons.py"
$ cat > paths.conf <<EOF
> [paths]
--- a/tests/test-hook.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-hook.t Wed Feb 16 14:13:22 2011 -0600
@@ -1,18 +1,16 @@
- $ cp "$TESTDIR"/printenv.py .
-
commit hooks can see env vars
$ hg init a
$ cd a
$ echo "[hooks]" > .hg/hgrc
- $ echo 'commit = unset HG_LOCAL HG_TAG; python ../printenv.py commit' >> .hg/hgrc
- $ echo 'commit.b = unset HG_LOCAL HG_TAG; python ../printenv.py commit.b' >> .hg/hgrc
- $ echo 'precommit = unset HG_LOCAL HG_NODE HG_TAG; python ../printenv.py precommit' >> .hg/hgrc
- $ echo 'pretxncommit = unset HG_LOCAL HG_TAG; python ../printenv.py pretxncommit' >> .hg/hgrc
+ $ echo 'commit = unset HG_LOCAL HG_TAG; python "$TESTDIR"/printenv.py commit' >> .hg/hgrc
+ $ echo 'commit.b = unset HG_LOCAL HG_TAG; python "$TESTDIR"/printenv.py commit.b' >> .hg/hgrc
+ $ echo 'precommit = unset HG_LOCAL HG_NODE HG_TAG; python "$TESTDIR"/printenv.py precommit' >> .hg/hgrc
+ $ echo 'pretxncommit = unset HG_LOCAL HG_TAG; python "$TESTDIR"/printenv.py pretxncommit' >> .hg/hgrc
$ echo 'pretxncommit.tip = hg -q tip' >> .hg/hgrc
- $ echo 'pre-identify = python ../printenv.py pre-identify 1' >> .hg/hgrc
- $ echo 'pre-cat = python ../printenv.py pre-cat' >> .hg/hgrc
- $ echo 'post-cat = python ../printenv.py post-cat' >> .hg/hgrc
+ $ echo 'pre-identify = python "$TESTDIR"/printenv.py pre-identify 1' >> .hg/hgrc
+ $ echo 'pre-cat = python "$TESTDIR"/printenv.py pre-cat' >> .hg/hgrc
+ $ echo 'post-cat = python "$TESTDIR"/printenv.py post-cat' >> .hg/hgrc
$ echo a > a
$ hg add a
$ hg commit -m a
@@ -30,9 +28,9 @@
changegroup hooks can see env vars
$ echo '[hooks]' > .hg/hgrc
- $ echo 'prechangegroup = python ../printenv.py prechangegroup' >> .hg/hgrc
- $ echo 'changegroup = python ../printenv.py changegroup' >> .hg/hgrc
- $ echo 'incoming = python ../printenv.py incoming' >> .hg/hgrc
+ $ echo 'prechangegroup = python "$TESTDIR"/printenv.py prechangegroup' >> .hg/hgrc
+ $ echo 'changegroup = python "$TESTDIR"/printenv.py changegroup' >> .hg/hgrc
+ $ echo 'incoming = python "$TESTDIR"/printenv.py incoming' >> .hg/hgrc
pretxncommit and commit hooks can see both parents of merge
@@ -68,21 +66,21 @@
test generic hooks
$ hg id
- pre-identify hook: HG_ARGS=id HG_OPTS={'tags': None, 'rev': '', 'num': None, 'branch': None, 'id': None} HG_PATS=[]
+ pre-identify hook: HG_ARGS=id HG_OPTS={'branch': None, 'id': None, 'num': None, 'rev': '', 'tags': None} HG_PATS=[]
warning: pre-identify hook exited with status 1
[1]
$ hg cat b
- pre-cat hook: HG_ARGS=cat b HG_OPTS={'rev': '', 'decode': None, 'exclude': [], 'output': '', 'include': []} HG_PATS=['b']
- post-cat hook: HG_ARGS=cat b HG_OPTS={'rev': '', 'decode': None, 'exclude': [], 'output': '', 'include': []} HG_PATS=['b'] HG_RESULT=0
+ pre-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b']
b
+ post-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b'] HG_RESULT=0
$ cd ../b
$ hg pull ../a
- prechangegroup hook: HG_SOURCE=pull HG_URL=file:
- changegroup hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:
- incoming hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:
- incoming hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_SOURCE=pull HG_URL=file:
- incoming hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_URL=file:
+ prechangegroup hook: HG_SOURCE=pull HG_URL=file:$TESTTMP/a
+ changegroup hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:$TESTTMP/a
+ incoming hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:$TESTTMP/a
+ incoming hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_SOURCE=pull HG_URL=file:$TESTTMP/a
+ incoming hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_URL=file:$TESTTMP/a
pulling from ../a
searching for changes
adding changesets
@@ -94,8 +92,8 @@
tag hooks can see env vars
$ cd ../a
- $ echo 'pretag = python ../printenv.py pretag' >> .hg/hgrc
- $ echo 'tag = unset HG_PARENT1 HG_PARENT2; python ../printenv.py tag' >> .hg/hgrc
+ $ echo 'pretag = python "$TESTDIR"/printenv.py pretag' >> .hg/hgrc
+ $ echo 'tag = unset HG_PARENT1 HG_PARENT2; python "$TESTDIR"/printenv.py tag' >> .hg/hgrc
$ hg tag -d '3 0' a
pretag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
precommit hook: HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
@@ -110,7 +108,7 @@
pretag hook can forbid tagging
- $ echo 'pretag.forbid = python ../printenv.py pretag.forbid 1' >> .hg/hgrc
+ $ echo 'pretag.forbid = python "$TESTDIR"/printenv.py pretag.forbid 1' >> .hg/hgrc
$ hg tag -d '4 0' fa
pretag hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
pretag.forbid hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
@@ -126,7 +124,7 @@
more there after
$ echo 'pretxncommit.forbid0 = hg tip -q' >> .hg/hgrc
- $ echo 'pretxncommit.forbid1 = python ../printenv.py pretxncommit.forbid 1' >> .hg/hgrc
+ $ echo 'pretxncommit.forbid1 = python "$TESTDIR"/printenv.py pretxncommit.forbid 1' >> .hg/hgrc
$ echo z > z
$ hg add z
$ hg -q tip
@@ -146,7 +144,7 @@
precommit hook can prevent commit
- $ echo 'precommit.forbid = python ../printenv.py precommit.forbid 1' >> .hg/hgrc
+ $ echo 'precommit.forbid = python "$TESTDIR"/printenv.py precommit.forbid 1' >> .hg/hgrc
$ hg commit -m 'fail' -d '4 0'
precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
precommit.forbid hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
@@ -157,14 +155,14 @@
preupdate hook can prevent update
- $ echo 'preupdate = python ../printenv.py preupdate' >> .hg/hgrc
+ $ echo 'preupdate = python "$TESTDIR"/printenv.py preupdate' >> .hg/hgrc
$ hg update 1
preupdate hook: HG_PARENT1=ab228980c14d
0 files updated, 0 files merged, 2 files removed, 0 files unresolved
update hook
- $ echo 'update = python ../printenv.py update' >> .hg/hgrc
+ $ echo 'update = python "$TESTDIR"/printenv.py update' >> .hg/hgrc
$ hg update
preupdate hook: HG_PARENT1=539e4b31b6dc
update hook: HG_ERROR=0 HG_PARENT1=539e4b31b6dc
@@ -176,9 +174,9 @@
$ hg -q tip
3:07f3376c1e65
$ echo '[hooks]' > .hg/hgrc
- $ echo 'prechangegroup.forbid = python ../printenv.py prechangegroup.forbid 1' >> .hg/hgrc
+ $ echo 'prechangegroup.forbid = python "$TESTDIR"/printenv.py prechangegroup.forbid 1' >> .hg/hgrc
$ hg pull ../a
- prechangegroup.forbid hook: HG_SOURCE=pull HG_URL=file:
+ prechangegroup.forbid hook: HG_SOURCE=pull HG_URL=file:$TESTTMP/a
pulling from ../a
searching for changes
abort: prechangegroup.forbid hook exited with status 1
@@ -189,10 +187,10 @@
$ echo '[hooks]' > .hg/hgrc
$ echo 'pretxnchangegroup.forbid0 = hg tip -q' >> .hg/hgrc
- $ echo 'pretxnchangegroup.forbid1 = python ../printenv.py pretxnchangegroup.forbid 1' >> .hg/hgrc
+ $ echo 'pretxnchangegroup.forbid1 = python "$TESTDIR"/printenv.py pretxnchangegroup.forbid 1' >> .hg/hgrc
$ hg pull ../a
4:539e4b31b6dc
- pretxnchangegroup.forbid hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/b HG_SOURCE=pull HG_URL=file:
+ pretxnchangegroup.forbid hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/b HG_SOURCE=pull HG_URL=file:$TESTTMP/a
pulling from ../a
searching for changes
adding changesets
@@ -210,8 +208,8 @@
$ rm .hg/hgrc
$ echo '[hooks]' > ../a/.hg/hgrc
- $ echo 'preoutgoing = python ../printenv.py preoutgoing' >> ../a/.hg/hgrc
- $ echo 'outgoing = python ../printenv.py outgoing' >> ../a/.hg/hgrc
+ $ echo 'preoutgoing = python "$TESTDIR"/printenv.py preoutgoing' >> ../a/.hg/hgrc
+ $ echo 'outgoing = python "$TESTDIR"/printenv.py outgoing' >> ../a/.hg/hgrc
$ hg pull ../a
preoutgoing hook: HG_SOURCE=pull
outgoing hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_SOURCE=pull
@@ -227,7 +225,7 @@
preoutgoing hook can prevent outgoing changes
- $ echo 'preoutgoing.forbid = python ../printenv.py preoutgoing.forbid 1' >> ../a/.hg/hgrc
+ $ echo 'preoutgoing.forbid = python "$TESTDIR"/printenv.py preoutgoing.forbid 1' >> ../a/.hg/hgrc
$ hg pull ../a
preoutgoing hook: HG_SOURCE=pull
preoutgoing.forbid hook: HG_SOURCE=pull
@@ -240,8 +238,8 @@
$ cd ..
$ echo '[hooks]' > a/.hg/hgrc
- $ echo 'preoutgoing = python ../printenv.py preoutgoing' >> a/.hg/hgrc
- $ echo 'outgoing = python ../printenv.py outgoing' >> a/.hg/hgrc
+ $ echo 'preoutgoing = python "$TESTDIR"/printenv.py preoutgoing' >> a/.hg/hgrc
+ $ echo 'outgoing = python "$TESTDIR"/printenv.py outgoing' >> a/.hg/hgrc
$ hg clone a c
preoutgoing hook: HG_SOURCE=clone
outgoing hook: HG_NODE=0000000000000000000000000000000000000000 HG_SOURCE=clone
@@ -251,7 +249,7 @@
preoutgoing hook can prevent outgoing changes for local clones
- $ echo 'preoutgoing.forbid = python ../printenv.py preoutgoing.forbid 1' >> a/.hg/hgrc
+ $ echo 'preoutgoing.forbid = python "$TESTDIR"/printenv.py preoutgoing.forbid 1' >> a/.hg/hgrc
$ hg clone a zzz
preoutgoing hook: HG_SOURCE=clone
preoutgoing.forbid hook: HG_SOURCE=clone
--- a/tests/test-http-proxy.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-http-proxy.t Wed Feb 16 14:13:22 2011 -0600
@@ -104,13 +104,21 @@
* - - [*] "GET http://localhost:$HGPORT/?pairs=0000000000000000000000000000000000000000-0000000000000000000000000000000000000000&cmd=between HTTP/1.1" - - (glob)
* - - [*] "GET http://localhost:$HGPORT/?cmd=heads HTTP/1.1" - - (glob)
* - - [*] "GET http://localhost:$HGPORT/?cmd=changegroup&roots=0000000000000000000000000000000000000000 HTTP/1.1" - - (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys&namespace=bookmarks HTTP/1.1" - - (glob)
* - - [*] "GET http://localhost:$HGPORT/?pairs=0000000000000000000000000000000000000000-0000000000000000000000000000000000000000&cmd=between HTTP/1.1" - - (glob)
* - - [*] "GET http://localhost:$HGPORT/?cmd=heads HTTP/1.1" - - (glob)
* - - [*] "GET http://localhost:$HGPORT/?cmd=changegroup&roots=0000000000000000000000000000000000000000 HTTP/1.1" - - (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys&namespace=bookmarks HTTP/1.1" - - (glob)
* - - [*] "GET http://localhost:$HGPORT/?pairs=0000000000000000000000000000000000000000-0000000000000000000000000000000000000000&cmd=between HTTP/1.1" - - (glob)
* - - [*] "GET http://localhost:$HGPORT/?cmd=heads HTTP/1.1" - - (glob)
* - - [*] "GET http://localhost:$HGPORT/?cmd=changegroup&roots=0000000000000000000000000000000000000000 HTTP/1.1" - - (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys&namespace=bookmarks HTTP/1.1" - - (glob)
* - - [*] "GET http://localhost:$HGPORT/?pairs=0000000000000000000000000000000000000000-0000000000000000000000000000000000000000&cmd=between HTTP/1.1" - - (glob)
* - - [*] "GET http://localhost:$HGPORT/?cmd=heads HTTP/1.1" - - (glob)
* - - [*] "GET http://localhost:$HGPORT/?cmd=changegroup&roots=0000000000000000000000000000000000000000 HTTP/1.1" - - (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys&namespace=bookmarks HTTP/1.1" - - (glob)
--- a/tests/test-http.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-http.t Wed Feb 16 14:13:22 2011 -0600
@@ -1,5 +1,4 @@
- $ cp "$TESTDIR"/printenv.py .
$ hg init test
$ cd test
$ echo foo>foo
@@ -75,7 +74,7 @@
$ cd copy-pull
$ echo '[hooks]' >> .hg/hgrc
- $ echo 'changegroup = python ../printenv.py changegroup' >> .hg/hgrc
+ $ echo 'changegroup = python "$TESTDIR"/printenv.py changegroup' >> .hg/hgrc
$ hg pull
changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_URL=http://localhost:$HGPORT1/
pulling from http://localhost:$HGPORT1/
--- a/tests/test-https.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-https.t Wed Feb 16 14:13:22 2011 -0600
@@ -112,6 +112,7 @@
adding manifests
adding file changes
added 1 changesets with 4 changes to 4 files
+ warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
updating to branch default
4 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg verify -R copy-pull
@@ -140,6 +141,7 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
+ warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
(run 'hg update' to get a working copy)
$ cd ..
@@ -222,3 +224,45 @@
- ignores that certificate doesn't match hostname
$ hg -R copy-pull id https://127.0.0.1:$HGPORT/
5fed3813f7f5
+
+Prepare for connecting through proxy
+
+ $ kill `cat hg1.pid`
+ $ sleep 1
+
+ $ ("$TESTDIR/tinyproxy.py" $HGPORT1 localhost >proxy.log 2>&1 </dev/null &
+ $ echo $! > proxy.pid)
+ $ cat proxy.pid >> $DAEMON_PIDS
+ $ sleep 2
+
+ $ echo "[http_proxy]" >> copy-pull/.hg/hgrc
+ $ echo "always=True" >> copy-pull/.hg/hgrc
+ $ echo "[hostfingerprints]" >> copy-pull/.hg/hgrc
+ $ echo "localhost =" >> copy-pull/.hg/hgrc
+
+Test unvalidated https through proxy
+
+ $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --insecure --traceback
+ pulling from https://localhost:$HGPORT/
+ searching for changes
+ no changes found
+
+Test https with cacert and fingerprint through proxy
+
+ $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --config web.cacerts=pub.pem
+ pulling from https://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull https://127.0.0.1:$HGPORT/
+ pulling from https://127.0.0.1:$HGPORT/
+ searching for changes
+ no changes found
+
+Test https with cert problems through proxy
+
+ $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --config web.cacerts=pub-other.pem
+ abort: error: _ssl.c:499: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
+ [255]
+ $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --config web.cacerts=pub-expired.pem https://localhost:$HGPORT2/
+ abort: error: _ssl.c:499: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
+ [255]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-i18n.t Wed Feb 16 14:13:22 2011 -0600
@@ -0,0 +1,20 @@
+Test that translations are compiled and installed correctly.
+
+Default encoding in tests is "ascii" and the translation is encoded
+using the "replace" error handler:
+
+ $ LANGUAGE=pt_BR hg tip
+ abortado: N?o h? um reposit?rio do Mercurial aqui (.hg n?o encontrado)!
+ [255]
+
+Using a more accomodating encoding:
+
+ $ HGENCODING=UTF-8 LANGUAGE=pt_BR hg tip
+ abortado: N\xc3\xa3o h\xc3\xa1 um reposit\xc3\xb3rio do Mercurial aqui (.hg n\xc3\xa3o encontrado)! (esc)
+ [255]
+
+Different encoding:
+
+ $ HGENCODING=Latin-1 LANGUAGE=pt_BR hg tip
+ abortado: N\xe3o h\xe1 um reposit\xf3rio do Mercurial aqui (.hg n\xe3o encontrado)! (esc)
+ [255]
--- a/tests/test-import.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-import.t Wed Feb 16 14:13:22 2011 -0600
@@ -437,6 +437,13 @@
$ hg revert -a
reverting a
+
+import with --no-commit should have written .hg/last-message.txt
+
+ $ cat .hg/last-message.txt
+ change (no-eol)
+
+
test fuzziness with eol=auto
$ hg --config patch.eol=auto import --no-commit -v tip.patch
--- a/tests/test-inherit-mode.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-inherit-mode.t Wed Feb 16 14:13:22 2011 -0600
@@ -105,7 +105,8 @@
$ python ../printmodes.py ../push
00770 ../push/.hg/
00660 ../push/.hg/00changelog.i
- 00660 ../push/.hg/branchheads.cache
+ 00770 ../push/.hg/cache/
+ 00660 ../push/.hg/cache/branchheads
00660 ../push/.hg/requires
00770 ../push/.hg/store/
00660 ../push/.hg/store/00changelog.i
--- a/tests/test-issue619.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-issue619.t Wed Feb 16 14:13:22 2011 -0600
@@ -19,7 +19,12 @@
$ hg merge b
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
+ $ hg branch
+ default
+ $ hg parent --template '{rev}:{node|short} {branches}: {desc}\n'
+ 1:06c2121185be b: b
$ hg ci -Ammerge
+ created new head
Bogus fast-forward should fail:
--- a/tests/test-keyword.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-keyword.t Wed Feb 16 14:13:22 2011 -0600
@@ -17,6 +17,8 @@
keyword =
[keyword]
demo.txt =
+ [keywordset]
+ svn = False
[keywordmaps]
Author = {author|user}
Date = {date|utcdate}
@@ -40,6 +42,8 @@
keyword =
[keyword]
demo.txt =
+ [keywordset]
+ svn = False
[keywordmaps]
Branch = {branches}
$Branch: demobranch $
@@ -633,6 +637,8 @@
b = ignore
demo.txt =
i = ignore
+ [keywordset]
+ svn = False
[keywordmaps]
Xinfo = {author}: {desc}
$Xinfo: test: hg keyword configuration and expansion example $
--- a/tests/test-minirst.py Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-minirst.py Wed Feb 16 14:13:22 2011 -0600
@@ -120,16 +120,19 @@
There is support for simple option lists,
but only with long options:
---all Output all.
---both Output both (this description is
- quite long).
---long Output all day long.
+-X, --exclude filter an option with a short and long option with an argument
+-I, --include an option with both a short option and a long option
+--all Output all.
+--both Output both (this description is
+ quite long).
+--long Output all day long.
---par This option has two paragraphs in its description.
- This is the first.
+--par This option has two paragraphs in its description.
+ This is the first.
- This is the second. Blank lines may be omitted between
- options (as above) or left in (as here).
+ This is the second. Blank lines may be omitted between
+ options (as above) or left in (as here).
+
The next paragraph looks like an option list, but lacks the two-space
marker after the option. It is treated as a normal paragraph:
@@ -221,6 +224,10 @@
.. An indented comment
Some indented text.
+
+..
+
+Empty comment above
"""
debugformat('comments', comments, 30)
--- a/tests/test-minirst.py.out Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-minirst.py.out Wed Feb 16 14:13:22 2011 -0600
@@ -180,14 +180,20 @@
There is support for simple option lists, but only with long
options:
---all Output all.
---both Output both (this description is quite long).
---long Output all day long.
---par This option has two paragraphs in its
- description. This is the first.
+ -X --exclude filter an option with a short and long option
+ with an argument
+ -I --include an option with both a short option and
+ a long option
+ --all Output all.
+ --both Output both (this description is quite
+ long).
+ --long Output all day long.
+ --par This option has two paragraphs in its
+ description. This is the first.
- This is the second. Blank lines may be omitted
- between options (as above) or left in (as here).
+ This is the second. Blank lines may
+ be omitted between options (as above)
+ or left in (as here).
The next paragraph looks like an option list, but lacks the
two-space marker after the option. It is treated as a normal
@@ -202,23 +208,62 @@
option lists, but only with
long options:
---all Output all.
---both Output both (this
- description is
- quite long).
---long Output all day
- long.
---par This option has two
- paragraphs in its
- description. This
- is the first.
+ -X --exclude filter an
+ option
+ with a
+ short
+ and
+ long
+ option
+ with an
+ argumen
+ t
+ -I --include an
+ option
+ with
+ both a
+ short
+ option
+ and a
+ long
+ option
+ --all Output
+ all.
+ --both Output
+ both
+ (this d
+ escript
+ ion is
+ quite
+ long).
+ --long Output
+ all day
+ long.
+ --par This
+ option
+ has two
+ paragra
+ phs in
+ its des
+ criptio
+ n. This
+ is the
+ first.
- This is the second.
- Blank lines may be
- omitted between
- options (as above)
- or left in (as
- here).
+ This is
+ the
+ second.
+ Blank
+ lines
+ may be
+ omitted
+ between
+ options
+ (as
+ above)
+ or left
+ in (as
+ here).
The next paragraph looks like
an option list, but lacks the
@@ -339,5 +384,7 @@
Some text.
Some indented text.
+
+Empty comment above
----------------------------------------------------------------------
--- a/tests/test-mq-caches.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-mq-caches.t Wed Feb 16 14:13:22 2011 -0600
@@ -1,4 +1,4 @@
- $ branches=.hg/branchheads.cache
+ $ branches=.hg/cache/branchheads
$ echo '[extensions]' >> $HGRCPATH
$ echo 'mq =' >> $HGRCPATH
--- a/tests/test-mq-qnew.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-mq-qnew.t Wed Feb 16 14:13:22 2011 -0600
@@ -107,7 +107,7 @@
abort: "foo#bar" cannot be used as the name of a patch
abort: "foo:bar" cannot be used as the name of a patch
% qnew with name containing slash
- abort: cannot write patch "foo/": (Is a|No such file or) directory (re)
+ abort: path ends in directory separator: foo/
abort: "foo" already exists as a directory
foo/bar.patch
popping foo/bar.patch
@@ -172,7 +172,7 @@
abort: "foo#bar" cannot be used as the name of a patch
abort: "foo:bar" cannot be used as the name of a patch
% qnew with name containing slash
- abort: cannot write patch "foo/": (Is a|No such file or) directory (re)
+ abort: path ends in directory separator: foo/
abort: "foo" already exists as a directory
foo/bar.patch
popping foo/bar.patch
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-mq-qpush-exact.t Wed Feb 16 14:13:22 2011 -0600
@@ -0,0 +1,290 @@
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+ $ echo "graphlog=" >> $HGRCPATH
+
+make a test repository that looks like this:
+
+o 2:28bc7b1afd6a
+|
+| @ 1:d7fe2034f71b
+|/
+o 0/62ecad8b70e5
+
+ $ hg init r0
+ $ cd r0
+ $ touch f0
+ $ hg ci -m0 -Aq
+ $ touch f1
+ $ hg ci -m1 -Aq
+
+ $ hg update 0 -q
+ $ touch f2
+ $ hg ci -m2 -Aq
+ $ hg update 1 -q
+
+make some patches with a parent: 1:d7fe2034f71b -> p0 -> p1
+
+ $ echo cp0 >> fp0
+ $ hg add fp0
+ $ hg qnew p0 -d "0 0"
+
+ $ echo cp1 >> fp1
+ $ hg add fp1
+ $ hg qnew p1 -d "0 0"
+
+ $ hg qpop -aq
+ patch queue now empty
+
+qpush --exact when at the parent
+
+ $ hg update 1 -q
+ $ hg qpush -e
+ applying p0
+ now at: p0
+ $ hg parents -qr qbase
+ 1:d7fe2034f71b
+ $ hg qpop -aq
+ patch queue now empty
+
+ $ hg qpush -e p0
+ applying p0
+ now at: p0
+ $ hg parents -qr qbase
+ 1:d7fe2034f71b
+ $ hg qpop -aq
+ patch queue now empty
+
+ $ hg qpush -e p1
+ applying p0
+ applying p1
+ now at: p1
+ $ hg parents -qr qbase
+ 1:d7fe2034f71b
+ $ hg qpop -aq
+ patch queue now empty
+
+ $ hg qpush -ea
+ applying p0
+ applying p1
+ now at: p1
+ $ hg parents -qr qbase
+ 1:d7fe2034f71b
+ $ hg qpop -aq
+ patch queue now empty
+
+qpush --exact when at another rev
+
+ $ hg update 0 -q
+ $ hg qpush -e
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ applying p0
+ now at: p0
+ $ hg parents -qr qbase
+ 1:d7fe2034f71b
+ $ hg qpop -aq
+ patch queue now empty
+
+ $ hg update 0 -q
+ $ hg qpush -e p0
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ applying p0
+ now at: p0
+ $ hg parents -qr qbase
+ 1:d7fe2034f71b
+ $ hg qpop -aq
+ patch queue now empty
+
+ $ hg update 0 -q
+ $ hg qpush -e p1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ applying p0
+ applying p1
+ now at: p1
+ $ hg parents -qr qbase
+ 1:d7fe2034f71b
+ $ hg qpop -aq
+ patch queue now empty
+
+ $ hg update 0 -q
+ $ hg qpush -ea
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ applying p0
+ applying p1
+ now at: p1
+ $ hg parents -qr qbase
+ 1:d7fe2034f71b
+ $ hg qpop -aq
+ patch queue now empty
+
+qpush --exact while crossing branches
+
+ $ hg update 2 -q
+ $ hg qpush -e
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ applying p0
+ now at: p0
+ $ hg parents -qr qbase
+ 1:d7fe2034f71b
+ $ hg qpop -aq
+ patch queue now empty
+
+ $ hg update 2 -q
+ $ hg qpush -e p0
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ applying p0
+ now at: p0
+ $ hg parents -qr qbase
+ 1:d7fe2034f71b
+ $ hg qpop -aq
+ patch queue now empty
+
+ $ hg update 2 -q
+ $ hg qpush -e p1
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ applying p0
+ applying p1
+ now at: p1
+ $ hg parents -qr qbase
+ 1:d7fe2034f71b
+ $ hg qpop -aq
+ patch queue now empty
+
+ $ hg update 2 -q
+ $ hg qpush -ea
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ applying p0
+ applying p1
+ now at: p1
+ $ hg parents -qr qbase
+ 1:d7fe2034f71b
+ $ hg qpop -aq
+ patch queue now empty
+
+qpush --exact --force with changes to an unpatched file
+
+ $ hg update 1 -q
+ $ echo c0 >> f0
+ $ hg qpush -e
+ abort: local changes found, refresh first
+ [255]
+ $ hg qpush -ef
+ applying p0
+ now at: p0
+ $ cat f0
+ c0
+ $ rm f0
+ $ touch f0
+ $ hg qpop -aq
+ patch queue now empty
+
+ $ hg update 1 -q
+ $ echo c0 >> f0
+ $ hg qpush -e p1
+ abort: local changes found, refresh first
+ [255]
+ $ hg qpush -e p1 -f
+ applying p0
+ applying p1
+ now at: p1
+ $ cat f0
+ c0
+ $ rm f0
+ $ touch f0
+ $ hg qpop -aq
+ patch queue now empty
+
+qpush --exact --force with changes to a patched file
+
+ $ hg update 1 -q
+ $ echo cp0-bad >> fp0
+ $ hg add fp0
+ $ hg qpush -e
+ abort: local changes found, refresh first
+ [255]
+ $ hg qpush -ef
+ applying p0
+ file fp0 already exists
+ 1 out of 1 hunks FAILED -- saving rejects to file fp0.rej
+ patch failed, unable to continue (try -v)
+ patch failed, rejects left in working dir
+ errors during apply, please fix and refresh p0
+ [2]
+ $ cat fp0
+ cp0-bad
+ $ cat fp0.rej
+ --- fp0
+ +++ fp0
+ @@ -0,0 +1,1 @@
+ +cp0
+ $ hg qpop -aqf
+ patch queue now empty
+ $ rm fp0
+ $ rm fp0.rej
+
+ $ hg update 1 -q
+ $ echo cp1-bad >> fp1
+ $ hg add fp1
+ $ hg qpush -e p1
+ abort: local changes found, refresh first
+ [255]
+ $ hg qpush -e p1 -f
+ applying p0
+ applying p1
+ file fp1 already exists
+ 1 out of 1 hunks FAILED -- saving rejects to file fp1.rej
+ patch failed, unable to continue (try -v)
+ patch failed, rejects left in working dir
+ errors during apply, please fix and refresh p1
+ [2]
+ $ cat fp1
+ cp1-bad
+ $ cat fp1.rej
+ --- fp1
+ +++ fp1
+ @@ -0,0 +1,1 @@
+ +cp1
+ $ hg qpop -aqf
+ patch queue now empty
+ $ rm fp1
+ $ rm fp1.rej
+
+qpush --exact when already at a patch
+
+ $ hg update 1
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg qpush -e p0
+ applying p0
+ now at: p0
+ $ hg qpush -e p1
+ abort: cannot push --exact with applied patches
+ [255]
+ $ hg qpop -aq
+ patch queue now empty
+
+qpush --exact --move should fail
+
+ $ hg qpush -e --move p1
+ abort: cannot use --exact and --move together
+ [255]
+
+qpush --exact a patch without a parent recorded
+
+ $ hg qpush -q
+ now at: p0
+ $ grep -v '# Parent' .hg/patches/p0 > p0.new
+ $ mv p0.new .hg/patches/p0
+ $ hg qpop -aq
+ patch queue now empty
+ $ hg qpush -e
+ abort: p0 does not have a parent recorded
+ [255]
+ $ hg qpush -e p0
+ abort: p0 does not have a parent recorded
+ [255]
+ $ hg qpush -e p1
+ abort: p0 does not have a parent recorded
+ [255]
+ $ hg qpush -ea
+ abort: p0 does not have a parent recorded
+ [255]
+
--- a/tests/test-mq-qrefresh.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-mq-qrefresh.t Wed Feb 16 14:13:22 2011 -0600
@@ -487,74 +487,3 @@
$ cd ..
-
-Issue2499: refuse to add .hgsub{,state} to a patch
-
- $ hg init repo-2499
- $ cd repo-2499
- $ hg qinit
- $ hg qnew -m 0 0.diff
- $ echo a > a
- $ hg init sub
- $ cd sub
- $ echo b > b
- $ hg ci -Am 0sub
- adding b
- $ cd ..
-
-test when adding
- $ echo sub = sub > .hgsub
- $ echo `hg id -i --debug sub` sub > .hgsubstate
- $ hg add
- adding .hgsub
- adding .hgsubstate
- adding a
- $ hg qrefresh
- warning: not adding .hgsub
- warning: not adding .hgsubstate
- $ hg qfinish -a
- $ hg status
- A .hgsub
- A .hgsubstate
- $ hg forget .hgsubstate
- $ rm .hgsubstate
-
-add subrepo with a real commit
- $ hg ci -m 1
- committing subrepository sub
- $ hg qnew -m 2 2.diff
-
-test when modifying
- $ echo sub2 = sub2 >> .hgsub
- $ hg qrefresh
- warning: not refreshing .hgsub
- $ echo 0000000000000000000000000000000000000000 sub2 >> .hgsubstate
- $ hg qrefresh
- warning: not refreshing .hgsub
- warning: not refreshing .hgsubstate
- $ hg revert --no-backup .hgsub .hgsubstate
-
-test when removing
- $ hg rm .hgsub
- $ hg rm .hgsubstate
- $ hg qrefresh
- warning: not removing .hgsub
- warning: not removing .hgsubstate
- $ hg status
- R .hgsub
- R .hgsubstate
- $ hg revert --no-backup .hgsub .hgsubstate
-
-test when deleting
- $ rm .hgsub .hgsubstate
- $ hg qrefresh
- warning: not removing .hgsub
- warning: not removing .hgsubstate
- warning: subrepo spec file .hgsub not found
- $ hg status
- ! .hgsub
- ! .hgsubstate
- $ hg cat -r1 .hgsub > .hgsub
- $ hg revert --no-backup .hgsubstate
-
- $ cd ..
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-mq-subrepo-svn.t Wed Feb 16 14:13:22 2011 -0600
@@ -0,0 +1,52 @@
+ $ "$TESTDIR/hghave" svn || exit 80
+
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+ $ echo "[diff]" >> $HGRCPATH
+ $ echo "nodates=1" >> $HGRCPATH
+
+fn to create new repository, and cd into it
+ $ mkrepo() {
+ > hg init $1
+ > cd $1
+ > hg qinit
+ > }
+
+
+handle svn subrepos safely
+
+ $ svnadmin create svn-repo-2499
+ $ curpath=`pwd | tr '\\\\' /`
+ $ expr "$svnpath" : "\/" > /dev/null
+ > if [ $? -ne 0 ]; then
+ > curpath="/$curpath"
+ > fi
+ $ svnurl="file://$curpath/svn-repo-2499/project"
+ $ mkdir -p svn-project-2499/trunk
+ $ svn import -m 'init project' svn-project-2499 "$svnurl"
+ Adding svn-project-2499/trunk
+
+ Committed revision 1.
+
+qnew on repo w/svn subrepo
+ $ mkrepo repo-2499-svn-subrepo
+ $ svn co "$svnurl"/trunk sub
+ Checked out revision 1.
+ $ echo 'sub = [svn]sub' >> .hgsub
+ $ hg add .hgsub
+ $ hg status -S -X '**/format'
+ A .hgsub
+ ? sub/.svn/entries
+ $ hg qnew -m0 0.diff
+ committing subrepository sub
+ $ cd sub
+ $ echo a > a
+ $ svn add a
+ A a
+ $ svn st
+ A* a (glob)
+ $ cd ..
+ $ hg status -S # doesn't show status for svn subrepos (yet)
+ $ hg qnew -m1 1.diff
+ abort: uncommitted changes in subrepository sub
+ [255]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-mq-subrepo.t Wed Feb 16 14:13:22 2011 -0600
@@ -0,0 +1,347 @@
+ $ echo "[extensions]" >> $HGRCPATH
+ $ echo "mq=" >> $HGRCPATH
+ $ echo "record=" >> $HGRCPATH
+ $ echo "[diff]" >> $HGRCPATH
+ $ echo "nodates=1" >> $HGRCPATH
+
+ $ stdin=`pwd`/stdin.tmp
+
+fn to create new repository w/dirty subrepo, and cd into it
+ $ mkrepo() {
+ > hg init $1
+ > cd $1
+ > hg qinit
+ > }
+
+fn to create dirty subrepo
+ $ mksubrepo() {
+ > hg init $1
+ > cd $1
+ > echo a > a
+ > hg add
+ > cd ..
+ > }
+
+ $ testadd() {
+ > cat - > "$stdin"
+ > mksubrepo sub
+ > echo sub = sub >> .hgsub
+ > hg add .hgsub
+ > echo % abort when adding .hgsub w/dirty subrepo
+ > hg status -S
+ > echo '%' $*
+ > cat "$stdin" | hg $*
+ > echo [$?]
+ > hg -R sub ci -m0sub
+ > echo % update substate when adding .hgsub w/clean updated subrepo
+ > hg status -S
+ > echo '%' $*
+ > cat "$stdin" | hg $*
+ > hg debugsub
+ > }
+
+ $ testmod() {
+ > cat - > "$stdin"
+ > mksubrepo sub2
+ > echo sub2 = sub2 >> .hgsub
+ > echo % abort when modifying .hgsub w/dirty subrepo
+ > hg status -S
+ > echo '%' $*
+ > cat "$stdin" | hg $*
+ > echo [$?]
+ > hg -R sub2 ci -m0sub2
+ > echo % update substate when modifying .hgsub w/clean updated subrepo
+ > hg status -S
+ > echo '%' $*
+ > cat "$stdin" | hg $*
+ > hg debugsub
+ > }
+
+ $ testrm1() {
+ > cat - > "$stdin"
+ > mksubrepo sub3
+ > echo sub3 = sub3 >> .hgsub
+ > hg ci -Aqmsub3
+ > $EXTRA
+ > echo b >> sub3/a
+ > hg rm .hgsub
+ > echo % update substate when removing .hgsub w/dirty subrepo
+ > hg status -S
+ > echo '%' $*
+ > cat "$stdin" | hg $*
+ > echo % debugsub should be empty
+ > hg debugsub
+ > }
+
+ $ testrm2() {
+ > cat - > "$stdin"
+ > mksubrepo sub4
+ > echo sub4 = sub4 >> .hgsub
+ > hg ci -Aqmsub4
+ > $EXTRA
+ > hg rm .hgsub
+ > echo % update substate when removing .hgsub w/clean updated subrepo
+ > hg status -S
+ > echo '%' $*
+ > cat "$stdin" | hg $*
+ > echo % debugsub should be empty
+ > hg debugsub
+ > }
+
+
+handle subrepos safely on qnew
+
+ $ mkrepo repo-2499-qnew
+ $ testadd qnew -m0 0.diff
+ adding a
+ % abort when adding .hgsub w/dirty subrepo
+ A .hgsub
+ A sub/a
+ % qnew -m0 0.diff
+ abort: uncommitted changes in subrepository sub
+ [255]
+ % update substate when adding .hgsub w/clean updated subrepo
+ A .hgsub
+ % qnew -m0 0.diff
+ committing subrepository sub
+ path sub
+ source sub
+ revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
+
+ $ testmod qnew -m1 1.diff
+ adding a
+ % abort when modifying .hgsub w/dirty subrepo
+ M .hgsub
+ A sub2/a
+ % qnew -m1 1.diff
+ abort: uncommitted changes in subrepository sub2
+ [255]
+ % update substate when modifying .hgsub w/clean updated subrepo
+ M .hgsub
+ % qnew -m1 1.diff
+ committing subrepository sub2
+ path sub
+ source sub
+ revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
+ path sub2
+ source sub2
+ revision 1f94c7611cc6b74f5a17b16121a1170d44776845
+
+ $ hg qpop -qa
+ patch queue now empty
+ $ testrm1 qnew -m2 2.diff
+ adding a
+ % update substate when removing .hgsub w/dirty subrepo
+ M sub3/a
+ R .hgsub
+ % qnew -m2 2.diff
+ % debugsub should be empty
+
+ $ hg qpop -qa
+ patch queue now empty
+ $ testrm2 qnew -m3 3.diff
+ adding a
+ % update substate when removing .hgsub w/clean updated subrepo
+ R .hgsub
+ % qnew -m3 3.diff
+ % debugsub should be empty
+
+ $ cd ..
+
+
+handle subrepos safely on qrefresh
+
+ $ mkrepo repo-2499-qrefresh
+ $ hg qnew -m0 0.diff
+ $ testadd qrefresh
+ adding a
+ % abort when adding .hgsub w/dirty subrepo
+ A .hgsub
+ A sub/a
+ % qrefresh
+ abort: uncommitted changes in subrepository sub
+ [255]
+ % update substate when adding .hgsub w/clean updated subrepo
+ A .hgsub
+ % qrefresh
+ committing subrepository sub
+ path sub
+ source sub
+ revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
+
+ $ hg qnew -m1 1.diff
+ $ testmod qrefresh
+ adding a
+ % abort when modifying .hgsub w/dirty subrepo
+ M .hgsub
+ A sub2/a
+ % qrefresh
+ abort: uncommitted changes in subrepository sub2
+ [255]
+ % update substate when modifying .hgsub w/clean updated subrepo
+ M .hgsub
+ % qrefresh
+ committing subrepository sub2
+ path sub
+ source sub
+ revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
+ path sub2
+ source sub2
+ revision 1f94c7611cc6b74f5a17b16121a1170d44776845
+
+ $ hg qpop -qa
+ patch queue now empty
+ $ EXTRA='hg qnew -m2 2.diff' testrm1 qrefresh
+ adding a
+ % update substate when removing .hgsub w/dirty subrepo
+ M sub3/a
+ R .hgsub
+ % qrefresh
+ % debugsub should be empty
+
+ $ hg qpop -qa
+ patch queue now empty
+ $ EXTRA='hg qnew -m3 3.diff' testrm2 qrefresh
+ adding a
+ % update substate when removing .hgsub w/clean updated subrepo
+ R .hgsub
+ % qrefresh
+ % debugsub should be empty
+
+ $ cd ..
+
+
+handle subrepos safely on qpush/qpop
+
+ $ mkrepo repo-2499-qpush
+ $ mksubrepo sub
+ adding a
+ $ hg -R sub ci -m0sub
+ $ echo sub = sub > .hgsub
+ $ hg add .hgsub
+ $ hg qnew -m0 0.diff
+ committing subrepository sub
+ $ hg debugsub
+ path sub
+ source sub
+ revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
+
+qpop
+ $ hg qpop
+ popping 0.diff
+ patch queue now empty
+ $ hg status -AS
+ $ hg debugsub
+
+qpush
+ $ hg qpush
+ applying 0.diff
+ now at: 0.diff
+ $ hg status -AS
+ C .hgsub
+ C .hgsubstate
+ C sub/a
+ $ hg debugsub
+ path sub
+ source sub
+ revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
+
+ $ cd ..
+
+
+handle subrepos safely on qrecord
+
+ $ mkrepo repo-2499-qrecord
+ $ testadd qrecord --config ui.interactive=1 -m0 0.diff <<EOF
+ > y
+ > y
+ > EOF
+ adding a
+ % abort when adding .hgsub w/dirty subrepo
+ A .hgsub
+ A sub/a
+ % qrecord --config ui.interactive=1 -m0 0.diff
+ diff --git a/.hgsub b/.hgsub
+ new file mode 100644
+ examine changes to '.hgsub'? [Ynsfdaq?]
+ abort: uncommitted changes in subrepository sub
+ [255]
+ % update substate when adding .hgsub w/clean updated subrepo
+ A .hgsub
+ % qrecord --config ui.interactive=1 -m0 0.diff
+ diff --git a/.hgsub b/.hgsub
+ new file mode 100644
+ examine changes to '.hgsub'? [Ynsfdaq?]
+ committing subrepository sub
+ path sub
+ source sub
+ revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
+
+ $ testmod qrecord --config ui.interactive=1 -m1 1.diff <<EOF
+ > y
+ > y
+ > EOF
+ adding a
+ % abort when modifying .hgsub w/dirty subrepo
+ M .hgsub
+ A sub2/a
+ % qrecord --config ui.interactive=1 -m1 1.diff
+ diff --git a/.hgsub b/.hgsub
+ 1 hunks, 1 lines changed
+ examine changes to '.hgsub'? [Ynsfdaq?]
+ @@ -1,1 +1,2 @@
+ sub = sub
+ +sub2 = sub2
+ record this change to '.hgsub'? [Ynsfdaq?]
+ abort: uncommitted changes in subrepository sub2
+ [255]
+ % update substate when modifying .hgsub w/clean updated subrepo
+ M .hgsub
+ % qrecord --config ui.interactive=1 -m1 1.diff
+ diff --git a/.hgsub b/.hgsub
+ 1 hunks, 1 lines changed
+ examine changes to '.hgsub'? [Ynsfdaq?]
+ @@ -1,1 +1,2 @@
+ sub = sub
+ +sub2 = sub2
+ record this change to '.hgsub'? [Ynsfdaq?]
+ committing subrepository sub2
+ path sub
+ source sub
+ revision b2fdb12cd82b021c3b7053d67802e77b6eeaee31
+ path sub2
+ source sub2
+ revision 1f94c7611cc6b74f5a17b16121a1170d44776845
+
+ $ hg qpop -qa
+ patch queue now empty
+ $ EXTRA= testrm1 qrecord --config ui.interactive=1 -m2 2.diff <<EOF
+ > y
+ > y
+ > EOF
+ adding a
+ % update substate when removing .hgsub w/dirty subrepo
+ M sub3/a
+ R .hgsub
+ % qrecord --config ui.interactive=1 -m2 2.diff
+ diff --git a/.hgsub b/.hgsub
+ deleted file mode 100644
+ examine changes to '.hgsub'? [Ynsfdaq?]
+ % debugsub should be empty
+
+ $ hg qpop -qa
+ patch queue now empty
+ $ EXTRA= testrm2 qrecord --config ui.interactive=1 -m3 3.diff <<EOF
+ > y
+ > y
+ > EOF
+ adding a
+ % update substate when removing .hgsub w/clean updated subrepo
+ R .hgsub
+ % qrecord --config ui.interactive=1 -m3 3.diff
+ diff --git a/.hgsub b/.hgsub
+ deleted file mode 100644
+ examine changes to '.hgsub'? [Ynsfdaq?]
+ % debugsub should be empty
+
+ $ cd ..
--- a/tests/test-mq.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-mq.t Wed Feb 16 14:13:22 2011 -0600
@@ -284,12 +284,12 @@
qpush with dump of tag cache
Dump the tag cache to ensure that it has exactly one head after qpush.
- $ rm -f .hg/tags.cache
+ $ rm -f .hg/cache/tags
$ hg tags > /dev/null
-.hg/tags.cache (pre qpush):
+.hg/cache/tags (pre qpush):
- $ cat .hg/tags.cache
+ $ cat .hg/cache/tags
1 [\da-f]{40} (re)
$ hg qpush
@@ -297,9 +297,9 @@
now at: test.patch
$ hg tags > /dev/null
-.hg/tags.cache (post qpush):
+.hg/cache/tags (post qpush):
- $ cat .hg/tags.cache
+ $ cat .hg/cache/tags
2 [\da-f]{40} (re)
$ checkundo qpush
--- a/tests/test-newbranch.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-newbranch.t Wed Feb 16 14:13:22 2011 -0600
@@ -1,4 +1,4 @@
- $ branchcache=.hg/branchheads.cache
+ $ branchcache=.hg/cache/branchheads
$ hg init t
$ cd t
@@ -208,12 +208,11 @@
$ hg branch
foo
$ hg commit -m'Merge ff into foo'
+ created new head
$ hg parents
- changeset: 6:917eb54e1b4b
+ changeset: 6:6af8030670c9
branch: foo
tag: tip
- parent: 4:98d14f698afe
- parent: 5:6683a60370cb
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: Merge ff into foo
--- a/tests/test-newcgi.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-newcgi.t Wed Feb 16 14:13:22 2011 -0600
@@ -49,36 +49,7 @@
$ chmod 755 hgwebdir.cgi
- $ DOCUMENT_ROOT="/var/www/hg"; export DOCUMENT_ROOT
- $ GATEWAY_INTERFACE="CGI/1.1"; export GATEWAY_INTERFACE
- $ HTTP_ACCEPT="text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"; export HTTP_ACCEPT
- $ HTTP_ACCEPT_CHARSET="ISO-8859-1,utf-8;q=0.7,*;q=0.7"; export HTTP_ACCEPT_CHARSET
- $ HTTP_ACCEPT_ENCODING="gzip,deflate"; export HTTP_ACCEPT_ENCODING
- $ HTTP_ACCEPT_LANGUAGE="en-us,en;q=0.5"; export HTTP_ACCEPT_LANGUAGE
- $ HTTP_CACHE_CONTROL="max-age=0"; export HTTP_CACHE_CONTROL
- $ HTTP_CONNECTION="keep-alive"; export HTTP_CONNECTION
- $ HTTP_HOST="hg.omnifarious.org"; export HTTP_HOST
- $ HTTP_KEEP_ALIVE="300"; export HTTP_KEEP_ALIVE
- $ HTTP_USER_AGENT="Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.0.4) Gecko/20060608 Ubuntu/dapper-security Firefox/1.5.0.4"; export HTTP_USER_AGENT
- $ PATH_INFO="/"; export PATH_INFO
- $ PATH_TRANSLATED="/var/www/hg/index.html"; export PATH_TRANSLATED
- $ QUERY_STRING=""; export QUERY_STRING
- $ REMOTE_ADDR="127.0.0.2"; export REMOTE_ADDR
- $ REMOTE_PORT="44703"; export REMOTE_PORT
- $ REQUEST_METHOD="GET"; export REQUEST_METHOD
- $ REQUEST_URI="/test/"; export REQUEST_URI
- $ SCRIPT_FILENAME="/home/hopper/hg_public/test.cgi"; export SCRIPT_FILENAME
- $ SCRIPT_NAME="/test"; export SCRIPT_NAME
- $ SCRIPT_URI="http://hg.omnifarious.org/test/"; export SCRIPT_URI
- $ SCRIPT_URL="/test/"; export SCRIPT_URL
- $ SERVER_ADDR="127.0.0.1"; export SERVER_ADDR
- $ SERVER_ADMIN="eric@localhost"; export SERVER_ADMIN
- $ SERVER_NAME="hg.omnifarious.org"; export SERVER_NAME
- $ SERVER_PORT="80"; export SERVER_PORT
- $ SERVER_PROTOCOL="HTTP/1.1"; export SERVER_PROTOCOL
- $ SERVER_SIGNATURE="<address>Apache/2.0.53 (Fedora) Server at hg.omnifarious.org Port 80</address>"; export SERVER_SIGNATURE
- $ SERVER_SOFTWARE="Apache/2.0.53 (Fedora)"; export SERVER_SOFTWARE
-
+ $ . "$TESTDIR/cgienv"
$ python hgweb.cgi > page1
$ python hgwebdir.cgi > page2
--- a/tests/test-newercgi.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-newercgi.t Wed Feb 16 14:13:22 2011 -0600
@@ -43,36 +43,7 @@
$ chmod 755 hgwebdir.cgi
- $ DOCUMENT_ROOT="/var/www/hg"; export DOCUMENT_ROOT
- $ GATEWAY_INTERFACE="CGI/1.1"; export GATEWAY_INTERFACE
- $ HTTP_ACCEPT="text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"; export HTTP_ACCEPT
- $ HTTP_ACCEPT_CHARSET="ISO-8859-1,utf-8;q=0.7,*;q=0.7"; export HTTP_ACCEPT_CHARSET
- $ HTTP_ACCEPT_ENCODING="gzip,deflate"; export HTTP_ACCEPT_ENCODING
- $ HTTP_ACCEPT_LANGUAGE="en-us,en;q=0.5"; export HTTP_ACCEPT_LANGUAGE
- $ HTTP_CACHE_CONTROL="max-age=0"; export HTTP_CACHE_CONTROL
- $ HTTP_CONNECTION="keep-alive"; export HTTP_CONNECTION
- $ HTTP_HOST="hg.omnifarious.org"; export HTTP_HOST
- $ HTTP_KEEP_ALIVE="300"; export HTTP_KEEP_ALIVE
- $ HTTP_USER_AGENT="Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.0.4) Gecko/20060608 Ubuntu/dapper-security Firefox/1.5.0.4"; export HTTP_USER_AGENT
- $ PATH_INFO="/"; export PATH_INFO
- $ PATH_TRANSLATED="/var/www/hg/index.html"; export PATH_TRANSLATED
- $ QUERY_STRING=""; export QUERY_STRING
- $ REMOTE_ADDR="127.0.0.2"; export REMOTE_ADDR
- $ REMOTE_PORT="44703"; export REMOTE_PORT
- $ REQUEST_METHOD="GET"; export REQUEST_METHOD
- $ REQUEST_URI="/test/"; export REQUEST_URI
- $ SCRIPT_FILENAME="/home/hopper/hg_public/test.cgi"; export SCRIPT_FILENAME
- $ SCRIPT_NAME="/test"; export SCRIPT_NAME
- $ SCRIPT_URI="http://hg.omnifarious.org/test/"; export SCRIPT_URI
- $ SCRIPT_URL="/test/"; export SCRIPT_URL
- $ SERVER_ADDR="127.0.0.1"; export SERVER_ADDR
- $ SERVER_ADMIN="eric@localhost"; export SERVER_ADMIN
- $ SERVER_NAME="hg.omnifarious.org"; export SERVER_NAME
- $ SERVER_PORT="80"; export SERVER_PORT
- $ SERVER_PROTOCOL="HTTP/1.1"; export SERVER_PROTOCOL
- $ SERVER_SIGNATURE="<address>Apache/2.0.53 (Fedora) Server at hg.omnifarious.org Port 80</address>"; export SERVER_SIGNATURE
- $ SERVER_SOFTWARE="Apache/2.0.53 (Fedora)"; export SERVER_SOFTWARE
-
+ $ . "$TESTDIR/cgienv"
$ python hgweb.cgi > page1
$ python hgwebdir.cgi > page2
@@ -81,7 +52,6 @@
$ REQUEST_URI="/test/test/"
$ SCRIPT_URI="http://hg.omnifarious.org/test/test/"
$ SCRIPT_URL="/test/test/"
-
$ python hgwebdir.cgi > page3
$ grep -i error page1 page2 page3
--- a/tests/test-no-symlinks Sat Feb 12 16:08:41 2011 +0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-#!/bin/sh
-
-"$TESTDIR/hghave" no-symlink || exit 80
-
-# The following script was used to create the bundle:
-#
-# hg init symlinks
-# cd symlinks
-# echo a > a
-# mkdir d
-# echo b > d/b
-# ln -s a a.lnk
-# ln -s d/b d/b.lnk
-# hg ci -Am t
-# hg bundle --base null ../test-no-symlinks.hg
-
-# Extract a symlink on a platform not supporting them
-echo % unbundle
-hg init t
-cd t
-hg pull -q "$TESTDIR/test-no-symlinks.hg"
-hg update
-
-cat a.lnk && echo
-cat d/b.lnk && echo
-
-# Copy a symlink and move another
-echo % move and copy
-hg copy a.lnk d/a2.lnk
-hg mv d/b.lnk b2.lnk
-hg ci -Am copy
-cat d/a2.lnk && echo
-cat b2.lnk && echo
-
-# Bundle and extract again
-echo % bundle
-hg bundle --base null ../symlinks.hg
-cd ..
-
-hg init t2
-cd t2
-hg pull ../symlinks.hg
-hg update
-
-cat a.lnk && echo
-cat d/a2.lnk && echo
-cat b2.lnk && echo
--- a/tests/test-no-symlinks.out Sat Feb 12 16:08:41 2011 +0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-% unbundle
-4 files updated, 0 files merged, 0 files removed, 0 files unresolved
-a
-d/b
-% move and copy
-a
-d/b
-% bundle
-2 changesets found
-pulling from ../symlinks.hg
-requesting all changes
-adding changesets
-adding manifests
-adding file changes
-added 2 changesets with 6 changes to 6 files
-(run 'hg update' to get a working copy)
-5 files updated, 0 files merged, 0 files removed, 0 files unresolved
-a
-a
-d/b
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-no-symlinks.t Wed Feb 16 14:13:22 2011 -0600
@@ -0,0 +1,59 @@
+ $ "$TESTDIR/hghave" no-symlink || exit 80
+
+# The following script was used to create the bundle:
+#
+# hg init symlinks
+# cd symlinks
+# echo a > a
+# mkdir d
+# echo b > d/b
+# ln -s a a.lnk
+# ln -s d/b d/b.lnk
+# hg ci -Am t
+# hg bundle --base null ../test-no-symlinks.hg
+
+Extract a symlink on a platform not supporting them
+
+ $ hg init t
+ $ cd t
+ $ hg pull -q "$TESTDIR/test-no-symlinks.hg"
+ $ hg update
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cat a.lnk && echo
+ a
+ $ cat d/b.lnk && echo
+ d/b
+
+Copy a symlink and move another
+
+ $ hg copy a.lnk d/a2.lnk
+ $ hg mv d/b.lnk b2.lnk
+ $ hg ci -Am copy
+ $ cat d/a2.lnk && echo
+ a
+ $ cat b2.lnk && echo
+ d/b
+
+Bundle and extract again
+
+ $ hg bundle --base null ../symlinks.hg
+ 2 changesets found
+ $ cd ..
+ $ hg init t2
+ $ cd t2
+ $ hg pull ../symlinks.hg
+ pulling from ../symlinks.hg
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 6 changes to 6 files
+ (run 'hg update' to get a working copy)
+ $ hg update
+ 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cat a.lnk && echo
+ a
+ $ cat d/a2.lnk && echo
+ a
+ $ cat b2.lnk && echo
+ d/b
--- a/tests/test-oldcgi.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-oldcgi.t Wed Feb 16 14:13:22 2011 -0600
@@ -59,36 +59,7 @@
$ chmod 755 hgwebdir.cgi
- $ DOCUMENT_ROOT="/var/www/hg"; export DOCUMENT_ROOT
- $ GATEWAY_INTERFACE="CGI/1.1"; export GATEWAY_INTERFACE
- $ HTTP_ACCEPT="text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"; export HTTP_ACCEPT
- $ HTTP_ACCEPT_CHARSET="ISO-8859-1,utf-8;q=0.7,*;q=0.7"; export HTTP_ACCEPT_CHARSET
- $ HTTP_ACCEPT_ENCODING="gzip,deflate"; export HTTP_ACCEPT_ENCODING
- $ HTTP_ACCEPT_LANGUAGE="en-us,en;q=0.5"; export HTTP_ACCEPT_LANGUAGE
- $ HTTP_CACHE_CONTROL="max-age=0"; export HTTP_CACHE_CONTROL
- $ HTTP_CONNECTION="keep-alive"; export HTTP_CONNECTION
- $ HTTP_HOST="hg.omnifarious.org"; export HTTP_HOST
- $ HTTP_KEEP_ALIVE="300"; export HTTP_KEEP_ALIVE
- $ HTTP_USER_AGENT="Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.0.4) Gecko/20060608 Ubuntu/dapper-security Firefox/1.5.0.4"; export HTTP_USER_AGENT
- $ PATH_INFO="/"; export PATH_INFO
- $ PATH_TRANSLATED="/var/www/hg/index.html"; export PATH_TRANSLATED
- $ QUERY_STRING=""; export QUERY_STRING
- $ REMOTE_ADDR="127.0.0.2"; export REMOTE_ADDR
- $ REMOTE_PORT="44703"; export REMOTE_PORT
- $ REQUEST_METHOD="GET"; export REQUEST_METHOD
- $ REQUEST_URI="/test/"; export REQUEST_URI
- $ SCRIPT_FILENAME="/home/hopper/hg_public/test.cgi"; export SCRIPT_FILENAME
- $ SCRIPT_NAME="/test"; export SCRIPT_NAME
- $ SCRIPT_URI="http://hg.omnifarious.org/test/"; export SCRIPT_URI
- $ SCRIPT_URL="/test/"; export SCRIPT_URL
- $ SERVER_ADDR="127.0.0.1"; export SERVER_ADDR
- $ SERVER_ADMIN="eric@localhost"; export SERVER_ADMIN
- $ SERVER_NAME="hg.omnifarious.org"; export SERVER_NAME
- $ SERVER_PORT="80"; export SERVER_PORT
- $ SERVER_PROTOCOL="HTTP/1.1"; export SERVER_PROTOCOL
- $ SERVER_SIGNATURE="<address>Apache/2.0.53 (Fedora) Server at hg.omnifarious.org Port 80</address>"; export SERVER_SIGNATURE
- $ SERVER_SOFTWARE="Apache/2.0.53 (Fedora)"; export SERVER_SOFTWARE
-
+ $ . "$TESTDIR/cgienv"
$ python hgweb.cgi > page1
$ python hgwebdir.cgi > page2
--- a/tests/test-parentrevspec.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-parentrevspec.t Wed Feb 16 14:13:22 2011 -0600
@@ -69,12 +69,12 @@
6^^^^^: 0
6^^^^^^: -1
6^1: 5
- 6^2: abort: unknown revision '6^2'!
+ 6^2: hg: parse error at 1: syntax error
6^^2: 4
6^1^2: 4
- 6^^3: abort: unknown revision '6^^3'!
+ 6^^3: hg: parse error at 1: syntax error
$ lookup "6~" "6~1" "6~2" "6~3" "6~4" "6~5" "6~42" "6~1^2" "6~1^2~2"
- 6~: abort: unknown revision '6~'!
+ 6~: hg: parse error at 1: syntax error
6~1: 5
6~2: 3
6~3: 2
@@ -102,4 +102,4 @@
$ hg tag -l -r 2 "foo^bar"
$ lookup "foo^bar" "foo^bar^"
foo^bar: 2
- foo^bar^: abort: unknown revision 'foo^bar^'!
+ foo^bar^: hg: parse error at 3: syntax error
--- a/tests/test-parseindex2.py Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-parseindex2.py Wed Feb 16 14:13:22 2011 -0600
@@ -21,7 +21,7 @@
index = []
nodemap = {nullid: nullrev}
n = off = 0
- # if we're not using lazymap, always read the whole index
+
l = len(data) - s
append = index.append
if inline:
@@ -50,7 +50,7 @@
# add the magic null revision at -1
index.append((0, 0, 0, -1, -1, -1, -1, nullid))
- return index, nodemap, cache
+ return index, cache
data_inlined = '\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00\x01\x8c' \
@@ -97,10 +97,10 @@
def runtest() :
py_res_1 = py_parseindex(data_inlined, True)
- c_res_1 = parsers.parse_index(data_inlined, True)
+ c_res_1 = parsers.parse_index2(data_inlined, True)
py_res_2 = py_parseindex(data_non_inlined, False)
- c_res_2 = parsers.parse_index(data_non_inlined, False)
+ c_res_2 = parsers.parse_index2(data_non_inlined, False)
if py_res_1 != c_res_1:
print "Parse index result (with inlined data) differs!"
--- a/tests/test-patchbomb.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-patchbomb.t Wed Feb 16 14:13:22 2011 -0600
@@ -145,6 +145,17 @@
+b
+.hg/last-email.txt
+
+ $ cat > editor << '__EOF__'
+ > #!/bin/sh
+ > echo "a precious introductory message" > "$1"
+ > __EOF__
+ $ chmod +x editor
+ $ HGEDITOR="'`pwd`'"/editor hg email -n -t foo -s test -r 0:tip > /dev/null
+ $ cat .hg/last-email.txt
+ a precious introductory message
+
$ hg email -m test.mbox -f quux -t foo -c bar -s test 0:tip \
> --config extensions.progress= --config progress.assume-tty=1 \
> --config progress.delay=0 --config progress.refresh=0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-pending.t Wed Feb 16 14:13:22 2011 -0600
@@ -0,0 +1,117 @@
+Verify that pending changesets are seen by pretxn* hooks but not by other
+processes that access the destination repo while the hooks are running.
+
+The hooks (python and external) both reject changesets after some think time,
+during which another process runs pull. Each hook creates a file ('notify') to
+indicate to the controlling process that it is running; the process removes the
+file to indicate the hook can terminate.
+
+init env vars
+
+ $ d=`pwd`
+ $ maxwait=20
+
+utility to run the test - start a push in the background and run pull
+
+ $ dotest() {
+ > rm -f notify
+ > printf 'push '; hg -R child-push tip --template '{node}\n'
+ > hg -R child-push -q push > push.out 2>&1 &
+ >
+ > # wait for hook to create the notify file
+ > i=$maxwait
+ > while [ ! -f notify -a $i != 0 ]; do
+ > sleep 1
+ > i=`expr $i - 1`
+ > done
+ >
+ > # run pull
+ > hg -R child-pull -q pull
+ > rc=$?
+ >
+ > # tell hook to finish; notify should exist.
+ > rm notify
+ > wait
+ >
+ > cat push.out
+ > printf 'pull '; hg -R child-pull tip --template '{node}\n'
+ > return $rc
+ > }
+
+python hook
+
+ $ cat <<EOF > reject.py
+ > import os, time
+ > from mercurial import ui, localrepo
+ > def rejecthook(ui, repo, hooktype, node, **opts):
+ > ui.write('hook %s\\n' % repo['tip'].hex())
+ > # create the notify file so caller knows we're running
+ > fpath = os.path.join('$d', 'notify')
+ > f = open(fpath, 'w')
+ > f.close()
+ > # wait for ack - caller should delete the notify file
+ > i = $maxwait
+ > while os.path.exists(fpath) and i > 0:
+ > time.sleep(1)
+ > i -= 1
+ > return True # reject the changesets
+ > EOF
+
+external hook
+
+ $ cat <<EOF > reject.sh
+ > #! /bin/sh
+ > printf 'hook '; hg tip --template '{node}\\n'
+ > # create the notify file so caller knows we're running
+ > fpath=$d/notify
+ > touch \$fpath
+ > # wait for ack - caller should delete the notify file
+ > i=$maxwait
+ > while [ -f \$fpath -a \$i != 0 ]; do
+ > sleep 1
+ > i=\`expr \$i - 1\`
+ > done
+ > exit 1 # reject the changesets
+ > EOF
+ $ chmod +x reject.sh
+
+create repos
+
+ $ hg init parent
+ $ hg clone -q parent child-push
+ $ hg clone -q parent child-pull
+ $ echo a > child-push/a
+ $ hg -R child-push add child-push/a
+ $ hg -R child-push commit -m a -d '1000000 0'
+
+test python hook
+
+ $ cat <<EOF > parent/.hg/hgrc
+ > [extensions]
+ > reject = $d/reject.py
+ > [hooks]
+ > pretxnchangegroup = python:reject.rejecthook
+ > EOF
+
+ $ dotest
+ push 29b62aeb769fdf78d8d9c5f28b017f76d7ef824b
+ hook 29b62aeb769fdf78d8d9c5f28b017f76d7ef824b
+ transaction abort!
+ rollback completed
+ abort: pretxnchangegroup hook failed
+ pull 0000000000000000000000000000000000000000
+
+test external hook
+
+ $ cat <<EOF > parent/.hg/hgrc
+ > [hooks]
+ > pretxnchangegroup = $d/reject.sh
+ > EOF
+
+ $ dotest
+ push 29b62aeb769fdf78d8d9c5f28b017f76d7ef824b
+ hook 29b62aeb769fdf78d8d9c5f28b017f76d7ef824b
+ transaction abort!
+ rollback completed
+ abort: pretxnchangegroup hook exited with status 1
+ pull 0000000000000000000000000000000000000000
--- a/tests/test-progress.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-progress.t Wed Feb 16 14:13:22 2011 -0600
@@ -23,78 +23,144 @@
> }
> EOF
- $ cat > filtercr.py <<EOF
- > import sys, re
- > for line in sys.stdin:
- > line = re.sub(r'\r+[^\n]', lambda m: '\n' + m.group()[-1:], line)
- > sys.stdout.write(line)
- > print
- > EOF
-
$ echo "[extensions]" >> $HGRCPATH
$ echo "progress=" >> $HGRCPATH
$ echo "loop=`pwd`/loop.py" >> $HGRCPATH
$ echo "[progress]" >> $HGRCPATH
+ $ echo "format = topic bar number" >> $HGRCPATH
$ echo "assume-tty=1" >> $HGRCPATH
+ $ echo "width=60" >> $HGRCPATH
test default params, display nothing because of delay
- $ hg -y loop 3 2>&1 | python filtercr.py
+ $ hg -y loop 3 2>&1 | $TESTDIR/filtercr.py
$ echo "delay=0" >> $HGRCPATH
$ echo "refresh=0" >> $HGRCPATH
test with delay=0, refresh=0
- $ hg -y loop 3 2>&1 | python filtercr.py
+ $ hg -y loop 3 2>&1 | $TESTDIR/filtercr.py
- loop [ ] 0/3
- loop [=====================> ] 1/3
- loop [============================================> ] 2/3
- \r (esc)
+ loop [ ] 0/3
+ loop [===============> ] 1/3
+ loop [===============================> ] 2/3
+ \r (esc)
test refresh is taken in account
- $ hg -y --config progress.refresh=100 loop 3 2>&1 | python filtercr.py
+ $ hg -y --config progress.refresh=100 loop 3 2>&1 | $TESTDIR/filtercr.py
test format options 1
- $ hg -y --config 'progress.format=number topic item+2' loop 2 2>&1 | python filtercr.py
+ $ hg -y --config 'progress.format=number topic item+2' loop 2 2>&1 \
+ > | $TESTDIR/filtercr.py
0/2 loop lo
1/2 loop lo
- \r (esc)
+ \r (esc)
test format options 2
- $ hg -y --config 'progress.format=number item-3 bar' loop 2 2>&1 | python filtercr.py
+ $ hg -y --config 'progress.format=number item-3 bar' loop 2 2>&1 \
+ > | $TESTDIR/filtercr.py
- 0/2 p.0 [ ]
- 1/2 p.1 [=================================> ]
- \r (esc)
+ 0/2 p.0 [ ]
+ 1/2 p.1 [=======================> ]
+ \r (esc)
test format options and indeterminate progress
- $ hg -y --config 'progress.format=number item bar' loop -- -2 2>&1 | python filtercr.py
+ $ hg -y --config 'progress.format=number item bar' loop -- -2 2>&1 \
+ > | $TESTDIR/filtercr.py
- 0 loop.0 [ <=> ]
- 1 loop.1 [ <=> ]
- \r (esc)
+ 0 loop.0 [ <=> ]
+ 1 loop.1 [ <=> ]
+ \r (esc)
make sure things don't fall over if count > total
- $ hg -y loop --total 4 6 2>&1 | python filtercr.py
+ $ hg -y loop --total 4 6 2>&1 | $TESTDIR/filtercr.py
- loop [ ] 0/4
- loop [================> ] 1/4
- loop [=================================> ] 2/4
- loop [==================================================> ] 3/4
- loop [===================================================================>] 4/4
- loop [ <=> ] 5/4
- \r (esc)
+ loop [ ] 0/4
+ loop [===========> ] 1/4
+ loop [=======================> ] 2/4
+ loop [===================================> ] 3/4
+ loop [===============================================>] 4/4
+ loop [ <=> ] 5/4
+ \r (esc)
test immediate progress completion
- $ hg -y loop 0 2>&1 | python filtercr.py
+ $ hg -y loop 0 2>&1 | $TESTDIR/filtercr.py
+
+
+test delay time estimates
+
+ $ cat > mocktime.py <<EOF
+ > import os
+ > import time
+ >
+ > class mocktime(object):
+ > def __init__(self, increment):
+ > self.time = 0
+ > self.increment = increment
+ > def __call__(self):
+ > self.time += self.increment
+ > return self.time
+ >
+ > def uisetup(ui):
+ > time.time = mocktime(int(os.environ.get('MOCKTIME', '11')))
+ > EOF
+
+ $ echo "[extensions]" > $HGRCPATH
+ $ echo "mocktime=`pwd`/mocktime.py" >> $HGRCPATH
+ $ echo "progress=" >> $HGRCPATH
+ $ echo "loop=`pwd`/loop.py" >> $HGRCPATH
+ $ echo "[progress]" >> $HGRCPATH
+ $ echo "assume-tty=1" >> $HGRCPATH
+ $ echo "delay=25" >> $HGRCPATH
+ $ echo "width=60" >> $HGRCPATH
+
+ $ hg -y loop 8 2>&1 | python $TESTDIR/filtercr.py
+ loop [=========> ] 2/8 1m07s
+ loop [===============> ] 3/8 56s
+ loop [=====================> ] 4/8 45s
+ loop [==========================> ] 5/8 34s
+ loop [================================> ] 6/8 23s
+ loop [=====================================> ] 7/8 12s
+ \r (esc)
+
+ $ MOCKTIME=10000 hg -y loop 4 2>&1 | python $TESTDIR/filtercr.py
+
+ loop [ ] 0/4
+ loop [=========> ] 1/4 8h21m
+ loop [====================> ] 2/4 5h34m
+ loop [==============================> ] 3/4 2h47m
+ \r (esc)
+
+ $ MOCKTIME=1000000 hg -y loop 4 2>&1 | python $TESTDIR/filtercr.py
+
+ loop [ ] 0/4
+ loop [=========> ] 1/4 5w00d
+ loop [====================> ] 2/4 3w03d
+ loop [=============================> ] 3/4 11d14h
+ \r (esc)
+
+
+ $ MOCKTIME=14000000 hg -y loop 4 2>&1 | python $TESTDIR/filtercr.py
+
+ loop [ ] 0/4
+ loop [=========> ] 1/4 1y18w
+ loop [===================> ] 2/4 46w03d
+ loop [=============================> ] 3/4 23w02d
+ \r (esc)
+
+Time estimates should not fail when there's no end point:
+ $ hg -y loop -- -4 2>&1 | python $TESTDIR/filtercr.py
+
+ loop [ <=> ] 2
+ loop [ <=> ] 3
+ \r (esc)
--- a/tests/test-pull-http.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-pull-http.t Wed Feb 16 14:13:22 2011 -0600
@@ -1,5 +1,4 @@
- $ cp "$TESTDIR"/printenv.py .
$ hg init test
$ cd test
$ echo a > a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-push-cgi.t Wed Feb 16 14:13:22 2011 -0600
@@ -0,0 +1,74 @@
+This is a test of the push wire protocol over CGI-based hgweb.
+
+initialize repository
+
+ $ hg init r
+ $ cd r
+ $ echo a > a
+ $ hg ci -A -m "0"
+ adding a
+ $ echo '[web]' > .hg/hgrc
+ $ echo 'allow_push = *' >> .hg/hgrc
+ $ echo 'push_ssl = false' >> .hg/hgrc
+
+create hgweb invocation script
+
+ $ cat >hgweb.cgi <<HGWEB
+ > import cgitb
+ > cgitb.enable()
+ > from mercurial import demandimport; demandimport.enable()
+ > from mercurial.hgweb import hgweb
+ > from mercurial.hgweb import wsgicgi
+ > application = hgweb('.', 'test repository')
+ > wsgicgi.launch(application)
+ > HGWEB
+ $ chmod 755 hgweb.cgi
+
+test preparation
+
+ $ . "$TESTDIR/cgienv"
+ $ REQUEST_METHOD="POST"; export REQUEST_METHOD
+ $ CONTENT_TYPE="application/octet-stream"; export CONTENT_TYPE
+ $ hg bundle --all bundle.hg
+ 1 changesets found
+ $ CONTENT_LENGTH=279; export CONTENT_LENGTH;
+
+expect unsynced changes
+
+ $ QUERY_STRING="cmd=unbundle&heads=0000000000000000000000000000000000000000"; export QUERY_STRING
+ $ python hgweb.cgi <bundle.hg >page1 2>&1
+ $ cat page1
+ Status: 200 Script output follows\r (esc)
+ Content-Type: application/mercurial-0.1\r (esc)
+ Content-Length: 19\r (esc)
+ \r (esc)
+ 0
+ unsynced changes
+
+successful force push
+
+ $ QUERY_STRING="cmd=unbundle&heads=666f726365"; export QUERY_STRING
+ $ python hgweb.cgi <bundle.hg >page2 2>&1
+ $ cat page2
+ Status: 200 Script output follows\r (esc)
+ Content-Type: application/mercurial-0.1\r (esc)
+ \r (esc)
+ 1
+ adding changesets
+ adding manifests
+ adding file changes
+ added 0 changesets with 0 changes to 1 files
+
+successful push
+
+ $ QUERY_STRING="cmd=unbundle&heads=f7b1eb17ad24730a1651fccd46c43826d1bbc2ac"; export QUERY_STRING
+ $ python hgweb.cgi <bundle.hg >page3 2>&1
+ $ cat page3
+ Status: 200 Script output follows\r (esc)
+ Content-Type: application/mercurial-0.1\r (esc)
+ \r (esc)
+ 1
+ adding changesets
+ adding manifests
+ adding file changes
+ added 0 changesets with 0 changes to 1 files
--- a/tests/test-push-http.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-push-http.t Wed Feb 16 14:13:22 2011 -0600
@@ -1,5 +1,4 @@
- $ cp "$TESTDIR"/printenv.py .
$ hg init test
$ cd test
$ echo a > a
@@ -53,7 +52,7 @@
$ echo 'allow_push = *' >> .hg/hgrc
$ echo '[hooks]' >> .hg/hgrc
- $ echo 'changegroup = python ../printenv.py changegroup 0' >> .hg/hgrc
+ $ echo 'changegroup = python "$TESTDIR"/printenv.py changegroup 0' >> .hg/hgrc
$ req
pushing to http://localhost:$HGPORT/
searching for changes
@@ -61,7 +60,7 @@
remote: adding manifests
remote: adding file changes
remote: added 1 changesets with 1 changes to 1 files
- remote: changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_URL=remote:http
+ remote: changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_URL=remote:http:*: (glob)
% serve errors
$ hg rollback
rolling back to revision 0 (undo serve)
--- a/tests/test-push-warn.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-push-warn.t Wed Feb 16 14:13:22 2011 -0600
@@ -30,6 +30,23 @@
(you should pull and merge or use push -f to force)
[255]
+ $ hg push --debug ../a
+ pushing to ../a
+ searching for changes
+ examining 1c9246a22a0a:d8d565842d04
+ found incomplete branch 1c9246a22a0a:d8d565842d04
+ searching: 1 queries
+ narrowing 1:1 d8d565842d04
+ found new branch changeset 1c9246a22a0a
+ found new changesets starting at 1c9246a22a0a
+ 1 total queries
+ common changesets up to d8d565842d04
+ new remote heads on branch 'default'
+ new remote head 1e108cc5548c
+ abort: push creates new remote heads on branch 'default'!
+ (you should pull and merge or use push -f to force)
+ [255]
+
$ hg pull ../a
pulling from ../a
searching for changes
@@ -396,6 +413,7 @@
(branch merge, don't forget to commit)
$ hg -R k ci -m merge
+ created new head
$ hg -R k push -r a j
pushing to j
--- a/tests/test-qrecord.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-qrecord.t Wed Feb 16 14:13:22 2011 -0600
@@ -158,13 +158,13 @@
-2
+2 2
3
- record change 1/6 to '1.txt'? [Ynsfdaq?]
+ record change 1/4 to '1.txt'? [Ynsfdaq?]
@@ -3,3 +3,3 @@
3
-4
+4 4
5
- record change 2/6 to '1.txt'? [Ynsfdaq?]
+ record change 2/4 to '1.txt'? [Ynsfdaq?]
diff --git a/2.txt b/2.txt
1 hunks, 1 lines changed
examine changes to '2.txt'? [Ynsfdaq?]
@@ -175,7 +175,7 @@
c
d
e
- record change 4/6 to '2.txt'? [Ynsfdaq?]
+ record change 3/4 to '2.txt'? [Ynsfdaq?]
diff --git a/dir/a.txt b/dir/a.txt
1 hunks, 1 lines changed
examine changes to 'dir/a.txt'? [Ynsfdaq?]
@@ -255,7 +255,7 @@
-4
+4 4
5
- record change 1/3 to '1.txt'? [Ynsfdaq?]
+ record change 1/2 to '1.txt'? [Ynsfdaq?]
diff --git a/dir/a.txt b/dir/a.txt
1 hunks, 1 lines changed
examine changes to 'dir/a.txt'? [Ynsfdaq?]
@@ -265,7 +265,7 @@
someone
up
- record change 3/3 to 'dir/a.txt'? [Ynsfdaq?]
+ record change 2/2 to 'dir/a.txt'? [Ynsfdaq?]
After qrecord b.patch 'tip'
--- a/tests/test-record.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-record.t Wed Feb 16 14:13:22 2011 -0600
@@ -285,7 +285,9 @@
Modify end of plain file, add EOL
$ echo >> plain
- $ hg record -d '10 0' -m eol plain <<EOF
+ $ echo 1 > plain2
+ $ hg add plain2
+ $ hg record -d '10 0' -m eol plain plain2 <<EOF
> y
> y
> y
@@ -300,16 +302,23 @@
-7264f99c5f5ff3261504828afa4fb4d406c3af54
\ No newline at end of file
+7264f99c5f5ff3261504828afa4fb4d406c3af54
- record this change to 'plain'? [Ynsfdaq?]
+ record change 1/2 to 'plain'? [Ynsfdaq?]
+ diff --git a/plain2 b/plain2
+ new file mode 100644
+ examine changes to 'plain2'? [Ynsfdaq?]
-Modify beginning, trim end, record both
+Modify beginning, trim end, record both, add another file to test
+changes numbering
$ rm plain
$ for i in 2 2 3 4 5 6 7 8 9 10; do
> echo $i >> plain
> done
+ $ echo 2 >> plain2
- $ hg record -d '10 0' -m begin-and-end plain <<EOF
+ $ hg record -d '10 0' -m begin-and-end plain plain2 <<EOF
+ > y
+ > y
> y
> y
> y
@@ -323,23 +332,30 @@
2
3
4
- record change 1/2 to 'plain'? [Ynsfdaq?]
+ record change 1/3 to 'plain'? [Ynsfdaq?]
@@ -8,5 +8,3 @@
8
9
10
-11
-7264f99c5f5ff3261504828afa4fb4d406c3af54
- record change 2/2 to 'plain'? [Ynsfdaq?]
+ record change 2/3 to 'plain'? [Ynsfdaq?]
+ diff --git a/plain2 b/plain2
+ 1 hunks, 1 lines changed
+ examine changes to 'plain2'? [Ynsfdaq?]
+ @@ -1,1 +1,2 @@
+ 1
+ +2
+ record change 3/3 to 'plain2'? [Ynsfdaq?]
$ hg tip -p
- changeset: 11:efca65c9b09e
+ changeset: 11:21df83db12b8
tag: tip
user: test
date: Thu Jan 01 00:00:10 1970 +0000
summary: begin-and-end
- diff -r cd07d48e8cbe -r efca65c9b09e plain
+ diff -r ddb8b281c3ff -r 21df83db12b8 plain
--- a/plain Thu Jan 01 00:00:10 1970 +0000
+++ b/plain Thu Jan 01 00:00:10 1970 +0000
@@ -1,4 +1,4 @@
@@ -354,6 +370,12 @@
10
-11
-7264f99c5f5ff3261504828afa4fb4d406c3af54
+ diff -r ddb8b281c3ff -r 21df83db12b8 plain2
+ --- a/plain2 Thu Jan 01 00:00:10 1970 +0000
+ +++ b/plain2 Thu Jan 01 00:00:10 1970 +0000
+ @@ -1,1 +1,2 @@
+ 1
+ +2
Trim beginning, modify end
@@ -396,13 +418,13 @@
record change 2/2 to 'plain'? [Ynsfdaq?]
$ hg tip -p
- changeset: 12:7d1e66983c15
+ changeset: 12:99337501826f
tag: tip
user: test
date: Thu Jan 01 00:00:11 1970 +0000
summary: end-only
- diff -r efca65c9b09e -r 7d1e66983c15 plain
+ diff -r 21df83db12b8 -r 99337501826f plain
--- a/plain Thu Jan 01 00:00:10 1970 +0000
+++ b/plain Thu Jan 01 00:00:11 1970 +0000
@@ -7,4 +7,4 @@
@@ -432,13 +454,13 @@
record this change to 'plain'? [Ynsfdaq?]
$ hg tip -p
- changeset: 13:a09fc62a0e61
+ changeset: 13:bbd45465d540
tag: tip
user: test
date: Thu Jan 01 00:00:12 1970 +0000
summary: begin-only
- diff -r 7d1e66983c15 -r a09fc62a0e61 plain
+ diff -r 99337501826f -r bbd45465d540 plain
--- a/plain Thu Jan 01 00:00:11 1970 +0000
+++ b/plain Thu Jan 01 00:00:12 1970 +0000
@@ -1,6 +1,3 @@
@@ -533,13 +555,13 @@
record change 3/3 to 'plain'? [Ynsfdaq?]
$ hg tip -p
- changeset: 15:7d137997f3a6
+ changeset: 15:f34a7937ec33
tag: tip
user: test
date: Thu Jan 01 00:00:14 1970 +0000
summary: middle-only
- diff -r c0b8e5fb0be6 -r 7d137997f3a6 plain
+ diff -r 82c065d0b850 -r f34a7937ec33 plain
--- a/plain Thu Jan 01 00:00:13 1970 +0000
+++ b/plain Thu Jan 01 00:00:14 1970 +0000
@@ -1,5 +1,10 @@
@@ -573,13 +595,13 @@
record this change to 'plain'? [Ynsfdaq?]
$ hg tip -p
- changeset: 16:4959e3ff13eb
+ changeset: 16:f9900b71a04c
tag: tip
user: test
date: Thu Jan 01 00:00:15 1970 +0000
summary: end-only
- diff -r 7d137997f3a6 -r 4959e3ff13eb plain
+ diff -r f34a7937ec33 -r f9900b71a04c plain
--- a/plain Thu Jan 01 00:00:14 1970 +0000
+++ b/plain Thu Jan 01 00:00:15 1970 +0000
@@ -9,3 +9,5 @@
@@ -610,13 +632,13 @@
record this change to 'subdir/a'? [Ynsfdaq?]
$ hg tip -p
- changeset: 18:40698cd490b2
+ changeset: 18:61be427a9deb
tag: tip
user: test
date: Thu Jan 01 00:00:16 1970 +0000
summary: subdir-change
- diff -r 661eacdc08b9 -r 40698cd490b2 subdir/a
+ diff -r a7ffae4d61cb -r 61be427a9deb subdir/a
--- a/subdir/a Thu Jan 01 00:00:16 1970 +0000
+++ b/subdir/a Thu Jan 01 00:00:16 1970 +0000
@@ -1,1 +1,2 @@
@@ -709,13 +731,13 @@
examine changes to 'subdir/f2'? [Ynsfdaq?]
$ hg tip -p
- changeset: 20:d2d8c25276a8
+ changeset: 20:b3df3dda369a
tag: tip
user: test
date: Thu Jan 01 00:00:18 1970 +0000
summary: x
- diff -r 25eb2a7694fb -r d2d8c25276a8 subdir/f2
+ diff -r 6e02d6c9906d -r b3df3dda369a subdir/f2
--- a/subdir/f2 Thu Jan 01 00:00:17 1970 +0000
+++ b/subdir/f2 Thu Jan 01 00:00:18 1970 +0000
@@ -1,1 +1,2 @@
@@ -733,13 +755,13 @@
examine changes to 'subdir/f1'? [Ynsfdaq?]
$ hg tip -p
- changeset: 21:1013f51ce32f
+ changeset: 21:38ec577f126b
tag: tip
user: test
date: Thu Jan 01 00:00:19 1970 +0000
summary: y
- diff -r d2d8c25276a8 -r 1013f51ce32f subdir/f1
+ diff -r b3df3dda369a -r 38ec577f126b subdir/f1
--- a/subdir/f1 Thu Jan 01 00:00:18 1970 +0000
+++ b/subdir/f1 Thu Jan 01 00:00:19 1970 +0000
@@ -1,1 +1,2 @@
@@ -768,7 +790,7 @@
record this change to 'subdir/f1'? [Ynsfdaq?]
$ hg tip --config diff.git=True -p
- changeset: 22:5df857735621
+ changeset: 22:3261adceb075
tag: tip
user: test
date: Thu Jan 01 00:00:20 1970 +0000
@@ -804,7 +826,7 @@
record this change to 'subdir/f1'? [Ynsfdaq?]
$ hg tip --config diff.git=True -p
- changeset: 23:a4ae36a78715
+ changeset: 23:b429867550db
tag: tip
user: test
date: Thu Jan 01 00:00:21 1970 +0000
@@ -842,7 +864,7 @@
record this change to 'subdir/f1'? [Ynsfdaq?]
$ hg tip --config diff.git=True -p
- changeset: 24:1460f6e47966
+ changeset: 24:0b082130c20a
tag: tip
user: test
date: Thu Jan 01 00:00:22 1970 +0000
@@ -865,7 +887,7 @@
Abort early when a merge is in progress
$ hg up 4
- 1 files updated, 0 files merged, 5 files removed, 0 files unresolved
+ 1 files updated, 0 files merged, 6 files removed, 0 files unresolved
$ touch iwillmergethat
$ hg add iwillmergethat
@@ -876,14 +898,14 @@
$ hg ci -m'new head'
$ hg up default
- 5 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ 6 files updated, 0 files merged, 2 files removed, 0 files unresolved
$ hg merge thatbranch
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg record -m'will abort'
- abort: cannot partially commit a merge (use hg commit instead)
+ abort: cannot partially commit a merge (use "hg commit" instead)
[255]
$ hg up -C
@@ -921,14 +943,14 @@
record this change to 'subdir/f1'? [Ynsfdaq?]
$ hg tip -p
- changeset: 26:5bacc1f6e9cf
+ changeset: 26:b8306e70edc4
tag: tip
- parent: 24:1460f6e47966
+ parent: 24:0b082130c20a
user: test
date: Thu Jan 01 00:00:23 1970 +0000
summary: w1
- diff -r 1460f6e47966 -r 5bacc1f6e9cf subdir/f1
+ diff -r 0b082130c20a -r b8306e70edc4 subdir/f1
--- a/subdir/f1 Thu Jan 01 00:00:22 1970 +0000
+++ b/subdir/f1 Thu Jan 01 00:00:23 1970 +0000
@@ -3,3 +3,4 @@
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-revset-dirstate-parents.t Wed Feb 16 14:13:22 2011 -0600
@@ -0,0 +1,52 @@
+ $ HGENCODING=utf-8
+ $ export HGENCODING
+
+ $ try() {
+ > hg debugrevspec --debug $@
+ > }
+
+ $ log() {
+ > hg log --template '{rev}\n' -r "$1"
+ > }
+
+ $ hg init repo
+ $ cd repo
+
+ $ try 'p1()'
+ ('func', ('symbol', 'p1'), None)
+ $ try 'p2()'
+ ('func', ('symbol', 'p2'), None)
+ $ try 'parents()'
+ ('func', ('symbol', 'parents'), None)
+
+null revision
+ $ log 'p1()'
+ $ log 'p2()'
+ $ log 'parents()'
+
+working dir with a single parent
+ $ echo a > a
+ $ hg ci -Aqm0
+ $ log 'p1()'
+ 0
+ $ log 'tag() and p1()'
+ $ log 'p2()'
+ $ log 'parents()'
+ 0
+ $ log 'tag() and parents()'
+
+merge in progress
+ $ echo b > b
+ $ hg ci -Aqm1
+ $ hg up -q 0
+ $ echo c > c
+ $ hg ci -Aqm2
+ $ hg merge -q
+ $ log 'p1()'
+ 2
+ $ log 'p2()'
+ 1
+ $ log 'tag() and p2()'
+ $ log 'parents()'
+ 1
+ 2
--- a/tests/test-rollback.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-rollback.t Wed Feb 16 14:13:22 2011 -0600
@@ -72,8 +72,9 @@
$ cat .hg/last-message.txt ; echo
precious commit message
- $ echo '% same thing, but run $EDITOR'
- % same thing, but run $EDITOR
+
+same thing, but run $EDITOR
+
$ cat > editor << '__EOF__'
> #!/bin/sh
> echo "another precious commit message" > "$1"
@@ -88,5 +89,3 @@
$ cat .hg/last-message.txt
another precious commit message
-.hg/last-message.txt:
-
--- a/tests/test-ssh.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-ssh.t Wed Feb 16 14:13:22 2011 -0600
@@ -1,5 +1,4 @@
- $ cp "$TESTDIR"/printenv.py .
This test tries to exercise the ssh functionality with a dummy script
@@ -45,7 +44,7 @@
> bookmarks =
>
> [hooks]
- > changegroup = python ../printenv.py changegroup-in-remote 0 ../dummylog
+ > changegroup = python "$TESTDIR"/printenv.py changegroup-in-remote 0 ../dummylog
> EOF
$ cd ..
@@ -101,7 +100,7 @@
checking files
2 files, 1 changesets, 2 total revisions
$ echo '[hooks]' >> .hg/hgrc
- $ echo 'changegroup = python ../printenv.py changegroup-in-local 0 ../dummylog' >> .hg/hgrc
+ $ echo 'changegroup = python "$TESTDIR"/printenv.py changegroup-in-local 0 ../dummylog' >> .hg/hgrc
empty default pull
@@ -214,7 +213,7 @@
$ hg debugpushkey --config ui.ssh="python ../dummyssh" ssh://user@dummy/remote bookmarks
foo 1160648e36cec0054048a7edc4110c6f84fde594
$ hg book -f foo
- $ hg push
+ $ hg push --traceback
pushing to ssh://user@dummy/remote
searching for changes
no changes found
@@ -233,6 +232,9 @@
importing bookmark foo
$ hg book -d foo
$ hg push -B foo
+ pushing to ssh://user@dummy/remote
+ searching for changes
+ no changes found
deleting remote bookmark foo
a bad, evil hook that prints to stdout
@@ -287,5 +289,3 @@
Got arguments 1:user@dummy 2:hg -R remote serve --stdio
Got arguments 1:user@dummy 2:hg -R remote serve --stdio
Got arguments 1:user@dummy 2:hg -R remote serve --stdio
- Got arguments 1:user@dummy 2:hg -R remote serve --stdio
- Got arguments 1:user@dummy 2:hg -R remote serve --stdio
--- a/tests/test-static-http.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-static-http.t Wed Feb 16 14:13:22 2011 -0600
@@ -1,5 +1,4 @@
- $ cp "$TESTDIR"/printenv.py .
$ hg clone http://localhost:$HGPORT/ copy
abort: error: Connection refused
[255]
@@ -10,7 +9,7 @@
one pull
$ cat > dumb.py <<EOF
- > import BaseHTTPServer, SimpleHTTPServer, os, signal
+ > import BaseHTTPServer, SimpleHTTPServer, os, signal, sys
>
> def run(server_class=BaseHTTPServer.HTTPServer,
> handler_class=SimpleHTTPServer.SimpleHTTPRequestHandler):
@@ -18,7 +17,7 @@
> httpd = server_class(server_address, handler_class)
> httpd.serve_forever()
>
- > signal.signal(signal.SIGTERM, lambda x: sys.exit(0))
+ > signal.signal(signal.SIGTERM, lambda x, y: sys.exit(0))
> run()
> EOF
$ python dumb.py 2>/dev/null &
@@ -27,10 +26,13 @@
$ cd remote
$ hg init
$ echo foo > bar
- $ hg add bar
+ $ echo c2 > '.dotfile with spaces'
+ $ hg add
+ adding .dotfile with spaces
+ adding bar
$ hg commit -m"test"
$ hg tip
- changeset: 0:61c9426e69fe
+ changeset: 0:02770d679fb8
tag: tip
user: test
date: Thu Jan 01 00:00:00 1970 +0000
@@ -42,16 +44,16 @@
adding changesets
adding manifests
adding file changes
- added 1 changesets with 1 changes to 1 files
+ added 1 changesets with 2 changes to 2 files
updating to branch default
- 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ cd local
$ hg verify
checking changesets
checking manifests
crosschecking files in changesets and manifests
checking files
- 1 files, 1 changesets, 1 total revisions
+ 2 files, 1 changesets, 2 total revisions
$ cat bar
foo
$ cd ../remote
@@ -61,12 +63,12 @@
check for HTTP opener failures when cachefile does not exist
- $ rm .hg/*.cache
+ $ rm .hg/cache/*
$ cd ../local
$ echo '[hooks]' >> .hg/hgrc
- $ echo 'changegroup = python ../printenv.py changegroup' >> .hg/hgrc
+ $ echo 'changegroup = python "$TESTDIR"/printenv.py changegroup' >> .hg/hgrc
$ hg pull
- changegroup hook: HG_NODE=822d6e31f08b9d6e3b898ce5e52efc0a4bf4905a HG_SOURCE=pull HG_URL=http://localhost:$HGPORT/remote
+ changegroup hook: HG_NODE=4ac2e3648604439c580c69b09ec9d93a88d93432 HG_SOURCE=pull HG_URL=http://localhost:$HGPORT/remote
pulling from static-http://localhost:$HGPORT/remote
searching for changes
adding changesets
@@ -96,9 +98,9 @@
adding changesets
adding manifests
adding file changes
- added 1 changesets with 1 changes to 1 files
+ added 1 changesets with 2 changes to 2 files
updating to branch default
- 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
test with "/" URI (issue 747)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-subrepo-git.t Wed Feb 16 14:13:22 2011 -0600
@@ -0,0 +1,445 @@
+ $ "$TESTDIR/hghave" git || exit 80
+
+make git commits repeatable
+
+ $ GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME
+ $ GIT_AUTHOR_EMAIL='test@example.org'; export GIT_AUTHOR_EMAIL
+ $ GIT_AUTHOR_DATE='1234567891 +0000'; export GIT_AUTHOR_DATE
+ $ GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; export GIT_COMMITTER_NAME
+ $ GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"; export GIT_COMMITTER_EMAIL
+ $ GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"; export GIT_COMMITTER_DATE
+
+root hg repo
+
+ $ hg init t
+ $ cd t
+ $ echo a > a
+ $ hg add a
+ $ hg commit -m a
+ $ cd ..
+
+new external git repo
+
+ $ mkdir gitroot
+ $ cd gitroot
+ $ git init -q
+ $ echo g > g
+ $ git add g
+ $ git commit -q -m g
+
+add subrepo clone
+
+ $ cd ../t
+ $ echo 's = [git]../gitroot' > .hgsub
+ $ git clone -q ../gitroot s
+ $ hg add .hgsub
+ $ hg commit -m 'new git subrepo'
+ committing subrepository s
+ $ hg debugsub
+ path s
+ source ../gitroot
+ revision da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
+
+record a new commit from upstream from a different branch
+
+ $ cd ../gitroot
+ $ git checkout -q -b testing
+ $ echo gg >> g
+ $ git commit -q -a -m gg
+
+ $ cd ../t/s
+ $ git pull -q >/dev/null 2>/dev/null
+ $ git checkout -q -b testing origin/testing >/dev/null
+
+ $ cd ..
+ $ hg status --subrepos
+ M s/g
+ $ hg commit -m 'update git subrepo'
+ committing subrepository s
+ $ hg debugsub
+ path s
+ source ../gitroot
+ revision 126f2a14290cd5ce061fdedc430170e8d39e1c5a
+
+make $GITROOT pushable, by replacing it with a clone with nothing checked out
+
+ $ cd ..
+ $ git clone gitroot gitrootbare --bare -q
+ $ rm -rf gitroot
+ $ mv gitrootbare gitroot
+
+clone root
+
+ $ cd t
+ $ hg clone . ../tc
+ updating to branch default
+ cloning subrepo s
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ../tc
+ $ hg debugsub
+ path s
+ source ../gitroot
+ revision 126f2a14290cd5ce061fdedc430170e8d39e1c5a
+
+update to previous substate
+
+ $ hg update 1 -q
+ $ cat s/g
+ g
+ $ hg debugsub
+ path s
+ source ../gitroot
+ revision da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
+
+clone root, make local change
+
+ $ cd ../t
+ $ hg clone . ../ta
+ updating to branch default
+ cloning subrepo s
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ cd ../ta
+ $ echo ggg >> s/g
+ $ hg status --subrepos
+ M s/g
+ $ hg commit -m ggg
+ committing subrepository s
+ $ hg debugsub
+ path s
+ source ../gitroot
+ revision 79695940086840c99328513acbe35f90fcd55e57
+
+clone root separately, make different local change
+
+ $ cd ../t
+ $ hg clone . ../tb
+ updating to branch default
+ cloning subrepo s
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ cd ../tb/s
+ $ echo f > f
+ $ git add f
+ $ cd ..
+
+ $ hg status --subrepos
+ A s/f
+ $ hg commit -m f
+ committing subrepository s
+ $ hg debugsub
+ path s
+ source ../gitroot
+ revision aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
+
+user b push changes
+
+ $ hg push 2>/dev/null
+ pushing to $TESTTMP/t
+ pushing branch testing of subrepo s
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+
+user a pulls, merges, commits
+
+ $ cd ../ta
+ $ hg pull
+ pulling from $TESTTMP/t
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files (+1 heads)
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+ $ hg merge 2>/dev/null
+ pulling subrepo s
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ cat s/f
+ f
+ $ cat s/g
+ g
+ gg
+ ggg
+ $ hg commit -m 'merge'
+ committing subrepository s
+ $ hg status --subrepos --rev 1:5
+ M .hgsubstate
+ M s/g
+ A s/f
+ $ hg debugsub
+ path s
+ source ../gitroot
+ revision f47b465e1bce645dbf37232a00574aa1546ca8d3
+ $ hg push 2>/dev/null
+ pushing to $TESTTMP/t
+ pushing branch testing of subrepo s
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 2 changes to 1 files
+
+make upstream git changes
+
+ $ cd ..
+ $ git clone -q gitroot gitclone
+ $ cd gitclone
+ $ echo ff >> f
+ $ git commit -q -a -m ff
+ $ echo fff >> f
+ $ git commit -q -a -m fff
+ $ git push origin testing 2>/dev/null
+
+make and push changes to hg without updating the subrepo
+
+ $ cd ../t
+ $ hg clone . ../td
+ updating to branch default
+ cloning subrepo s
+ checking out detached HEAD in subrepo s
+ check out a git branch if you intend to make changes
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ../td
+ $ echo aa >> a
+ $ hg commit -m aa
+ $ hg push
+ pushing to $TESTTMP/t
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+
+sync to upstream git, distribute changes
+
+ $ cd ../ta
+ $ hg pull -u -q
+ $ cd s
+ $ git pull -q >/dev/null 2>/dev/null
+ $ cd ..
+ $ hg commit -m 'git upstream sync'
+ committing subrepository s
+ $ hg debugsub
+ path s
+ source ../gitroot
+ revision 32a343883b74769118bb1d3b4b1fbf9156f4dddc
+ $ hg push -q
+
+ $ cd ../tb
+ $ hg pull -q
+ $ hg update 2>/dev/null
+ pulling subrepo s
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg debugsub
+ path s
+ source ../gitroot
+ revision 32a343883b74769118bb1d3b4b1fbf9156f4dddc
+
+update to a revision without the subrepo, keeping the local git repository
+
+ $ cd ../t
+ $ hg up 0
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ ls -a s
+ .
+ ..
+ .git
+
+ $ hg up 2
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ ls -a s
+ .
+ ..
+ .git
+ g
+
+archive subrepos
+
+ $ cd ../tc
+ $ hg pull -q
+ $ hg archive --subrepos -r 5 ../archive 2>/dev/null
+ pulling subrepo s
+ $ cd ../archive
+ $ cat s/f
+ f
+ $ cat s/g
+ g
+ gg
+ ggg
+
+create nested repo
+
+ $ cd ..
+ $ hg init outer
+ $ cd outer
+ $ echo b>b
+ $ hg add b
+ $ hg commit -m b
+
+ $ hg clone ../t inner
+ updating to branch default
+ cloning subrepo s
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo inner = inner > .hgsub
+ $ hg add .hgsub
+ $ hg commit -m 'nested sub'
+ committing subrepository inner
+
+nested commit
+
+ $ echo ffff >> inner/s/f
+ $ hg status --subrepos
+ M inner/s/f
+ $ hg commit -m nested
+ committing subrepository inner
+ committing subrepository inner/s
+
+nested archive
+
+ $ hg archive --subrepos ../narchive
+ $ ls ../narchive/inner/s | grep -v pax_global_header
+ f
+ g
+
+Check hg update --clean
+ $ cd $TESTTMP/ta
+ $ echo > s/g
+ $ cd s
+ $ echo c1 > f1
+ $ echo c1 > f2
+ $ git add f1
+ $ cd ..
+ $ hg status -S
+ M s/g
+ A s/f1
+ $ ls s
+ f
+ f1
+ f2
+ g
+ $ hg update --clean
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg status -S
+ $ ls s
+ f
+ f1
+ f2
+ g
+
+Sticky subrepositories, no changes
+ $ cd $TESTTMP/ta
+ $ hg id -n
+ 7
+ $ cd s
+ $ git rev-parse HEAD
+ 32a343883b74769118bb1d3b4b1fbf9156f4dddc
+ $ cd ..
+ $ hg update 1 > /dev/null 2>&1
+ $ hg id -n
+ 1
+ $ cd s
+ $ git rev-parse HEAD
+ da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
+ $ cd ..
+
+Sticky subrepositorys, file changes
+ $ touch s/f1
+ $ cd s
+ $ git add f1
+ $ cd ..
+ $ hg id -n
+ 1
+ $ cd s
+ $ git rev-parse HEAD
+ da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
+ $ cd ..
+ $ hg update 4
+ subrepository sources for s differ
+ use (l)ocal source (da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7) or (r)emote source (aa84837ccfbdfedcdcdeeedc309d73e6eb069edc)?
+ l
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 4+
+ $ cd s
+ $ git rev-parse HEAD
+ da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
+ $ cd ..
+ $ hg update --clean tip > /dev/null 2>&1
+
+Sticky subrepository, revision updates
+ $ hg id -n
+ 7
+ $ cd s
+ $ git rev-parse HEAD
+ 32a343883b74769118bb1d3b4b1fbf9156f4dddc
+ $ cd ..
+ $ cd s
+ $ git checkout aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
+ Previous HEAD position was 32a3438... fff
+ HEAD is now at aa84837... f
+ $ cd ..
+ $ hg update 1
+ subrepository sources for s differ (in checked out version)
+ use (l)ocal source (32a343883b74769118bb1d3b4b1fbf9156f4dddc) or (r)emote source (da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7)?
+ l
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 1+
+ $ cd s
+ $ git rev-parse HEAD
+ aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
+ $ cd ..
+
+Sticky subrepository, file changes and revision updates
+ $ touch s/f1
+ $ cd s
+ $ git add f1
+ $ git rev-parse HEAD
+ aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
+ $ cd ..
+ $ hg id -n
+ 1+
+ $ hg update 7
+ subrepository sources for s differ
+ use (l)ocal source (32a343883b74769118bb1d3b4b1fbf9156f4dddc) or (r)emote source (32a343883b74769118bb1d3b4b1fbf9156f4dddc)?
+ l
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 7
+ $ cd s
+ $ git rev-parse HEAD
+ aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
+ $ cd ..
+
+Sticky repository, update --clean
+ $ hg update --clean tip
+ Previous HEAD position was aa84837... f
+ HEAD is now at 32a3438... fff
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 7
+ $ cd s
+ $ git rev-parse HEAD
+ 32a343883b74769118bb1d3b4b1fbf9156f4dddc
+ $ cd ..
+
+Test subrepo already at intended revision:
+ $ cd s
+ $ git checkout 32a343883b74769118bb1d3b4b1fbf9156f4dddc
+ HEAD is now at 32a3438... fff
+ $ cd ..
+ $ hg update 1
+ Previous HEAD position was 32a3438... fff
+ HEAD is now at da5f5b1... g
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 1
+ $ cd s
+ $ git rev-parse HEAD
+ da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
+ $ cd ..
+
--- a/tests/test-subrepo-recursion.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-subrepo-recursion.t Wed Feb 16 14:13:22 2011 -0600
@@ -221,9 +221,48 @@
z1
+z2
-Test archiving to a directory tree:
+Enable progress extension for archive tests:
+
+ $ cp $HGRCPATH $HGRCPATH.no-progress
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > progress =
+ > [progress]
+ > assume-tty = 1
+ > delay = 0
+ > format = topic bar number
+ > refresh = 0
+ > width = 60
+ > EOF
+
+Test archiving to a directory tree (the doubled lines in the output
+only show up in the test output, not in real usage):
- $ hg archive --subrepos ../archive
+ $ hg archive --subrepos ../archive 2>&1 | $TESTDIR/filtercr.py
+
+ archiving [ ] 0/3
+ archiving [ ] 0/3
+ archiving [=============> ] 1/3
+ archiving [=============> ] 1/3
+ archiving [===========================> ] 2/3
+ archiving [===========================> ] 2/3
+ archiving [==========================================>] 3/3
+ archiving [==========================================>] 3/3
+
+ archiving (foo) [ ] 0/3
+ archiving (foo) [ ] 0/3
+ archiving (foo) [===========> ] 1/3
+ archiving (foo) [===========> ] 1/3
+ archiving (foo) [=======================> ] 2/3
+ archiving (foo) [=======================> ] 2/3
+ archiving (foo) [====================================>] 3/3
+ archiving (foo) [====================================>] 3/3
+
+ archiving (foo/bar) [ ] 0/1
+ archiving (foo/bar) [ ] 0/1
+ archiving (foo/bar) [================================>] 1/1
+ archiving (foo/bar) [================================>] 1/1
+ \r (esc)
$ find ../archive | sort
../archive
../archive/.hg_archival.txt
@@ -239,7 +278,35 @@
Test archiving to zip file (unzip output is unstable):
- $ hg archive --subrepos ../archive.zip
+ $ hg archive --subrepos ../archive.zip 2>&1 | $TESTDIR/filtercr.py
+
+ archiving [ ] 0/3
+ archiving [ ] 0/3
+ archiving [=============> ] 1/3
+ archiving [=============> ] 1/3
+ archiving [===========================> ] 2/3
+ archiving [===========================> ] 2/3
+ archiving [==========================================>] 3/3
+ archiving [==========================================>] 3/3
+
+ archiving (foo) [ ] 0/3
+ archiving (foo) [ ] 0/3
+ archiving (foo) [===========> ] 1/3
+ archiving (foo) [===========> ] 1/3
+ archiving (foo) [=======================> ] 2/3
+ archiving (foo) [=======================> ] 2/3
+ archiving (foo) [====================================>] 3/3
+ archiving (foo) [====================================>] 3/3
+
+ archiving (foo/bar) [ ] 0/1
+ archiving (foo/bar) [ ] 0/1
+ archiving (foo/bar) [================================>] 1/1
+ archiving (foo/bar) [================================>] 1/1
+ \r (esc)
+
+Disable progress extension and cleanup:
+
+ $ mv $HGRCPATH.no-progress $HGRCPATH
Clone and test outgoing:
--- a/tests/test-subrepo-svn.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-subrepo-svn.t Wed Feb 16 14:13:22 2011 -0600
@@ -126,7 +126,7 @@
add an unrelated revision in svn and update the subrepo to without
bringing any changes.
- $ svn mkdir --parents "$SVNREPO/unrelated" -m 'create unrelated'
+ $ svn mkdir "$SVNREPO/unrelated" -m 'create unrelated'
Committed revision 4.
$ svn up s
@@ -273,11 +273,11 @@
$ echo c1 > f2
$ svn add f1 -q
$ svn status
- ? a
- X externals
- ? f2
- M alpha
- A f1
+ ? * a (glob)
+ X * externals (glob)
+ ? * f2 (glob)
+ M * alpha (glob)
+ A * f1 (glob)
Performing status on external item at 'externals'
$ cd ../..
@@ -290,9 +290,151 @@
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ cd t/s
$ svn status
- ? a
- X externals
- ? f1
- ? f2
+ ? * a (glob)
+ X * externals (glob)
+ ? * f1 (glob)
+ ? * f2 (glob)
Performing status on external item at 'externals'
+
+Sticky subrepositories, no changes
+ $ cd $TESTTMP/sub/t
+ $ hg id -n
+ 2
+ $ cd s
+ $ svnversion
+ 3
+ $ cd ..
+ $ hg update 1
+ U $TESTTMP/sub/t/s/alpha
+
+ Fetching external item into '$TESTTMP/sub/t/s/externals'
+ Checked out external at revision 1.
+
+ Checked out revision 2.
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 1
+ $ cd s
+ $ svnversion
+ 2
+ $ cd ..
+
+Sticky subrepositorys, file changes
+ $ touch s/f1
+ $ cd s
+ $ svn add f1
+ A f1
+ $ cd ..
+ $ hg id -n
+ 1
+ $ cd s
+ $ svnversion
+ 2M
+ $ cd ..
+ $ hg update tip
+ subrepository sources for s differ
+ use (l)ocal source (2) or (r)emote source (3)?
+ l
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 2+
+ $ cd s
+ $ svnversion
+ 2M
+ $ cd ..
+ $ hg update --clean tip
+ U $TESTTMP/sub/t/s/alpha
+
+ Fetching external item into '$TESTTMP/sub/t/s/externals'
+ Checked out external at revision 1.
+
+ Checked out revision 3.
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Sticky subrepository, revision updates
+ $ hg id -n
+ 2
+ $ cd s
+ $ svnversion
+ 3
+ $ cd ..
+ $ cd s
+ $ svn update -r 1
+ U alpha
+ U .
+
+ Fetching external item into 'externals'
+ Updated external to revision 1.
+
+ Updated to revision 1.
+ $ cd ..
+ $ hg update 1
+ subrepository sources for s differ (in checked out version)
+ use (l)ocal source (1) or (r)emote source (2)?
+ l
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 1+
+ $ cd s
+ $ svnversion
+ 1
+ $ cd ..
+
+Sticky subrepository, file changes and revision updates
+ $ touch s/f1
+ $ cd s
+ $ svn add f1
+ A f1
+ $ svnversion
+ 1M
+ $ cd ..
+ $ hg id -n
+ 1+
+ $ hg update tip
+ subrepository sources for s differ
+ use (l)ocal source (1) or (r)emote source (3)?
+ l
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 2
+ $ cd s
+ $ svnversion
+ 1M
+ $ cd ..
+
+Sticky repository, update --clean
+ $ hg update --clean tip
+ U $TESTTMP/sub/t/s/alpha
+ U $TESTTMP/sub/t/s
+
+ Fetching external item into '$TESTTMP/sub/t/s/externals'
+ Checked out external at revision 1.
+
+ Checked out revision 3.
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 2
+ $ cd s
+ $ svnversion
+ 3
+ $ cd ..
+
+Test subrepo already at intended revision:
+ $ cd s
+ $ svn update -r 2
+ U alpha
+
+ Fetching external item into 'externals'
+ Updated external to revision 1.
+
+ Updated to revision 2.
+ $ cd ..
+ $ hg update 1
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 1+
+ $ cd s
+ $ svnversion
+ 2
+ $ cd ..
--- a/tests/test-subrepo.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-subrepo.t Wed Feb 16 14:13:22 2011 -0600
@@ -75,16 +75,19 @@
commit: (clean)
update: (current)
-bump sub rev
+bump sub rev (and check it is ignored by ui.commitsubrepos)
$ echo b > s/a
$ hg -R s ci -ms1
- $ hg ci -m3
+ $ hg --config ui.commitsubrepos=no ci -m3
committing subrepository s
-leave sub dirty
+leave sub dirty (and check ui.commitsubrepos=no aborts the commit)
$ echo c > s/a
+ $ hg --config ui.commitsubrepos=no ci -m4
+ abort: uncommitted changes in subrepo s
+ [255]
$ hg ci -m4
committing subrepository s
$ hg tip -R s
@@ -703,3 +706,125 @@
$ hg status -S
? s/b
? s/c
+
+Sticky subrepositories, no changes
+ $ cd $TESTTMP/sub/t
+ $ hg id
+ 925c17564ef8 tip
+ $ hg -R s id
+ 12a213df6fa9 tip
+ $ hg -R t id
+ 52c0adc0515a tip
+ $ hg update 11
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id
+ 365661e5936a
+ $ hg -R s id
+ fc627a69481f
+ $ hg -R t id
+ e95bcfa18a35
+
+Sticky subrepositorys, file changes
+ $ touch s/f1
+ $ touch t/f1
+ $ hg add -S s/f1
+ $ hg add -S t/f1
+ $ hg id
+ 365661e5936a
+ $ hg -R s id
+ fc627a69481f+
+ $ hg -R t id
+ e95bcfa18a35+
+ $ hg update tip
+ subrepository sources for s differ
+ use (l)ocal source (fc627a69481f) or (r)emote source (12a213df6fa9)?
+ l
+ subrepository sources for t differ
+ use (l)ocal source (e95bcfa18a35) or (r)emote source (52c0adc0515a)?
+ l
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id
+ 925c17564ef8+ tip
+ $ hg -R s id
+ fc627a69481f+
+ $ hg -R t id
+ e95bcfa18a35+
+ $ hg update --clean tip
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Sticky subrepository, revision updates
+ $ hg id
+ 925c17564ef8 tip
+ $ hg -R s id
+ 12a213df6fa9 tip
+ $ hg -R t id
+ 52c0adc0515a tip
+ $ cd s
+ $ hg update -r -2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ../t
+ $ hg update -r 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ..
+ $ hg update 10
+ subrepository sources for t differ (in checked out version)
+ use (l)ocal source (7af322bc1198) or (r)emote source (20a0db6fbf6c)?
+ l
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id
+ e45c8b14af55+
+ $ hg -R s id
+ 1c833a7a9e3a
+ $ hg -R t id
+ 7af322bc1198
+
+Sticky subrepository, file changes and revision updates
+ $ touch s/f1
+ $ touch t/f1
+ $ hg add -S s/f1
+ $ hg add -S t/f1
+ $ hg id
+ e45c8b14af55+
+ $ hg -R s id
+ 1c833a7a9e3a+
+ $ hg -R t id
+ 7af322bc1198+
+ $ hg update tip
+ subrepository sources for s differ
+ use (l)ocal source (1c833a7a9e3a) or (r)emote source (12a213df6fa9)?
+ l
+ subrepository sources for t differ
+ use (l)ocal source (7af322bc1198) or (r)emote source (52c0adc0515a)?
+ l
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id
+ 925c17564ef8 tip
+ $ hg -R s id
+ 1c833a7a9e3a+
+ $ hg -R t id
+ 7af322bc1198+
+
+Sticky repository, update --clean
+ $ hg update --clean tip
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id
+ 925c17564ef8 tip
+ $ hg -R s id
+ 12a213df6fa9 tip
+ $ hg -R t id
+ 52c0adc0515a tip
+
+Test subrepo already at intended revision:
+ $ cd s
+ $ hg update fc627a69481f
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd ..
+ $ hg update 11
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg id -n
+ 11+
+ $ hg -R s id
+ fc627a69481f
+ $ hg -R t id
+ e95bcfa18a35
--- a/tests/test-tag.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-tag.t Wed Feb 16 14:13:22 2011 -0600
@@ -63,6 +63,18 @@
$ hg tag -f gack
$ hg tag --remove gack gorp
+ $ hg tag "bleah "
+ abort: tag 'bleah' already exists (use -f to force)
+ [255]
+ $ hg tag " bleah"
+ abort: tag 'bleah' already exists (use -f to force)
+ [255]
+ $ hg tag " bleah"
+ abort: tag 'bleah' already exists (use -f to force)
+ [255]
+ $ hg tag -r 0 " bleahbleah "
+ $ hg tag -r 0 " bleah bleah "
+
$ cat .hgtags
acb14030fe0a21b60322c440ad2d20cf7685a376 bleah
acb14030fe0a21b60322c440ad2d20cf7685a376 bleah0
@@ -75,6 +87,9 @@
0000000000000000000000000000000000000000 gack
336fccc858a4eb69609a291105009e484a6b6b8d gorp
0000000000000000000000000000000000000000 gorp
+ acb14030fe0a21b60322c440ad2d20cf7685a376 bleahbleah
+ acb14030fe0a21b60322c440ad2d20cf7685a376 bleah bleah
+
$ cat .hg/localtags
d4f0d2909abc9290e2773c08837d70c1794e3f5a bleah1
@@ -107,7 +122,9 @@
$ hg -R test log -r0:5
changeset: 0:acb14030fe0a
tag: bleah
+ tag: bleah bleah
tag: bleah0
+ tag: bleahbleah
tag: foobar
tag: localblah
user: test
@@ -210,7 +227,7 @@
$ hg tag hgtags-modified
$ hg rollback
- rolling back to revision 11 (undo commit)
+ rolling back to revision 13 (undo commit)
$ hg st
M .hgtags
? .hgtags.orig
@@ -227,7 +244,7 @@
0 files updated, 1 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg ci -m 'merge named branch'
- $ hg up 11
+ $ hg up 13
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg tag new-topo-head
@@ -252,27 +269,29 @@
$ echo c1 > f1
$ hg ci -Am0
adding f1
+ $ echo c2 > f2
+ $ hg ci -Am1
+ adding f2
+ $ hg co -q 0
$ hg branch b1
marked working directory as branch b1
- $ echo c2 >> f1
- $ hg ci -m1
+ $ hg ci -m2
$ hg up default
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg merge b1
- 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg tag t1
abort: uncommitted merge
[255]
$ hg status
- M f1
$ hg tag --rev 1 t2
abort: uncommitted merge
[255]
$ hg tag --rev 1 --local t3
$ hg tags -v
- tip 1:9466ada9ee90
- t3 1:9466ada9ee90 local
+ tip 2:8a8f787d0d5c
+ t3 1:c3adabd1a5f4 local
$ cd ..
--- a/tests/test-tags.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-tags.t Wed Feb 16 14:13:22 2011 -0600
@@ -1,7 +1,7 @@
Helper functions:
$ cacheexists() {
- > [ -f .hg/tags.cache ] && echo "tag cache exists" || echo "no tag cache"
+ > [ -f .hg/cache/tags ] && echo "tag cache exists" || echo "no tag cache"
> }
$ dumptags() {
@@ -36,9 +36,9 @@
Try corrupting the cache
- $ printf 'a b' > .hg/tags.cache
+ $ printf 'a b' > .hg/cache/tags
$ hg identify
- .hg/tags.cache is corrupt, rebuilding it
+ .hg/cache/tags is corrupt, rebuilding it
acb14030fe0a tip
$ cacheexists
tag cache exists
@@ -69,13 +69,13 @@
Repeat with cold tag cache:
- $ rm -f .hg/tags.cache
+ $ rm -f .hg/cache/tags
$ hg identify
b9154636be93 tip
And again, but now unable to write tag cache:
- $ rm -f .hg/tags.cache
+ $ rm -f .hg/cache/tags
$ chmod 555 .hg
$ hg identify
b9154636be93 tip
@@ -216,7 +216,7 @@
Dump cache:
- $ cat .hg/tags.cache
+ $ cat .hg/cache/tags
4 0c192d7d5e6b78a714de54a2e9627952a877e25a 0c04f2a8af31de17fab7422878ee5a2dadbc943d
3 6fa450212aeb2a21ed616a54aea39a4a27894cd7 7d3b718c964ef37b89e550ebdafd5789e76ce1b0
2 7a94127795a33c10a370c93f731fd9fea0b79af6 0c04f2a8af31de17fab7422878ee5a2dadbc943d
@@ -325,7 +325,7 @@
$ hg tags # partly stale
tip 4:735c3ca72986
bar 0:bbd179dfa0a7
- $ rm -f .hg/tags.cache
+ $ rm -f .hg/cache/tags
$ hg tags # cold cache
tip 4:735c3ca72986
bar 0:bbd179dfa0a7
--- a/tests/test-win32text.t Sat Feb 12 16:08:41 2011 +0800
+++ b/tests/test-win32text.t Wed Feb 16 14:13:22 2011 -0600
@@ -9,10 +9,6 @@
> data = data.replace('\n', '\r\n')
> file(path, 'wb').write(data)
> EOF
- $ cat > print.py <<EOF
- > import sys
- > print(sys.stdin.read().replace('\n', '<LF>').replace('\r', '<CR>').replace('\0', '<NUL>'))
- > EOF
$ echo '[hooks]' >> .hg/hgrc
$ echo 'pretxncommit.crlf = python:hgext.win32text.forbidcrlf' >> .hg/hgrc
$ echo 'pretxnchangegroup.crlf = python:hgext.win32text.forbidcrlf' >> .hg/hgrc
@@ -369,12 +365,13 @@
$ python -c 'file("f4.bat", "wb").write("rem empty\x0D\x0A")'
$ hg add f3 f4.bat
$ hg ci -m 6
- $ python print.py < bin
- hello<NUL><CR><LF>
- $ python print.py < f3
- some<LF>text<LF>
- $ python print.py < f4.bat
- rem empty<CR><LF>
+ $ cat bin
+ hello\x00\r (esc)
+ $ cat f3
+ some
+ text
+ $ cat f4.bat
+ rem empty\r (esc)
$ echo
$ echo '[extensions]' >> .hg/hgrc
@@ -405,38 +402,39 @@
tip
$ rm f3 f4.bat bin
- $ hg co -C 2>&1 | python -c 'import sys, os; sys.stdout.write(sys.stdin.read().replace(os.getcwd(), "...."))'
+ $ hg co -C
WARNING: f4.bat already has CRLF line endings
and does not need EOL conversion by the win32text plugin.
Before your next commit, please reconsider your encode/decode settings in
- Mercurial.ini or ..../.hg/hgrc.
+ Mercurial.ini or $TESTTMP/t/.hg/hgrc.
3 files updated, 0 files merged, 0 files removed, 0 files unresolved
- $ python print.py < bin
- hello<NUL><CR><LF>
- $ python print.py < f3
- some<CR><LF>text<CR><LF>
- $ python print.py < f4.bat
- rem empty<CR><LF>
+ $ cat bin
+ hello\x00\r (esc)
+ $ cat f3
+ some\r (esc)
+ text\r (esc)
+ $ cat f4.bat
+ rem empty\r (esc)
$ echo
$ python -c 'file("f5.sh", "wb").write("# empty\x0D\x0A")'
$ hg add f5.sh
$ hg ci -m 7
- $ python print.py < f5.sh
- # empty<CR><LF>
- $ hg cat f5.sh | python print.py
- # empty<LF>
+ $ cat f5.sh
+ # empty\r (esc)
+ $ hg cat f5.sh
+ # empty
$ echo '% just linefeed' > linefeed
$ hg ci -qAm 8 linefeed
- $ python print.py < linefeed
- % just linefeed<LF>
- $ hg cat linefeed | python print.py
- % just linefeed<LF>
+ $ cat linefeed
+ % just linefeed
+ $ hg cat linefeed
+ % just linefeed
$ hg st -q
$ hg revert -a linefeed
no changes needed to linefeed
- $ python print.py < linefeed
- % just linefeed<LF>
+ $ cat linefeed
+ % just linefeed
$ hg st -q
$ echo modified >> linefeed
$ hg st -q
@@ -444,5 +442,5 @@
$ hg revert -a
reverting linefeed
$ hg st -q
- $ python print.py < linefeed
- % just linefeed<CR><LF>
+ $ cat linefeed
+ % just linefeed\r (esc)