merge with crew.
--- a/contrib/darcs2hg.py
+++ b/contrib/darcs2hg.py
@@ -4,12 +4,11 @@
# -----------------------------------------------------------------------------
# Project : Basic Darcs to Mercurial conversion script
# -----------------------------------------------------------------------------
-# Author : Sebastien Pierre <sebastien@xprima.com>
+# Authors : Sebastien Pierre <sebastien@xprima.com>
+# TK Soh <teekaysoh@gmail.com>
+# -----------------------------------------------------------------------------
# Creation : 24-May-2006
-# Last mod : 26-May-2006
-# History :
-# 26-May-2006 - Updated
-# 24-May-2006 - First implementation
+# Last mod : 05-Jun-2006
# -----------------------------------------------------------------------------
import os, sys
@@ -21,12 +20,14 @@ DARCS_REPO = None
HG_REPO = None
USAGE = """\
-%s DARCSREPO HGREPO
+%s DARCSREPO HGREPO [SKIP]
Converts the given Darcs repository to a new Mercurial repository. The given
HGREPO must not exist, as it will be created and filled up (this will avoid
overwriting valuable data.
+ In case an error occurs within the process, you can resume the process by
+ giving the last successfuly applied change number.
""" % (os.path.basename(sys.argv[0]))
# ------------------------------------------------------------------------------
@@ -35,7 +36,7 @@ USAGE = """\
#
# ------------------------------------------------------------------------------
-def cmd(text, path=None):
+def cmd(text, path=None, silent=False):
"""Executes a command, in the given directory (if any), and returns the
command result as a string."""
cwd = None
@@ -43,7 +44,7 @@ def cmd(text, path=None):
path = os.path.abspath(path)
cwd = os.getcwd()
os.chdir(path)
- print text
+ if not silent: print "> ", text
res = os.popen(text).read()
if path:
os.chdir(cwd)
@@ -53,6 +54,14 @@ def writefile(path, data):
"""Writes the given data into the given file."""
f = file(path, "w") ; f.write(data) ; f.close()
+def error( *args ):
+ sys.stderr.write("ERROR: ")
+ for a in args: sys.stderr.write(str(a))
+ sys.stderr.write("\n")
+ sys.stderr.write("You can make manual fixes if necessary and then resume by"
+ " giving the last changeset number")
+ sys.exit(-1)
+
# ------------------------------------------------------------------------------
#
# Darcs interface
@@ -64,7 +73,6 @@ def darcs_changes(darcsRepo):
chronological list of changes as (change name, change summary)."""
changes = cmd("darcs changes --reverse --xml-output", darcsRepo)
doc = xml_dom.parseString(changes)
- res = []
for patch_node in doc.childNodes[0].childNodes:
name = filter(lambda n:n.nodeName == "name", patch_node.childNodes)
comm = filter(lambda n:n.nodeName == "comment", patch_node.childNodes)
@@ -73,11 +81,22 @@ def darcs_changes(darcsRepo):
if not comm: comm = ""
else: comm = comm[0].childNodes[0].data
author = patch_node.getAttribute("author")
- date = patch_node.getAttribute("date")
- yield author, date, name, comm
+ date = patch_node.getAttribute("date")
+ chash = os.path.splitext(patch_node.getAttribute("hash"))[0]
+ yield author, date, name, chash, comm
-def darcs_pull(hg_repo, darcs_repo, change):
- cmd("darcs pull '%s' --all --patches='%s'" % (darcs_repo, change), hg_repo)
+def darcs_tip(darcs_repo):
+ changes = cmd("darcs changes",darcs_repo,silent=True)
+ changes = filter(lambda l:l.strip().startswith("* "), changes.split("\n"))
+ return len(changes)
+
+def darcs_pull(hg_repo, darcs_repo, chash):
+ old_tip = darcs_tip(darcs_repo)
+ res = cmd("darcs pull '%s' --all --match='hash %s'" % (darcs_repo, chash), hg_repo)
+ print res
+ new_tip = darcs_tip(darcs_repo)
+ if not new_tip != old_tip + 1:
+ error("Darcs pull did not work as expected: " + res)
# ------------------------------------------------------------------------------
#
@@ -88,10 +107,24 @@ def darcs_pull(hg_repo, darcs_repo, chan
def hg_commit( hg_repo, text, author, date ):
fd, tmpfile = tempfile.mkstemp(prefix="darcs2hg_")
writefile(tmpfile, text)
+ old_tip = hg_tip(hg_repo)
cmd("hg add -X _darcs", hg_repo)
cmd("hg remove -X _darcs --after", hg_repo)
- cmd("hg commit -l %s -u '%s' -d '%s 0'" % (tmpfile, author, date), hg_repo)
+ res = cmd("hg commit -l %s -u '%s' -d '%s 0'" % (tmpfile, author, date), hg_repo)
os.unlink(tmpfile)
+ new_tip = hg_tip(hg_repo)
+ if not new_tip == old_tip + 1:
+ # Sometimes we may have empty commits, we simply skip them
+ if res.strip().lower().find("nothing changed") != -1:
+ pass
+ else:
+ error("Mercurial commit did not work as expected: " + res)
+
+def hg_tip( hg_repo ):
+ """Returns the latest local revision number in the given repository."""
+ tip = cmd("hg tip", hg_repo, silent=True)
+ tip = tip.split("\n")[0].split(":")[1].strip()
+ return int(tip)
# ------------------------------------------------------------------------------
#
@@ -105,26 +138,41 @@ if __name__ == "__main__":
if len(args) == 2:
darcs_repo = os.path.abspath(args[0])
hg_repo = os.path.abspath(args[1])
+ skip = None
+ elif len(args) == 3:
+ darcs_repo = os.path.abspath(args[0])
+ hg_repo = os.path.abspath(args[1])
+ skip = int(args[2])
else:
print USAGE
sys.exit(-1)
# Initializes the target repo
if not os.path.isdir(darcs_repo + "/_darcs"):
- print "No darcs directory found at: " + darc_repo
+ print "No darcs directory found at: " + darcs_repo
sys.exit(-1)
if not os.path.isdir(hg_repo):
os.mkdir(hg_repo)
- else:
- print "Given HG repository must not exist. It will be created"
+ elif skip == None:
+ print "Given HG repository must not exist when no SKIP is specified."
sys.exit(-1)
- cmd("hg init '%s'" % (hg_repo))
- cmd("darcs initialize", hg_repo)
+ if skip == None:
+ cmd("hg init '%s'" % (hg_repo))
+ cmd("darcs initialize", hg_repo)
# Get the changes from the Darcs repository
- for author, date, summary, description in darcs_changes(darcs_repo):
- text = summary + "\n" + description
- darcs_pull(hg_repo, darcs_repo, summary)
- epoch = int(mktime(strptime(date, '%Y%m%d%H%M%S')))
- hg_commit(hg_repo, text, author, epoch)
+ change_number = 0
+ for author, date, summary, chash, description in darcs_changes(darcs_repo):
+ print "== changeset", change_number,
+ if skip != None and change_number <= skip:
+ print "(skipping)"
+ else:
+ text = summary + "\n" + description
+ darcs_pull(hg_repo, darcs_repo, chash)
+ # The commit hash has a date like 20021020201112
+ # --------------------------------YYYYMMDDHHMMSS
+ date = chash.split("-")[0]
+ epoch = int(mktime(strptime(date, '%Y%m%d%H%M%S')))
+ hg_commit(hg_repo, text, author, epoch)
+ change_number += 1
+ print "Darcs repository (_darcs) was not deleted. You can keep or remove it."
# EOF
-
--- a/doc/hgrc.5.txt
+++ b/doc/hgrc.5.txt
@@ -309,6 +309,9 @@ smtp::
Optional. Password to authenticate to SMTP server with.
If username is specified, password must also be specified.
Default: none.
+ local_hostname;;
+ Optional. It's the hostname that the sender can use to identify itself
+ to the MTA.
paths::
Assigns symbolic names to repositories. The left side is the
--- a/mercurial/bdiff.c
+++ b/mercurial/bdiff.c
@@ -65,7 +65,7 @@ static inline uint32_t rol32(uint32_t wo
int splitlines(const char *a, int len, struct line **lr)
{
- int h, i;
+ int g, h, i;
const char *p, *b = a;
struct line *l;
@@ -82,7 +82,16 @@ int splitlines(const char *a, int len, s
/* build the line array and calculate hashes */
h = 0;
for (p = a; p < a + len; p++) {
- h = *p + rol32(h, 7); /* a simple hash from GNU diff */
+ /*
+ * a simple hash from GNU diff, with better collision
+ * resistance from hashpjw. this slows down common
+ * case by 10%, but speeds up worst case by 100x.
+ */
+ h = *p + rol32(h, 7);
+ if ((g = h & 0xf0000000)) {
+ h ^= g >> 24;
+ h ^= g;
+ }
if (*p == '\n' || p == a + len - 1) {
l->len = p - b + 1;
l->h = h * l->len;
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -231,7 +231,7 @@ def revrange(ui, repo, revs):
"""Yield revision as strings from a list of revision specifications."""
seen = {}
for spec in revs:
- if spec.find(revrangesep) >= 0:
+ if revrangesep in spec:
start, end = spec.split(revrangesep, 1)
start = revfix(repo, start, 0)
end = revfix(repo, end, repo.changelog.count() - 1)
@@ -405,23 +405,33 @@ def dodiff(fp, ui, repo, node1, node2, f
diffopts = ui.diffopts()
showfunc = opts.get('show_function') or diffopts['showfunc']
ignorews = opts.get('ignore_all_space') or diffopts['ignorews']
+ ignorewsamount = opts.get('ignore_space_change') or \
+ diffopts['ignorewsamount']
+ ignoreblanklines = opts.get('ignore_blank_lines') or \
+ diffopts['ignoreblanklines']
for f in modified:
to = None
if f in mmap:
to = repo.file(f).read(mmap[f])
tn = read(f)
fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, text=text,
- showfunc=showfunc, ignorews=ignorews))
+ showfunc=showfunc, ignorews=ignorews,
+ ignorewsamount=ignorewsamount,
+ ignoreblanklines=ignoreblanklines))
for f in added:
to = None
tn = read(f)
fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, text=text,
- showfunc=showfunc, ignorews=ignorews))
+ showfunc=showfunc, ignorews=ignorews,
+ ignorewsamount=ignorewsamount,
+ ignoreblanklines=ignoreblanklines))
for f in removed:
to = repo.file(f).read(mmap[f])
tn = None
fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, text=text,
- showfunc=showfunc, ignorews=ignorews))
+ showfunc=showfunc, ignorews=ignorews,
+ ignorewsamount=ignorewsamount,
+ ignoreblanklines=ignoreblanklines))
def trimuser(ui, name, rev, revcache):
"""trim the name of the user who committed a change"""
@@ -941,6 +951,10 @@ def clone(ui, source, dest=None, **opts)
hardlinking.
See pull for valid source format details.
+
+ It is possible to specify an ssh:// URL as the destination, but no
+ .hg/hgrc will be created on the remote side. Look at the help text
+ for the pull command for important details about ssh:// URLs.
"""
if dest is None:
dest = os.path.basename(os.path.normpath(source))
@@ -1950,6 +1964,10 @@ def init(ui, dest="."):
directory does not exist, it is created.
If no directory is given, the current directory is used.
+
+ It is possible to specify an ssh:// URL as the destination.
+ Look at the help text for the pull command for important details
+ about ssh:// URLs.
"""
hg.repository(ui, dest, create=1)
@@ -2218,15 +2236,16 @@ def pull(ui, repo, source="default", **o
Valid URLs are of the form:
local/filesystem/path
- http://[user@]host[:port][/path]
- https://[user@]host[:port][/path]
- ssh://[user@]host[:port][/path]
+ http://[user@]host[:port]/[path]
+ https://[user@]host[:port]/[path]
+ ssh://[user@]host[:port]/[path]
Some notes about using SSH with Mercurial:
- SSH requires an accessible shell account on the destination machine
and a copy of hg in the remote path or specified with as remotecmd.
- - /path is relative to the remote user's home directory by default.
- Use two slashes at the start of a path to specify an absolute path.
+ - path is relative to the remote user's home directory by default.
+ Use an extra slash at the start of a path to specify an absolute path:
+ ssh://example.com//tmp/repository
- Mercurial doesn't use its own compression via SSH; the right thing
to do is to configure it in your ~/.ssh/ssh_config, e.g.:
Host *.mylocalnetwork.example.com
@@ -2270,10 +2289,13 @@ def push(ui, repo, dest=None, **opts):
Valid URLs are of the form:
local/filesystem/path
- ssh://[user@]host[:port][/path]
+ ssh://[user@]host[:port]/[path]
Look at the help text for the pull command for important details
about ssh:// URLs.
+
+ Pushing to http:// and https:// URLs is possible, too, if this
+ feature is enabled on the remote Mercurial server.
"""
dest = ui.expandpath(dest or 'default-push', dest or 'default')
@@ -2742,7 +2764,7 @@ def tag(ui, repo, name, rev_=None, **opt
disallowed = (revrangesep, '\r', '\n')
for c in disallowed:
- if name.find(c) >= 0:
+ if c in name:
raise util.Abort(_("%s cannot be used in a tag name") % repr(c))
repo.hook('pretag', throw=True, node=r, tag=name,
@@ -3018,6 +3040,10 @@ table = {
_('show which function each change is in')),
('w', 'ignore-all-space', None,
_('ignore white space when comparing lines')),
+ ('b', 'ignore-space-change', None,
+ _('ignore changes in the amount of white space')),
+ ('B', 'ignore-blank-lines', None,
+ _('ignore changes whose lines are all blank')),
('I', 'include', [], _('include names matching the given patterns')),
('X', 'exclude', [], _('exclude names matching the given patterns'))],
_('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
--- a/mercurial/filelog.py
+++ b/mercurial/filelog.py
@@ -34,14 +34,14 @@ class filelog(revlog):
t = self.revision(node)
if not t.startswith('\1\n'):
return t
- s = t.find('\1\n', 2)
+ 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.find('\1\n', 2)
+ s = t.index('\1\n', 2)
mt = t[2:s]
m = {}
for l in mt.splitlines():
--- a/mercurial/hg.py
+++ b/mercurial/hg.py
@@ -61,8 +61,7 @@ def repository(ui, path=None, create=0):
if not path: path = ''
scheme = path
if scheme:
- c = scheme.find(':')
- scheme = c >= 0 and scheme[:c]
+ scheme = scheme.split(":", 1)[0]
ctor = schemes.get(scheme) or schemes['file']
if create:
try:
--- a/mercurial/hgweb/hgweb_mod.py
+++ b/mercurial/hgweb/hgweb_mod.py
@@ -133,21 +133,29 @@ class hgweb(object):
diffopts = self.repo.ui.diffopts()
showfunc = diffopts['showfunc']
ignorews = diffopts['ignorews']
+ ignorewsamount = diffopts['ignorewsamount']
+ ignoreblanklines = diffopts['ignoreblanklines']
for f in modified:
to = r.file(f).read(mmap1[f])
tn = r.file(f).read(mmap2[f])
yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
- showfunc=showfunc, ignorews=ignorews), f, tn)
+ showfunc=showfunc, ignorews=ignorews,
+ ignorewsamount=ignorewsamount,
+ ignoreblanklines=ignoreblanklines), f, tn)
for f in added:
to = None
tn = r.file(f).read(mmap2[f])
yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
- showfunc=showfunc, ignorews=ignorews), f, tn)
+ showfunc=showfunc, ignorews=ignorews,
+ ignorewsamount=ignorewsamount,
+ ignoreblanklines=ignoreblanklines), f, tn)
for f in removed:
to = r.file(f).read(mmap1[f])
tn = None
yield diffblock(mdiff.unidiff(to, date1, tn, date2, f,
- showfunc=showfunc, ignorews=ignorews), f, tn)
+ showfunc=showfunc, ignorews=ignorews,
+ ignorewsamount=ignorewsamount,
+ ignoreblanklines=ignoreblanklines), f, tn)
def changelog(self, pos):
def changenav(**map):
@@ -462,7 +470,7 @@ class hgweb(object):
continue
remain = f[l:]
if "/" in remain:
- short = remain[:remain.find("/") + 1] # bleah
+ short = remain[:remain.index("/") + 1] # bleah
files[short] = (f, None)
else:
short = os.path.basename(remain)
--- a/mercurial/hgweb/server.py
+++ b/mercurial/hgweb/server.py
@@ -127,6 +127,11 @@ class _hgwebhandler(object, BaseHTTPServ
if h[0].lower() == 'content-length':
should_close = False
self.length = int(h[1])
+ # The value of the Connection header is a list of case-insensitive
+ # tokens separated by commas and optional whitespace.
+ if 'close' in [token.strip().lower() for token in
+ self.headers.get('connection', '').split(',')]:
+ should_close = True
if should_close:
self.send_header('Connection', 'close')
self.close_connection = should_close
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -74,8 +74,8 @@ class localrepository(object):
self.transhandle = None
if create:
- if not os.path.exists(path):
- os.mkdir(path)
+ if not os.path.exists(path):
+ os.mkdir(path)
os.mkdir(self.path)
os.mkdir(self.join("data"))
@@ -101,9 +101,13 @@ class localrepository(object):
try:
obj = __import__(modname)
except ImportError:
- raise util.Abort(_('%s hook is invalid '
- '(import of "%s" failed)') %
- (hname, modname))
+ try:
+ # extensions are loaded with hgext_ prefix
+ obj = __import__("hgext_%s" % modname)
+ except ImportError:
+ raise util.Abort(_('%s hook is invalid '
+ '(import of "%s" failed)') %
+ (hname, modname))
try:
for p in funcname.split('.')[1:]:
obj = getattr(obj, p)
--- a/mercurial/lock.py
+++ b/mercurial/lock.py
@@ -85,14 +85,14 @@ class lock(object):
# see if locker is alive. if locker is on this machine but
# not alive, we can safely break lock.
locker = util.readlock(self.f)
- c = locker.find(':')
- if c == -1:
+ try:
+ host, pid = locker.split(":", 1)
+ except ValueError:
return locker
- host = locker[:c]
if host != self.host:
return locker
try:
- pid = int(locker[c+1:])
+ pid = int(pid)
except:
return locker
if util.testpid(pid):
--- a/mercurial/mdiff.py
+++ b/mercurial/mdiff.py
@@ -20,7 +20,8 @@ def splitnewlines(text):
return lines
def unidiff(a, ad, b, bd, fn, r=None, text=False,
- showfunc=False, ignorews=False):
+ showfunc=False, ignorews=False, ignorewsamount=False,
+ ignoreblanklines=False):
if not a and not b: return ""
epoch = util.datestr((0, 0))
@@ -49,7 +50,9 @@ def unidiff(a, ad, b, bd, fn, r=None, te
al = splitnewlines(a)
bl = splitnewlines(b)
l = list(bunidiff(a, b, al, bl, "a/" + fn, "b/" + fn,
- showfunc=showfunc, ignorews=ignorews))
+ showfunc=showfunc, ignorews=ignorews,
+ ignorewsamount=ignorewsamount,
+ ignoreblanklines=ignoreblanklines))
if not l: return ""
# difflib uses a space, rather than a tab
l[0] = "%s\t%s\n" % (l[0][:-2], ad)
@@ -72,8 +75,10 @@ def unidiff(a, ad, b, bd, fn, r=None, te
# context is the number of context lines
# showfunc enables diff -p output
# ignorews ignores all whitespace changes in the diff
+# ignorewsamount ignores changes in the amount of whitespace
+# ignoreblanklines ignores changes whose lines are all blank
def bunidiff(t1, t2, l1, l2, header1, header2, context=3, showfunc=False,
- ignorews=False):
+ ignorews=False, ignorewsamount=False, ignoreblanklines=False):
def contextend(l, len):
ret = l + context
if ret > len:
@@ -116,6 +121,11 @@ def bunidiff(t1, t2, l1, l2, header1, he
if showfunc:
funcre = re.compile('\w')
+ if ignorewsamount:
+ wsamountre = re.compile('[ \t]+')
+ wsappendedre = re.compile(' \n')
+ if ignoreblanklines:
+ wsblanklinesre = re.compile('\n')
if ignorews:
wsre = re.compile('[ \t]')
@@ -149,6 +159,20 @@ def bunidiff(t1, t2, l1, l2, header1, he
if not old and not new:
continue
+ if ignoreblanklines:
+ wsold = wsblanklinesre.sub('', "".join(old))
+ wsnew = wsblanklinesre.sub('', "".join(new))
+ if wsold == wsnew:
+ continue
+
+ if ignorewsamount:
+ wsold = wsamountre.sub(' ', "".join(old))
+ wsold = wsappendedre.sub('\n', wsold)
+ wsnew = wsamountre.sub(' ', "".join(new))
+ wsnew = wsappendedre.sub('\n', wsnew)
+ if wsold == wsnew:
+ continue
+
if ignorews:
wsold = wsre.sub('', "".join(old))
wsnew = wsre.sub('', "".join(new))
--- a/mercurial/ui.py
+++ b/mercurial/ui.py
@@ -76,7 +76,7 @@ class ui(object):
if root is None:
root = os.path.expanduser('~')
for name, path in self.configitems("paths"):
- if path and path.find("://") == -1 and not os.path.isabs(path):
+ if path and "://" not in path and not os.path.isabs(path):
self.cdata.set("paths", name, os.path.join(root, path))
def setconfig(self, section, name, val):
@@ -172,7 +172,8 @@ class ui(object):
def diffopts(self):
if self.diffcache:
return self.diffcache
- result = {'showfunc': True, 'ignorews': False}
+ result = {'showfunc': True, 'ignorews': False,
+ 'ignorewsamount': False, 'ignoreblanklines': False}
for key, value in self.configitems("diff"):
if value:
result[key.lower()] = (value.lower() == 'true')
@@ -208,7 +209,7 @@ class ui(object):
def expandpath(self, loc, default=None):
"""Return repository location relative to cwd or from [paths]"""
- if loc.find("://") != -1 or os.path.exists(loc):
+ if "://" in loc or os.path.exists(loc):
return loc
path = self.config("paths", loc)
@@ -298,7 +299,8 @@ class ui(object):
def smtp():
'''send mail using smtp.'''
- s = smtplib.SMTP()
+ local_hostname = self.config('smtp', 'local_hostname')
+ s = smtplib.SMTP(local_hostname=local_hostname)
mailhost = self.config('smtp', 'host')
if not mailhost:
raise util.Abort(_('no [smtp]host in hgrc - cannot send mail'))
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -620,7 +620,7 @@ else:
def parse_patch_output(output_line):
"""parses the output produced by patch and returns the file name"""
pf = output_line[14:]
- if pf.startswith("'") and pf.endswith("'") and pf.find(" ") >= 0:
+ if pf.startswith("'") and pf.endswith("'") and " " in pf:
pf = pf[1:-1] # Remove the quotes
return pf
--- a/tests/test-help.out
+++ b/tests/test-help.out
@@ -173,12 +173,14 @@ diff repository (or selected files)
options:
- -r --rev revision
- -a --text treat all files as text
- -p --show-function show which function each change is in
- -w --ignore-all-space ignore white space when comparing lines
- -I --include include names matching the given patterns
- -X --exclude exclude names matching the given patterns
+ -r --rev revision
+ -a --text treat all files as text
+ -p --show-function show which function each change is in
+ -w --ignore-all-space ignore white space when comparing lines
+ -b --ignore-space-change ignore changes in the amount of white space
+ -B --ignore-blank-lines ignore changes whose lines are all blank
+ -I --include include names matching the given patterns
+ -X --exclude exclude names matching the given patterns
hg status [OPTION]... [FILE]...
show changed files in the working directory