summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQijiang Fan <fqj1994@gmail.com>2011-10-25 12:37:40 +0800
committerQijiang Fan <fqj1994@gmail.com>2011-10-25 12:37:40 +0800
commit4d96cae645ca33d56b4a4961f2b59bef82773b58 (patch)
tree3a7085b11447f986526447bceca48170e3602af4
parent6e8f1b6597c85527b4721f376e0360bb25543cc8 (diff)
Upstream version 1.3
-rw-r--r--.hg_archival.txt4
-rw-r--r--.hgignore5
-rw-r--r--.hgtags1
-rw-r--r--hgsubversion/__init__.py19
-rw-r--r--hgsubversion/editor.py43
-rw-r--r--hgsubversion/maps.py86
-rw-r--r--hgsubversion/pushmod.py11
-rw-r--r--hgsubversion/replay.py4
-rw-r--r--hgsubversion/stupid.py140
-rw-r--r--hgsubversion/svncommands.py14
-rw-r--r--hgsubversion/svnexternals.py27
-rw-r--r--hgsubversion/svnmeta.py16
-rw-r--r--hgsubversion/svnrepo.py27
-rw-r--r--hgsubversion/svnwrap/common.py2
-rw-r--r--hgsubversion/svnwrap/subvertpy_wrapper.py17
-rw-r--r--hgsubversion/svnwrap/svn_swig_wrapper.py4
-rw-r--r--hgsubversion/util.py78
-rw-r--r--hgsubversion/wrappers.py43
-rwxr-xr-xsetup.py33
-rw-r--r--tests/comprehensive/test_stupid_pull.py13
-rw-r--r--tests/comprehensive/test_verify.py4
-rwxr-xr-xtests/fixtures/branchtagcollision.sh37
-rw-r--r--tests/fixtures/branchtagcollision.svndump198
-rwxr-xr-xtests/fixtures/externals.sh3
-rw-r--r--tests/fixtures/externals.svndump35
-rw-r--r--tests/fixtures/mergeexternals.sh50
-rw-r--r--tests/fixtures/mergeexternals.svndump306
-rwxr-xr-xtests/fixtures/rsvn.py32
-rw-r--r--tests/run.py8
-rw-r--r--tests/test_binaryfiles.py4
-rw-r--r--tests/test_diff.py6
-rw-r--r--tests/test_externals.py38
-rw-r--r--tests/test_fetch_branches.py29
-rw-r--r--tests/test_fetch_command.py6
-rw-r--r--tests/test_fetch_exec.py4
-rw-r--r--tests/test_fetch_mappings.py16
-rw-r--r--tests/test_fetch_renames.py4
-rw-r--r--tests/test_fetch_symlinks.py6
-rw-r--r--tests/test_fetch_truncated.py4
-rw-r--r--tests/test_pull.py16
-rw-r--r--tests/test_push_command.py30
-rw-r--r--tests/test_push_dirs.py15
-rw-r--r--tests/test_push_eol.py4
-rw-r--r--tests/test_push_renames.py44
-rw-r--r--tests/test_rebuildmeta.py27
-rw-r--r--tests/test_single_dir_clone.py32
-rw-r--r--tests/test_startrev.py6
-rw-r--r--tests/test_svnwrap.py12
-rw-r--r--tests/test_tags.py6
-rw-r--r--tests/test_template_keywords.py6
-rw-r--r--tests/test_unaffected_core.py19
-rw-r--r--tests/test_urls.py12
-rw-r--r--tests/test_util.py43
-rw-r--r--tests/test_utility_commands.py10
54 files changed, 1302 insertions, 357 deletions
diff --git a/.hg_archival.txt b/.hg_archival.txt
new file mode 100644
index 0000000..916b999
--- /dev/null
+++ b/.hg_archival.txt
@@ -0,0 +1,4 @@
+repo: f2636cfed11500fdc47d1e3822d8e4a2bd636bf7
+node: 0cbf9fd89672e73165e1bb4db1ec8f7f65b95c94
+branch: default
+tag: 1.3
diff --git a/.hgignore b/.hgignore
index 35c6949..358b897 100644
--- a/.hgignore
+++ b/.hgignore
@@ -12,3 +12,8 @@ MANIFEST
dist
*.egg-info
hgsubversion/__version__.py
+nbproject
+.project
+.pydevproject
+.settings
+*.orig
diff --git a/.hgtags b/.hgtags
index 05a0ea9..d9c1ced 100644
--- a/.hgtags
+++ b/.hgtags
@@ -4,3 +4,4 @@
8e621dbb82d4363a85317638ad237e2817c56347 1.1.1
093ae2915b452539b44390ee4ea14987484e1eee 1.1.2
708234ad6c97fb52417e0b46a86c8373e25123a5 1.2
+4bbc6bf947f56a92e95a04a27b94a9f72d5482d7 1.2.1
diff --git a/hgsubversion/__init__.py b/hgsubversion/__init__.py
index 10fb63f..cc336c8 100644
--- a/hgsubversion/__init__.py
+++ b/hgsubversion/__init__.py
@@ -38,14 +38,14 @@ try:
# force demandimport to load templatekw
templatekw.keywords
except ImportError:
- templatekw = None
+ templatekw = None
try:
from mercurial import revset
# force demandimport to load revset
revset.methods
except ImportError:
- revset = None
+ revset = None
try:
from mercurial import subrepo
@@ -99,14 +99,21 @@ wrapcmds = { # cmd: generic, target, fixdoc, ppopts, opts
]),
}
-
-# only need the discovery variant of this code when we drop hg < 1.6
try:
from mercurial import discovery
+ def findcommonoutgoing(orig, *args, **opts):
+ capable = getattr(args[1], 'capable', lambda x: False)
+ if capable('subversion'):
+ return wrappers.findcommonoutgoing(*args, **opts)
+ else:
+ return orig(*args, **opts)
+ extensions.wrapfunction(discovery, 'findcommonoutgoing', findcommonoutgoing)
+except AttributeError:
+ # only need the discovery variant of this code when we drop hg < 1.6
def findoutgoing(orig, *args, **opts):
capable = getattr(args[1], 'capable', lambda x: False)
if capable('subversion'):
- return wrappers.outgoing(*args, **opts)
+ return wrappers.findoutgoing(*args, **opts)
else:
return orig(*args, **opts)
extensions.wrapfunction(discovery, 'findoutgoing', findoutgoing)
@@ -169,7 +176,7 @@ def extsetup():
def reposetup(ui, repo):
if repo.local():
- svnrepo.generate_repo_class(ui, repo)
+ svnrepo.generate_repo_class(ui, repo)
_old_local = hg.schemes['file']
def _lookup(url):
diff --git a/hgsubversion/editor.py b/hgsubversion/editor.py
index 44c39b4..54c04ac 100644
--- a/hgsubversion/editor.py
+++ b/hgsubversion/editor.py
@@ -8,6 +8,7 @@ from mercurial import node
import svnwrap
import util
+import svnexternals
class RevisionData(object):
@@ -118,7 +119,7 @@ class HgEditor(svnwrap.Editor):
# assuming it is a directory
self.current.externals[path] = None
map(self.current.delete, [pat for pat in self.current.files.iterkeys()
- if pat.startswith(path+'/')])
+ if pat.startswith(path + '/')])
for f in ctx.walk(util.PrefixMatch(br_path2)):
f_p = '%s/%s' % (path, f[len(br_path2):])
if f_p not in self.current.files:
@@ -231,11 +232,11 @@ class HgEditor(svnwrap.Editor):
if tag:
changeid = self.meta.tags[tag]
source_rev, source_branch = self.meta.get_source_rev(changeid)[:2]
- cp_f = ''
+ frompath = ''
else:
source_rev = copyfrom_revision
- cp_f, source_branch = self.meta.split_branch_path(copyfrom_path)[:2]
- if cp_f == '' and br_path == '':
+ frompath, source_branch = self.meta.split_branch_path(copyfrom_path)[:2]
+ if frompath == '' and br_path == '':
assert br_path is not None
tmp = source_branch, source_rev, self.current.rev.revnum
self.meta.branches[branch] = tmp
@@ -243,23 +244,22 @@ class HgEditor(svnwrap.Editor):
if new_hash == node.nullid:
self.current.missing.add('%s/' % path)
return path
- cp_f_ctx = self.repo.changectx(new_hash)
- if cp_f != '/' and cp_f != '':
- cp_f = '%s/' % cp_f
+ fromctx = self.repo.changectx(new_hash)
+ if frompath != '/' and frompath != '':
+ frompath = '%s/' % frompath
else:
- cp_f = ''
+ frompath = ''
copies = {}
- for f in cp_f_ctx:
- if not f.startswith(cp_f):
+ for f in fromctx:
+ if not f.startswith(frompath):
continue
- f2 = f[len(cp_f):]
- fctx = cp_f_ctx.filectx(f)
- fp_c = path + '/' + f2
- self.current.set(fp_c, fctx.data(), 'x' in fctx.flags(), 'l' in fctx.flags())
- if fp_c in self.current.deleted:
- del self.current.deleted[fp_c]
+ fctx = fromctx.filectx(f)
+ dest = path + '/' + f[len(frompath):]
+ self.current.set(dest, fctx.data(), 'x' in fctx.flags(), 'l' in fctx.flags())
+ if dest in self.current.deleted:
+ del self.current.deleted[dest]
if branch == source_branch:
- copies[fp_c] = f
+ copies[dest] = f
if copies:
# Preserve the directory copy records if no file was changed between
# the source and destination revisions, or discard it completely.
@@ -267,8 +267,15 @@ class HgEditor(svnwrap.Editor):
if parentid != revlog.nullid:
parentctx = self.repo.changectx(parentid)
for k, v in copies.iteritems():
- if util.issamefile(parentctx, cp_f_ctx, v):
+ if util.issamefile(parentctx, fromctx, v):
self.current.copies[k] = v
+ # Copy the externals definitions of copied directories
+ fromext = svnexternals.parse(self.ui, fromctx)
+ for p, v in fromext.iteritems():
+ pp = p and (p + '/') or ''
+ if pp.startswith(frompath):
+ dest = (path + '/' + pp[len(frompath):]).rstrip('/')
+ self.current.externals[dest] = v
return path
@svnwrap.ieditor
diff --git a/hgsubversion/maps.py b/hgsubversion/maps.py
index 7fbe2cf..93a3cbb 100644
--- a/hgsubversion/maps.py
+++ b/hgsubversion/maps.py
@@ -5,6 +5,7 @@ from mercurial import util as hgutil
from mercurial import node
import svncommands
+import util
class AuthorMap(dict):
'''A mapping from Subversion-style authors to Mercurial-style
@@ -34,6 +35,8 @@ class AuthorMap(dict):
def load(self, path):
''' Load mappings from a file at the specified path. '''
+
+ path = os.path.expandvars(path)
if not os.path.exists(path):
return
@@ -43,12 +46,9 @@ class AuthorMap(dict):
self.ui.note('reading authormap from %s\n' % path)
f = open(path, 'r')
- for number, line in enumerate(f):
-
- if writing:
- writing.write(line)
+ for number, line_org in enumerate(f):
- line = line.split('#')[0]
+ line = line_org.split('#')[0]
if not line.strip():
continue
@@ -61,10 +61,15 @@ class AuthorMap(dict):
src = src.strip()
dst = dst.strip()
- self.ui.debug('adding author %s to author map\n' % src)
- if src in self and dst != self[src]:
- msg = 'overriding author: "%s" to "%s" (%s)\n'
- self.ui.status(msg % (self[src], dst, src))
+
+ if writing:
+ if not src in self:
+ self.ui.debug('adding author %s to author map\n' % src)
+ elif dst != self[src]:
+ msg = 'overriding author: "%s" to "%s" (%s)\n'
+ self.ui.status(msg % (self[src], dst, src))
+ writing.write(line_org)
+
self[src] = dst
f.close()
@@ -132,14 +137,14 @@ class Tags(dict):
print 'tagmap too new -- please upgrade'
raise NotImplementedError
for l in f:
- hash, revision, tag = l.split(' ', 2)
+ ha, revision, tag = l.split(' ', 2)
revision = int(revision)
tag = tag[:-1]
if self.endrev is not None and revision > self.endrev:
break
if not tag:
continue
- dict.__setitem__(self, tag, node.bin(hash))
+ dict.__setitem__(self, tag, node.bin(ha))
f.close()
def _write(self):
@@ -164,11 +169,11 @@ class Tags(dict):
def __setitem__(self, tag, info):
if not tag:
raise hgutil.Abort('tag cannot be empty')
- hash, revision = info
+ ha, revision = info
f = open(self.path, 'a')
- f.write('%s %s %s\n' % (node.hex(hash), revision, tag))
+ f.write('%s %s %s\n' % (node.hex(ha), revision, tag))
f.close()
- dict.__setitem__(self, tag, hash)
+ dict.__setitem__(self, tag, ha)
class RevMap(dict):
@@ -178,13 +183,28 @@ class RevMap(dict):
def __init__(self, repo):
dict.__init__(self)
self.path = os.path.join(repo.path, 'svn', 'rev_map')
- self.youngest = 0
+ self.ypath = os.path.join(repo.path, 'svn', 'lastpulled')
+ # TODO(durin42): Consider moving management of the youngest
+ # file to svnmeta itself rather than leaving it here.
+ # must load youngest file first, or else self._load() can
+ # clobber the info
+ _yonngest_str = util.load_string(self.ypath, '0')
+ self._youngest = int(_yonngest_str.strip())
self.oldest = 0
if os.path.isfile(self.path):
self._load()
else:
self._write()
+ def _set_youngest(self, rev):
+ self._youngest = max(self._youngest, rev)
+ util.save_string(self.ypath, str(self._youngest) + '\n')
+
+ def _get_youngest(self):
+ return self._youngest
+
+ youngest = property(_get_youngest, _set_youngest)
+
def hashes(self):
return dict((v, k) for (k, v) in self.iteritems())
@@ -199,7 +219,7 @@ class RevMap(dict):
print 'revmap too new -- please upgrade'
raise NotImplementedError
for l in f:
- revnum, hash, branch = l.split(' ', 2)
+ revnum, ha, branch = l.split(' ', 2)
if branch == '\n':
branch = None
else:
@@ -209,7 +229,7 @@ class RevMap(dict):
self.youngest = revnum
if revnum < self.oldest or not self.oldest:
self.oldest = revnum
- dict.__setitem__(self, (revnum, branch), node.bin(hash))
+ dict.__setitem__(self, (revnum, branch), node.bin(ha))
f.close()
def _write(self):
@@ -217,17 +237,17 @@ class RevMap(dict):
f.write('%s\n' % self.VERSION)
f.close()
- def __setitem__(self, key, hash):
+ def __setitem__(self, key, ha):
revnum, branch = key
f = open(self.path, 'a')
b = branch or ''
- f.write(str(revnum) + ' ' + node.hex(hash) + ' ' + b + '\n')
+ f.write(str(revnum) + ' ' + node.hex(ha) + ' ' + b + '\n')
f.close()
if revnum > self.youngest or not self.youngest:
self.youngest = revnum
if revnum < self.oldest or not self.oldest:
self.oldest = revnum
- dict.__setitem__(self, (revnum, branch), hash)
+ dict.__setitem__(self, (revnum, branch), ha)
class FileMap(object):
@@ -247,12 +267,12 @@ class FileMap(object):
yield name[:e], name[e+1:]
e = name.rfind('/', 0, e)
- def check(self, map, path):
- map = getattr(self, map)
- for pre, suf in self._rpairs(path):
- if pre not in map:
+ def check(self, m, path):
+ m = getattr(self, m)
+ for pre, _suf in self._rpairs(path):
+ if pre not in m:
continue
- return map[pre]
+ return m[pre]
return None
def __contains__(self, path):
@@ -268,13 +288,17 @@ class FileMap(object):
return False
return True
- def add(self, fn, map, path):
- mapping = getattr(self, map)
+ # Needed so empty filemaps are false
+ def __len__(self):
+ return len(self.include) + len(self.exclude)
+
+ def add(self, fn, m, path):
+ mapping = getattr(self, m)
if path in mapping:
msg = 'duplicate %s entry in %s: "%s"\n'
- self.ui.status(msg % (map, fn, path))
+ self.ui.status(msg % (m, fn, path))
return
- bits = map.strip('e'), path
+ bits = m.strip('e'), path
self.ui.debug('%sing %s\n' % bits)
mapping[path] = path
@@ -365,8 +389,8 @@ class TagMap(dict):
oldname = newname
other =
- The oldname tag from SVN will be represented as newname in the hg tags;
- the other tag will not be reflected in the hg repository.
+ The oldname tag from SVN will be represented as newname in the hg tags;
+ the other tag will not be reflected in the hg repository.
'''
def __init__(self, ui, path):
diff --git a/hgsubversion/pushmod.py b/hgsubversion/pushmod.py
index e1f5231..7c0a104 100644
--- a/hgsubversion/pushmod.py
+++ b/hgsubversion/pushmod.py
@@ -122,6 +122,9 @@ def commit(ui, repo, rev_ctx, meta, base_revision, svn):
props.setdefault(file, {})['svn:executable'] = '*'
if 'l' in fctx.flags():
props.setdefault(file, {})['svn:special'] = '*'
+ isbinary = hgutil.binary(new_data)
+ if isbinary:
+ props.setdefault(file, {})['svn:mime-type'] = 'application/octet-stream'
if file not in parent:
renamed = fctx.renamed()
@@ -141,6 +144,8 @@ def commit(ui, repo, rev_ctx, meta, base_revision, svn):
if ('l' in parent.filectx(file).flags()
and 'l' not in rev_ctx.filectx(file).flags()):
props.setdefault(file, {})['svn:special'] = None
+ if hgutil.binary(base_data) and not isbinary:
+ props.setdefault(file, {})['svn:mime-type'] = None
action = 'modify'
else:
pos = file.rfind('/')
@@ -178,11 +183,7 @@ def commit(ui, repo, rev_ctx, meta, base_revision, svn):
if tf in file_data and tf != ntf:
file_data[ntf] = file_data[tf]
if tf in props:
- props[ntf] = props[tf]
- del props[tf]
- if hgutil.binary(file_data[ntf][1]):
- props.setdefault(ntf, {}).update(props.get(ntf, {}))
- props.setdefault(ntf, {})['svn:mime-type'] = 'application/octet-stream'
+ props[ntf] = props.pop(tf)
del file_data[tf]
addeddirs = [svnpath(d) for d in addeddirs]
diff --git a/hgsubversion/replay.py b/hgsubversion/replay.py
index 92db01e..10d3b48 100644
--- a/hgsubversion/replay.py
+++ b/hgsubversion/replay.py
@@ -174,7 +174,7 @@ def convert_rev(ui, meta, svn, r, tbdelta, firstrun):
date,
extra)
- new_hash = meta.repo.commitctx(current_ctx)
+ new_hash = meta.repo.svn_commitctx(current_ctx)
util.describe_commit(ui, new_hash, branch)
if (rev.revnum, branch) not in meta.revmap and not tag:
meta.revmap[rev.revnum, branch] = new_hash
@@ -209,7 +209,7 @@ def convert_rev(ui, meta, svn, r, tbdelta, firstrun):
meta.authors[rev.author],
date,
extra)
- new_hash = meta.repo.commitctx(current_ctx)
+ new_hash = meta.repo.svn_commitctx(current_ctx)
util.describe_commit(ui, new_hash, branch)
if (rev.revnum, branch) not in meta.revmap:
meta.revmap[rev.revnum, branch] = new_hash
diff --git a/hgsubversion/stupid.py b/hgsubversion/stupid.py
index 50e13d6..159396e 100644
--- a/hgsubversion/stupid.py
+++ b/hgsubversion/stupid.py
@@ -2,10 +2,11 @@ import cStringIO
import errno
import re
-from mercurial import patch
-from mercurial import node
from mercurial import context
+from mercurial import node
+from mercurial import patch
from mercurial import revlog
+from mercurial import util as hgutil
import svnwrap
import svnexternals
@@ -49,7 +50,6 @@ def print_your_svn_is_old_message(ui): #pragma: no cover
ui.status("In light of that, I'll fall back and do diffs, but it won't do "
"as good a job. You should really upgrade your server.\n")
-
def mempatchproxy(parentctx, files):
# Avoid circular references patch.patchfile -> mempatch
patchfile = patch.patchfile
@@ -79,17 +79,32 @@ def mempatchproxy(parentctx, files):
def filteriterhunks(meta):
iterhunks = patch.iterhunks
- def filterhunks(ui, fp, sourcefile=None, textmode=False):
+ def filterhunks(*args, **kwargs):
+ # ui, fp, sourcefile=None, textmode=False
applycurrent = False
# Passing False instead of textmode because we should never
# be ignoring EOL type.
- if not iterhunks.func_defaults:
- # Since 1.7 (cfedc529e4a1)
- gen = iterhunks(ui, fp)
- elif len(iterhunks.func_defaults) == 1:
- gen = iterhunks(ui, fp, sourcefile)
+ if iterhunks.func_code.co_argcount == 1:
+ # Since 1.9 (28762bb767dc)
+ fp = args[0]
+ gen = iterhunks(fp)
else:
- gen = iterhunks(ui, fp, sourcefile, textmode)
+ ui, fp = args[:2]
+ if len(args) > 2:
+ sourcefile = args[2]
+ else:
+ sourcefile = kwargs.get('sourcefile', None)
+ if len(args) > 3:
+ textmode = args[3]
+ else:
+ textmode = kwargs.get('textmode', False)
+ if not iterhunks.func_defaults:
+ # Since 1.7 (cfedc529e4a1)
+ gen = iterhunks(ui, fp)
+ elif len(iterhunks.func_defaults) == 1:
+ gen = iterhunks(ui, fp, sourcefile)
+ else:
+ gen = iterhunks(ui, fp, sourcefile, textmode)
for data in gen:
if data[0] == 'file':
if data[1][1] in meta.filemap:
@@ -101,6 +116,71 @@ def filteriterhunks(meta):
yield data
return filterhunks
+def patchrepoold(ui, meta, parentctx, patchfp):
+ files = {}
+ try:
+ oldpatchfile = patch.patchfile
+ olditerhunks = patch.iterhunks
+ patch.patchfile = mempatchproxy(parentctx, files)
+ patch.iterhunks = filteriterhunks(meta)
+ try:
+ # We can safely ignore the changed list since we are
+ # handling non-git patches. Touched files are known
+ # by our memory patcher.
+ patch_st = patch.applydiff(ui, patchfp, {}, strip=0)
+ finally:
+ patch.patchfile = oldpatchfile
+ patch.iterhunks = olditerhunks
+ except patch.PatchError:
+ # TODO: this happens if the svn server has the wrong mime
+ # type stored and doesn't know a file is binary. It would
+ # be better to do one file at a time and only do a
+ # full fetch on files that had problems.
+ raise BadPatchApply('patching failed')
+ # if this patch didn't apply right, fall back to exporting the
+ # entire rev.
+ if patch_st == -1:
+ assert False, ('This should only happen on case-insensitive'
+ ' volumes.')
+ elif patch_st == 1:
+ # When converting Django, I saw fuzz on .po files that was
+ # causing revisions to end up failing verification. If that
+ # can be fixed, maybe this won't ever be reached.
+ raise BadPatchApply('patching succeeded with fuzz')
+ return files
+
+try:
+ class svnbackend(patch.repobackend):
+ def getfile(self, fname):
+ data, (islink, isexec) = super(svnbackend, self).getfile(fname)
+ if islink:
+ data = 'link ' + data
+ return data, (islink, isexec)
+except AttributeError:
+ svnbackend = None
+
+def patchrepo(ui, meta, parentctx, patchfp):
+ if not svnbackend:
+ return patchrepoold(ui, meta, parentctx, patchfp)
+ store = patch.filestore()
+ try:
+ touched = set()
+ backend = svnbackend(ui, meta.repo, parentctx, store)
+ ret = patch.patchbackend(ui, backend, patchfp, 0, touched)
+ if ret < 0:
+ raise BadPatchApply('patching failed')
+ if ret > 0:
+ raise BadPatchApply('patching succeeded with fuzz')
+ files = {}
+ for f in touched:
+ try:
+ data, mode, copied = store.getfile(f)
+ files[f] = data
+ except IOError:
+ files[f] = None
+ return files
+ finally:
+ store.close()
def diff_branchrev(ui, svn, meta, branch, branchpath, r, parentctx):
"""Extract all 'branch' content at a given revision.
@@ -146,38 +226,9 @@ def diff_branchrev(ui, svn, meta, branch, branchpath, r, parentctx):
# are marked as touched. Content is loaded on demand.
touched_files.update(any_file_re.findall(d))
if d2.strip() and len(re.findall('\n[-+]', d2.strip())) > 0:
- try:
- oldpatchfile = patch.patchfile
- olditerhunks = patch.iterhunks
- patch.patchfile = mempatchproxy(parentctx, files_data)
- patch.iterhunks = filteriterhunks(meta)
- try:
- # We can safely ignore the changed list since we are
- # handling non-git patches. Touched files are known
- # by our memory patcher.
- patch_st = patch.applydiff(ui, cStringIO.StringIO(d2),
- {}, strip=0)
- finally:
- patch.patchfile = oldpatchfile
- patch.iterhunks = olditerhunks
- except patch.PatchError:
- # TODO: this happens if the svn server has the wrong mime
- # type stored and doesn't know a file is binary. It would
- # be better to do one file at a time and only do a
- # full fetch on files that had problems.
- raise BadPatchApply('patching failed')
+ files_data = patchrepo(ui, meta, parentctx, cStringIO.StringIO(d2))
for x in files_data.iterkeys():
ui.note('M %s\n' % x)
- # if this patch didn't apply right, fall back to exporting the
- # entire rev.
- if patch_st == -1:
- assert False, ('This should only happen on case-insensitive'
- ' volumes.')
- elif patch_st == 1:
- # When converting Django, I saw fuzz on .po files that was
- # causing revisions to end up failing verification. If that
- # can be fixed, maybe this won't ever be reached.
- raise BadPatchApply('patching succeeded with fuzz')
else:
ui.status('Not using patch for %s, diff had no hunks.\n' %
r.revnum)
@@ -357,7 +408,7 @@ def fetch_externals(ui, svn, branchpath, r, parentctx):
# revision in the common case.
dirs = set(externals)
if parentctx.node() == revlog.nullid:
- dirs.update([p for p,k in svn.list_files(branchpath, r.revnum) if k == 'd'])
+ dirs.update([p for p, k in svn.list_files(branchpath, r.revnum) if k == 'd'])
dirs.add('')
else:
branchprefix = (branchpath and branchpath + '/') or branchpath
@@ -509,7 +560,7 @@ def branches_in_paths(meta, tbdelta, paths, revnum, checkpath, listdir):
# we need to detect those branches. It's a little thorny and slow, but
# seems to be the best option.
elif paths[p].copyfrom_path and not p.startswith('tags/'):
- paths_need_discovery.extend(['%s/%s' % (p,x[0])
+ paths_need_discovery.extend(['%s/%s' % (p, x[0])
for x in listdir(p, revnum)
if x[1] == 'f'])
@@ -539,6 +590,9 @@ def branches_in_paths(meta, tbdelta, paths, revnum, checkpath, listdir):
def convert_rev(ui, meta, svn, r, tbdelta, firstrun):
# this server fails at replay
+ if meta.filemap:
+ raise hgutil.Abort('filemaps currently unsupported with stupid replay.')
+
branches = branches_in_paths(meta, tbdelta, r.paths, r.revnum,
svn.checkpath, svn.list_files)
brpaths = branches.values()
@@ -659,7 +713,7 @@ def convert_rev(ui, meta, svn, r, tbdelta, firstrun):
meta.authors[r.author],
date,
extra)
- ha = meta.repo.commitctx(current_ctx)
+ ha = meta.repo.svn_commitctx(current_ctx)
if not tag:
if (not origbranch in meta.branches
diff --git a/hgsubversion/svncommands.py b/hgsubversion/svncommands.py
index 529810c..0ae1262 100644
--- a/hgsubversion/svncommands.py
+++ b/hgsubversion/svncommands.py
@@ -55,7 +55,7 @@ def verify(ui, repo, args=None, **opts):
svnfiles.add(fn)
fp = fn
if branchpath:
- fp = branchpath + '/' + fn
+ fp = branchpath + '/' + fn
data, mode = svn.get_file(posixpath.normpath(fp), srev)
fctx = ctx[fn]
dmatch = fctx.data() == data
@@ -95,6 +95,7 @@ def rebuildmeta(ui, repo, args, **opts):
if not os.path.exists(svnmetadir):
os.makedirs(svnmetadir)
+ lastpulled = open(os.path.join(svnmetadir, 'lastpulled'), 'wb')
revmap = open(os.path.join(svnmetadir, 'rev_map'), 'w')
revmap.write('1\n')
last_rev = -1
@@ -120,13 +121,18 @@ def rebuildmeta(ui, repo, args, **opts):
# it would make us use O(revisions^2) time, so we perform an extra traversal
# of the repository instead. During this traversal, we find all converted
# changesets that close a branch, and store their first parent
+ youngest = 0
for rev in repo:
util.progress(ui, 'prepare', rev, total=numrevs)
ctx = repo[rev]
extra = ctx.extra()
convinfo = extra.get('convert_revision', None)
+ if not convinfo:
+ continue
+ svnrevnum = int(convinfo.rsplit('@', 1)[1])
+ youngest = max(youngest, svnrevnum)
- if not convinfo or not extra.get('close', None):
+ if extra.get('close', None) is None:
continue
droprev = lambda x: x.rsplit('@', 1)[0]
@@ -136,6 +142,7 @@ def rebuildmeta(ui, repo, args, **opts):
if droprev(parentinfo) == droprev(convinfo):
closed.add(parentctx.rev())
+ lastpulled.write(str(youngest) + '\n')
util.progress(ui, 'prepare', None, total=numrevs)
for rev in repo:
@@ -238,7 +245,8 @@ def rebuildmeta(ui, repo, args, **opts):
if parentpath.startswith('tags/') and parentextra.get('close'):
continue
- elif parentpath.startswith('branches/'): branch = parentpath[len('branches/'):]
+ elif parentpath.startswith('branches/'):
+ branch = parentpath[len('branches/'):]
elif parentpath == 'trunk':
branch = None
else:
diff --git a/hgsubversion/svnexternals.py b/hgsubversion/svnexternals.py
index 51a5c9a..38cc40b 100644
--- a/hgsubversion/svnexternals.py
+++ b/hgsubversion/svnexternals.py
@@ -12,6 +12,14 @@ try:
except (ImportError, AttributeError), e:
subrepo = None
+passpegrev = True # see svnsubrepo below
+try:
+ canonpath = hgutil.canonpath
+except (ImportError, AttributeError):
+ from mercurial import scmutil
+ canonpath = scmutil.canonpath
+ passpegrev = False
+
import util
class externalsfile(dict):
@@ -51,7 +59,6 @@ class externalsfile(dict):
def read(self, data):
self.clear()
fp = cStringIO.StringIO(data)
- dirs = {}
target = None
for line in fp.readlines():
if not line.strip():
@@ -112,7 +119,7 @@ def parsedefinition(line):
revgroup = 2
path, rev, source = m.group(1, 2, 3)
try:
- nrev = int(rev)
+ int(rev) # ensure revision is int()able, so we bail otherwise
norevline = line[:m.start(revgroup)] + '{REV}' + line[m.end(revgroup):]
except (TypeError, ValueError):
norevline = line
@@ -139,6 +146,9 @@ def parsedefinitions(ui, repo, svnroot, exts):
defs = []
for base in sorted(exts):
for line in exts[base]:
+ if not line.strip() or line.lstrip().startswith('#'):
+ # Ignore comments and blank lines
+ continue
try:
path, rev, source, pegrev, norevline = parsedefinition(line)
except BadDefinition:
@@ -148,7 +158,7 @@ def parsedefinitions(ui, repo, svnroot, exts):
if source is None:
continue
wpath = hgutil.pconvert(os.path.join(base, path))
- wpath = hgutil.canonpath(repo.root, '', wpath)
+ wpath = canonpath(repo.root, '', wpath)
defs.append((wpath, rev, source, pegrev, norevline, base))
# Check target dirs are not nested
defs.sort()
@@ -221,7 +231,7 @@ class externalsupdater:
if rev:
revspec = ['-r', rev]
if os.path.isdir(path):
- exturl, extroot, extrev = getsvninfo(path)
+ exturl, _extroot, extrev = getsvninfo(path)
# Comparing the source paths is not enough, but I don't
# know how to compare path+pegrev. The following update
# might fail if the path was replaced by another unrelated
@@ -336,7 +346,7 @@ def getchanges(ui, repo, parentctx, exts):
if exts:
defs = parsedefinitions(ui, repo, '', exts)
hgsub, hgsubstate = [], []
- for path, rev, source, pegrev, norevline, base in sorted(defs):
+ for path, rev, _source, _pegrev, norevline, base in sorted(defs):
hgsub.append('%s = [hgsubversion] %s:%s\n'
% (path, base, norevline))
if rev is None:
@@ -402,7 +412,12 @@ if subrepo:
svnurl = self._ctx._repo.ui.expandpath('default')
svnroot = getsvninfo(util.normalize_url(svnurl))[1]
source = resolvesource(self._ui, svnroot, source)
- if pegrev is not None:
+ # hg < 1.9 svnsubrepo calls "svn checkout" with --rev
+ # only, so peg revisions are correctly used. 1.9 and
+ # higher, append the rev as a peg revision to the source
+ # URL, so we cannot add our own. We assume that "-r10
+ # url@2" will be similar to "url@10" most of the time.
+ if pegrev is not None and passpegrev:
source = source + '@' + pegrev
state = (source, state[1])
# hg-1.7.4-c19b9282d3a7 introduced the overwrite argument
diff --git a/hgsubversion/svnmeta.py b/hgsubversion/svnmeta.py
index 3c91b0e..68ab4a7 100644
--- a/hgsubversion/svnmeta.py
+++ b/hgsubversion/svnmeta.py
@@ -257,7 +257,7 @@ class SVNMeta(object):
branchpath = branch[3:]
else:
branchpath = 'branches/%s' % branch
- path = '%s/%s' % (subdir , branchpath)
+ path = '%s/%s' % (subdir, branchpath)
extra['convert_revision'] = 'svn:%(uuid)s%(path)s@%(rev)s' % {
'uuid': self.uuid,
@@ -368,7 +368,7 @@ class SVNMeta(object):
else:
path = test.split('/')[-1]
test = '/'.join(test.split('/')[:-1])
- ln = self.localname(test)
+ ln = self.localname(test)
if ln and ln.startswith('../'):
return None, None, None
return path, ln, test
@@ -424,7 +424,7 @@ class SVNMeta(object):
branch_created_rev = self.branches[branch][2]
if parent_branch == 'trunk':
parent_branch = None
- if branch_created_rev <= number+1 and branch != parent_branch:
+ if branch_created_rev <= number + 1 and branch != parent_branch:
# did the branch exist in previous run
if exact and branch in self.prevbranches:
if self.prevbranches[branch][1] < real_num:
@@ -450,7 +450,7 @@ class SVNMeta(object):
return node.hex(self.revmap[tagged])
tag = fromtag
# Reference an existing tag
- limitedtags = maps.Tags(self.repo, endrev=number-1)
+ limitedtags = maps.Tags(self.repo, endrev=number - 1)
if tag in limitedtags:
return limitedtags[tag]
r, br = self.get_parent_svn_branch_and_rev(number - 1, branch, exact)
@@ -609,7 +609,7 @@ class SVNMeta(object):
branchparent = branchparent.parents()[0]
branch = self.get_source_rev(ctx=branchparent)[1]
- parentctx = self.repo[self.get_parent_revision(rev.revnum+1, branch)]
+ parentctx = self.repo[self.get_parent_revision(rev.revnum + 1, branch)]
if '.hgtags' in parentctx:
tagdata = parentctx.filectx('.hgtags').data()
else:
@@ -639,7 +639,7 @@ class SVNMeta(object):
self.authors[rev.author],
date,
parentctx.extra())
- new_hash = self.repo.commitctx(ctx)
+ new_hash = self.repo.svn_commitctx(ctx)
if not newparent:
assert self.revmap[revnum, branch] == parentctx.node()
self.revmap[revnum, branch] = new_hash
@@ -704,7 +704,7 @@ class SVNMeta(object):
self.authors[rev.author],
date,
extra)
- new = self.repo.commitctx(ctx)
+ new = self.repo.svn_commitctx(ctx)
if not fromtag and (rev.revnum, b) not in self.revmap:
self.revmap[rev.revnum, b] = new
@@ -726,5 +726,5 @@ class SVNMeta(object):
self.authors[rev.author],
self.fixdate(rev.date),
extra)
- new = self.repo.commitctx(ctx)
+ new = self.repo.svn_commitctx(ctx)
self.ui.status('Marked branch %s as closed.\n' % (branch or 'default'))
diff --git a/hgsubversion/svnrepo.py b/hgsubversion/svnrepo.py
index 58ce252..6bb3cd9 100644
--- a/hgsubversion/svnrepo.py
+++ b/hgsubversion/svnrepo.py
@@ -14,6 +14,8 @@ subclass: pull() is called on the instance pull *to*, but not the one pulled
are used to distinguish and filter these operations from others.
"""
+import errno
+
from mercurial import error
from mercurial import util as hgutil
from mercurial import httprepo
@@ -26,6 +28,25 @@ import svnmeta
propertycache = hgutil.propertycache
+class ctxctx(object):
+ """Proxies a ctx object and ensures files is never empty."""
+ def __init__(self, ctx):
+ self._ctx = ctx
+
+ def files(self):
+ return self._ctx.files() or ['.svn']
+
+ def filectx(self, path, filelog=None):
+ if path == '.svn':
+ raise IOError(errno.ENOENT, '.svn is a fake file')
+ return self._ctx.filectx(path, filelog=filelog)
+
+ def __getattr__(self, name):
+ return getattr(self._ctx, name)
+
+ def __getitem__(self, key):
+ return self._ctx[key]
+
def generate_repo_class(ui, repo):
""" This function generates the local repository wrapper. """
@@ -53,6 +74,10 @@ def generate_repo_class(ui, repo):
return wrapper
class svnlocalrepo(superclass):
+ def svn_commitctx(self, ctx):
+ """Commits a ctx, but defeats manifest recycling introduced in hg 1.9."""
+ return self.commitctx(ctxctx(ctx))
+
# TODO use newbranch to allow branch creation in Subversion?
@remotesvn
def push(self, remote, force=False, revs=None, newbranch=None):
@@ -64,7 +89,7 @@ def generate_repo_class(ui, repo):
@remotesvn
def findoutgoing(self, remote, base=None, heads=None, force=False):
- return wrappers.outgoing(repo, remote, heads, force)
+ return wrappers.findoutgoing(repo, remote, heads, force)
def svnmeta(self, uuid=None, subdir=None):
return svnmeta.SVNMeta(self, uuid, subdir)
diff --git a/hgsubversion/svnwrap/common.py b/hgsubversion/svnwrap/common.py
index 9b42b6a..211ff6d 100644
--- a/hgsubversion/svnwrap/common.py
+++ b/hgsubversion/svnwrap/common.py
@@ -38,7 +38,7 @@ def parse_url(url, user=None, passwd=None):
user, passwd = userpass, ''
user, passwd = urllib.unquote(user), urllib.unquote(passwd)
if user and scheme == 'svn+ssh':
- netloc = '@'.join((user, netloc, ))
+ netloc = '@'.join((user, netloc,))
url = urlparse.urlunparse((scheme, netloc, path, params, query, fragment))
return (user or None, passwd or None, url)
diff --git a/hgsubversion/svnwrap/subvertpy_wrapper.py b/hgsubversion/svnwrap/subvertpy_wrapper.py
index ab8cff8..0023d5a 100644
--- a/hgsubversion/svnwrap/subvertpy_wrapper.py
+++ b/hgsubversion/svnwrap/subvertpy_wrapper.py
@@ -87,7 +87,7 @@ class PathAdapter(object):
self.copyfrom_path = intern(self.copyfrom_path)
class AbstractEditor(object):
- __slots__ = ('editor', )
+ __slots__ = ('editor',)
def __init__(self, editor):
self.editor = editor
@@ -131,7 +131,7 @@ class AbstractEditor(object):
self.editor.delete_entry(path, revnum, None)
class FileEditor(AbstractEditor):
- __slots__ = ('path', )
+ __slots__ = ('path',)
def __init__(self, editor, path):
super(FileEditor, self).__init__(editor)
@@ -145,7 +145,7 @@ class FileEditor(AbstractEditor):
del self.path
class DirectoryEditor(AbstractEditor):
- __slots__ = ('path', )
+ __slots__ = ('path',)
def __init__(self, editor, path):
super(DirectoryEditor, self).__init__(editor)
@@ -306,7 +306,7 @@ class SubversionRepo(object):
# ra.get_log(), even with chunk_size set, takes a while
# when converting the 65k+ rev. in LLVM.
self.remote.get_log(paths=paths, revprops=revprops,
- start=start+1, end=stop, limit=chunk_size,
+ start=start + 1, end=stop, limit=chunk_size,
discover_changed_paths=True,
callback=callback)
except SubversionException, e:
@@ -417,9 +417,10 @@ class SubversionRepo(object):
try:
self.remote.replay(revision, oldestrev, AbstractEditor(editor))
- except SubversionException, e: #pragma: no cover
+ except (SubversionException, NotImplementedError), e: #pragma: no cover
# can I depend on this number being constant?
- if (e.args[1] == subvertpy.ERR_RA_NOT_IMPLEMENTED or
+ if (isinstance(e, NotImplementedError) or
+ e.args[1] == subvertpy.ERR_RA_NOT_IMPLEMENTED or
e.args[1] == subvertpy.ERR_UNSUPPORTED_FEATURE):
msg = ('This Subversion server is older than 1.4.0, and '
'cannot satisfy replay requests.')
@@ -476,7 +477,7 @@ class SubversionRepo(object):
# File not found
raise IOError(errno.ENOENT, e.args[0])
raise
- if mode == 'l':
+ if mode == 'l':
linkprefix = "link "
if data.startswith(linkprefix):
data = data[len(linkprefix):]
@@ -530,4 +531,4 @@ class SubversionRepo(object):
if not path or path == '.':
return self.svn_url
assert path[0] != '/', path
- return '/'.join((self.svn_url, urllib.quote(path).rstrip('/'), ))
+ return '/'.join((self.svn_url, urllib.quote(path).rstrip('/'),))
diff --git a/hgsubversion/svnwrap/svn_swig_wrapper.py b/hgsubversion/svnwrap/svn_swig_wrapper.py
index a6bd906..50ec898 100644
--- a/hgsubversion/svnwrap/svn_swig_wrapper.py
+++ b/hgsubversion/svnwrap/svn_swig_wrapper.py
@@ -293,7 +293,7 @@ class SubversionRepo(object):
# when converting the 65k+ rev. in LLVM.
ra.get_log(self.ra,
paths,
- start+1,
+ start + 1,
stop,
chunk_size, #limit of how many log messages to load
True, # don't need to know changed paths
@@ -497,7 +497,7 @@ class SubversionRepo(object):
if e.args[1] in notfound: # File not found
raise IOError(errno.ENOENT, e.args[0])
raise
- if mode == 'l':
+ if mode == 'l':
linkprefix = "link "
if data.startswith(linkprefix):
data = data[len(linkprefix):]
diff --git a/hgsubversion/util.py b/hgsubversion/util.py
index c0dfd1b..f55893e 100644
--- a/hgsubversion/util.py
+++ b/hgsubversion/util.py
@@ -35,7 +35,7 @@ def filterdiff(diff, oldrev, newrev):
diff)
oldrev = formatrev(oldrev)
newrev = formatrev(newrev)
- diff = a_re.sub(r'--- \1'+ oldrev, diff)
+ diff = a_re.sub(r'--- \1' + oldrev, diff)
diff = b_re.sub(r'+++ \1' + newrev, diff)
diff = devnull_re.sub(r'\1 /dev/null\t(working copy)', diff)
diff = header_re.sub(r'Index: \1' + '\n' + ('=' * 67), diff)
@@ -53,16 +53,21 @@ def parentrev(ui, repo, meta, hashes):
def islocalrepo(url):
- if not url.startswith('file:///'):
+ path = str(url) # convert once up front
+ if path.startswith('file:///'):
+ prefixlen = len('file://')
+ elif path.startswith('file:/'):
+ prefixlen = len('file:')
+ else:
return False
- if '#' in url.split('/')[-1]: # strip off #anchor
- url = url[:url.rfind('#')]
- path = url[len('file://'):]
+ if '#' in path.split('/')[-1]: # strip off #anchor
+ path = path[:path.rfind('#')]
+ path = url[prefixlen:]
path = urllib.url2pathname(path).replace(os.sep, '/')
while '/' in path:
- if reduce(lambda x,y: x and y,
+ if reduce(lambda x, y: x and y,
map(lambda p: os.path.exists(os.path.join(path, p)),
- ('hooks', 'format', 'db', ))):
+ ('hooks', 'format', 'db',))):
return True
path = path.rsplit('/', 1)[0]
return False
@@ -94,6 +99,29 @@ def normalize_url(url):
url = '%s#%s' % (url, checkout)
return url
+
+def load_string(file_path, default=None, limit=1024):
+ if not os.path.exists(file_path):
+ return default
+ try:
+ f = open(file_path, 'r')
+ ret = f.read(limit)
+ f.close()
+ except:
+ return default
+ if ret == '':
+ return default
+ return ret
+
+
+def save_string(file_path, string):
+ if string is None:
+ string = ""
+ f = open(file_path, 'wb')
+ f.write(str(string))
+ f.close()
+
+
# TODO remove when we drop 1.3 support
def progress(ui, *args, **kwargs):
if getattr(ui, 'progress', False):
@@ -149,6 +177,24 @@ def outgoing_revisions(repo, reverse_map, sourcerev):
if sourcerev.node() != node.nullid:
return outgoing_rev_hashes
+def outgoing_common_and_heads(repo, reverse_map, sourcerev):
+ """Given a repo and an hg_editor, determines outgoing revisions for the
+ current working copy state. Returns a tuple (common, heads) like
+ discovery.findcommonoutgoing does.
+ """
+ if sourcerev in reverse_map:
+ return ([sourcerev], [sourcerev]) # nothing outgoing
+ sourcecx = repo[sourcerev]
+ while (not sourcecx.node() in reverse_map
+ and sourcecx.node() != node.nullid):
+ ps = sourcecx.parents()
+ if len(ps) != 1:
+ raise hgutil.Abort("Sorry, can't find svn parent of a merge revision.")
+ sourcecx = ps[0]
+ if sourcecx.node() != node.nullid:
+ return ([sourcecx.node()], [sourcerev])
+ return ([sourcerev], [sourcerev]) # nothing outgoing
+
def default_commit_msg(ui):
return ui.config('hgsubversion', 'defaultmessage', '')
@@ -203,10 +249,22 @@ def _templatehelper(ctx, kw):
else:
raise hgutil.Abort('unrecognized hgsubversion keyword %s' % kw)
+def svnrevkw(**args):
+ """:svnrev: String. Converted subversion revision number."""
+ return _templatehelper(args['ctx'], 'svnrev')
+
+def svnpathkw(**args):
+ """:svnpath: String. Converted subversion revision project path."""
+ return _templatehelper(args['ctx'], 'svnpath')
+
+def svnuuidkw(**args):
+ """:svnuuid: String. Converted subversion revision repository identifier."""
+ return _templatehelper(args['ctx'], 'svnuuid')
+
templatekeywords = {
- 'svnrev': (lambda repo, ctx, templ, **a: _templatehelper(ctx, 'svnrev')),
- 'svnpath': (lambda repo, ctx, templ, **a: _templatehelper(ctx, 'svnpath')),
- 'svnuuid': (lambda repo, ctx, templ, **a: _templatehelper(ctx, 'svnuuid')),
+ 'svnrev': svnrevkw,
+ 'svnpath': svnpathkw,
+ 'svnuuid': svnuuidkw,
}
def revset_fromsvn(repo, subset, x):
diff --git a/hgsubversion/wrappers.py b/hgsubversion/wrappers.py
index c698447..3c16b31 100644
--- a/hgsubversion/wrappers.py
+++ b/hgsubversion/wrappers.py
@@ -15,6 +15,12 @@ import svnwrap
import svnrepo
import util
+try:
+ from mercurial import scmutil
+ revpair = scmutil.revpair
+except ImportError:
+ revpair = cmdutil.revpair
+
pullfuns = {
True: replay.convert_rev,
False: stupidmod.convert_rev,
@@ -77,13 +83,22 @@ def incoming(orig, ui, repo, origsource='default', **opts):
ui.status('%s%s\n' % (l1.ljust(13), val))
-def outgoing(repo, dest=None, heads=None, force=False):
+def findcommonoutgoing(repo, other, onlyheads=None, force=False, commoninc=None):
+ assert other.capable('subversion')
+ # split off #rev; TODO implement --revision/#rev support
+ svn = other.svn
+ meta = repo.svnmeta(svn.uuid, svn.subdir)
+ parent = repo.parents()[0].node()
+ hashes = meta.revmap.hashes()
+ return util.outgoing_common_and_heads(repo, hashes, parent)
+
+
+def findoutgoing(repo, dest=None, heads=None, force=False):
"""show changesets not found in the Subversion repository
"""
assert dest.capable('subversion')
-
# split off #rev; TODO implement --revision/#rev support
- svnurl, revs, checkout = util.parseurl(dest.svnurl, heads)
+ #svnurl, revs, checkout = util.parseurl(dest.svnurl, heads)
svn = dest.svn
meta = repo.svnmeta(svn.uuid, svn.subdir)
parent = repo.parents()[0].node()
@@ -104,7 +119,7 @@ def diff(orig, ui, repo, *args, **opts):
if o_r:
parent = repo[o_r[-1]].parents()[0]
opts['rev'] = ['%s:.' % node.hex(parent.node()), ]
- node1, node2 = cmdutil.revpair(repo, opts['rev'])
+ node1, node2 = revpair(repo, opts['rev'])
baserev, _junk = hashes.get(node1, (-1, 'junk'))
newrev, _junk = hashes.get(node2, (-1, 'junk'))
it = patch.diff(repo, node1, node2,
@@ -122,7 +137,11 @@ def push(repo, dest, force, revs):
"""push revisions starting at a specified head back to Subversion.
"""
assert not revs, 'designated revisions for push remains unimplemented.'
- cmdutil.bail_if_changed(repo)
+ if hasattr(cmdutil, 'bail_if_changed'):
+ cmdutil.bail_if_changed(repo)
+ else:
+ # Since 1.9 (d68ddccf276b)
+ cmdutil.bailifchanged(repo)
checkpush = getattr(repo, 'checkpush', None)
if checkpush:
checkpush(force, revs)
@@ -291,11 +310,13 @@ def pull(repo, source, heads=[], force=False):
total = stopat_rev - start
else:
total = svn.HEAD - start
+ lastpulled = None
try:
try:
# start converting revisions
firstrun = True
for r in svn.revisions(start=start, stop=stopat_rev):
+ lastpulled = r.revnum
if (r.author is None and
r.message == 'This is an empty revision for padding.'):
continue
@@ -352,6 +373,8 @@ def pull(repo, source, heads=[], force=False):
util.progress(ui, 'pull', None, total=total)
util.swap_out_encoding(old_encoding)
+ if lastpulled is not None:
+ meta.revmap.youngest = lastpulled
revisions = len(meta.revmap) - oldrevisions
if revisions == 0:
@@ -431,7 +454,13 @@ def clone(orig, ui, source, dest=None, **opts):
"""
data = {}
- def hgclonewrapper(orig, ui, origsource, dest, **opts):
+ def hgclonewrapper(orig, ui, *args, **opts):
+ if getattr(hg, 'peer', None):
+ # Since 1.9 (d976542986d2)
+ origsource = args[1]
+ else:
+ origsource = args[0]
+
if isinstance(origsource, str):
source, branch, checkout = util.parseurl(ui.expandpath(origsource),
opts.get('branch'))
@@ -445,7 +474,7 @@ def clone(orig, ui, source, dest=None, **opts):
data['branches'] = branches
ui.setconfig('hgsubversion', 'branch', branches[-1])
- data['srcrepo'], data['dstrepo'] = orig(ui, origsource, dest, **opts)
+ data['srcrepo'], data['dstrepo'] = orig(ui, *args, **opts)
for opt, (section, name) in optionmap.iteritems():
if opt in opts and opts[opt]:
diff --git a/setup.py b/setup.py
index 5504d04..dec8c0c 100755
--- a/setup.py
+++ b/setup.py
@@ -18,7 +18,8 @@ except ImportError:
from distutils.core import setup
def runcmd(cmd, env):
- p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+ shell = os.name == 'nt'
+ p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=shell,
stderr=subprocess.PIPE, env=env)
out, err = p.communicate()
# If root is executing setup.py, but the repository is owned by
@@ -71,7 +72,7 @@ elif os.path.exists('.hg_archival.txt'):
kw = dict([t.strip() for t in l.split(':', 1)]
for l in open('.hg_archival.txt'))
if 'tag' in kw:
- version = kw['tag']
+ version = kw['tag']
elif 'latesttag' in kw:
version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
else:
@@ -106,22 +107,22 @@ except ImportError:
requires.append('subvertpy>=0.7.4')
setup(
- name = 'hgsubversion',
- version = version,
- url = 'http://bitbucket.org/durin42/hgsubversion',
- license = 'GNU GPL',
- author = 'Augie Fackler, others',
- author_email = 'durin42@gmail.com',
- description = ('hgsubversion is a Mercurial extension for working with '
+ name='hgsubversion',
+ version=version,
+ url='http://bitbucket.org/durin42/hgsubversion',
+ license='GNU GPL',
+ author='Augie Fackler, others',
+ author_email='durin42@gmail.com',
+ description=('hgsubversion is a Mercurial extension for working with '
'Subversion repositories.'),
- long_description = open(os.path.join(os.path.dirname(__file__),
+ long_description=open(os.path.join(os.path.dirname(__file__),
'README')).read(),
- keywords = 'mercurial',
- packages = ('hgsubversion', 'hgsubversion.svnwrap'),
- package_data = { 'hgsubversion': ['help/subversion.rst'] },
- platforms = 'any',
+ keywords='mercurial',
+ packages=('hgsubversion', 'hgsubversion.svnwrap'),
+ package_data={ 'hgsubversion': ['help/subversion.rst'] },
+ platforms='any',
install_requires=requires,
- classifiers = [
+ classifiers=[
'License :: OSI Approved :: GNU General Public License (GPL)',
'Intended Audience :: Developers',
'Topic :: Software Development :: Version Control',
@@ -129,5 +130,5 @@ setup(
'Programming Language :: Python',
'Operating System :: OS Independent',
],
- cmdclass = {'build_py': build_py},
+ cmdclass={'build_py': build_py},
)
diff --git a/tests/comprehensive/test_stupid_pull.py b/tests/comprehensive/test_stupid_pull.py
index 0381b4f..466d460 100644
--- a/tests/comprehensive/test_stupid_pull.py
+++ b/tests/comprehensive/test_stupid_pull.py
@@ -28,7 +28,7 @@ def _do_case(self, name, layout):
checkout_path += '/' + subdir
u.setconfig('hgsubversion', 'stupid', '1')
u.setconfig('hgsubversion', 'layout', layout)
- hg.clone(u, test_util.fileurl(checkout_path), wc2_path, update=False)
+ test_util.hgclone(u, test_util.fileurl(checkout_path), wc2_path, update=False)
if layout == 'single':
self.assertEqual(len(self.repo.heads()), 1)
self.repo2 = hg.repository(ui.ui(), wc2_path)
@@ -45,14 +45,17 @@ attrs = {'_do_case': _do_case,
}
for case in (f for f in os.listdir(test_util.FIXTURES) if f.endswith('.svndump')):
name = 'test_' + case[:-len('.svndump')]
- attrs[name] = buildmethod(case, name, 'auto')
+ # Automatic layout branchtag collision exposes a minor defect
+ # here, but since it isn't a regression we suppress the test case.
+ if case != 'branchtagcollision.svndump':
+ attrs[name] = buildmethod(case, name, 'auto')
name += '_single'
attrs[name] = buildmethod(case, name, 'single')
-StupidPullTests = type('StupidPullTests', (test_util.TestBase, ), attrs)
+StupidPullTests = type('StupidPullTests', (test_util.TestBase,), attrs)
def suite():
- all = [unittest.TestLoader().loadTestsFromTestCase(StupidPullTests),
+ all_tests = [unittest.TestLoader().loadTestsFromTestCase(StupidPullTests),
]
- return unittest.TestSuite(all)
+ return unittest.TestSuite(all_tests)
diff --git a/tests/comprehensive/test_verify.py b/tests/comprehensive/test_verify.py
index 42414ab..65bdfa9 100644
--- a/tests/comprehensive/test_verify.py
+++ b/tests/comprehensive/test_verify.py
@@ -51,5 +51,5 @@ for case in fixtures:
VerifyTests = type('VerifyTests', (test_util.TestBase,), attrs)
def suite():
- all = [unittest.TestLoader().loadTestsFromTestCase(VerifyTests)]
- return unittest.TestSuite(all)
+ all_tests = [unittest.TestLoader().loadTestsFromTestCase(VerifyTests)]
+ return unittest.TestSuite(all_tests)
diff --git a/tests/fixtures/branchtagcollision.sh b/tests/fixtures/branchtagcollision.sh
new file mode 100755
index 0000000..2660fe3
--- /dev/null
+++ b/tests/fixtures/branchtagcollision.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+#
+# Generate branchtagcollision.svndump
+#
+# Generates an svn repository with a branch and a tag that have the same name.
+
+
+mkdir temp
+cd temp
+
+svnadmin create testrepo
+svn checkout file://`pwd`/testrepo client
+
+cd client
+mkdir trunk
+mkdir branches
+mkdir tags
+
+svn add trunk branches tags
+svn commit -m "Initial commit"
+
+echo "fileA" >> trunk/fileA
+svn add trunk/fileA
+svn commit -m "Added fileA"
+
+svn cp trunk branches/A
+svn commit -m "added branch"
+
+echo "fileB" >> trunk/fileB
+svn add trunk/fileB
+svn commit -m "Added fileB"
+
+svn cp trunk tags/A
+svn commit -m "added bad tag"
+
+cd ..
+svnadmin dump testrepo > ../branchtagcollision.svndump
diff --git a/tests/fixtures/branchtagcollision.svndump b/tests/fixtures/branchtagcollision.svndump
new file mode 100644
index 0000000..f0d2e6f
--- /dev/null
+++ b/tests/fixtures/branchtagcollision.svndump
@@ -0,0 +1,198 @@
+SVN-fs-dump-format-version: 2
+
+UUID: 764a21f0-1c44-4bc9-b81b-0321cc58934d
+
+Revision-number: 0
+Prop-content-length: 56
+Content-length: 56
+
+K 8
+svn:date
+V 27
+2011-05-24T15:46:13.951233Z
+PROPS-END
+
+Revision-number: 1
+Prop-content-length: 114
+Content-length: 114
+
+K 7
+svn:log
+V 14
+Initial commit
+K 10
+svn:author
+V 5
+augie
+K 8
+svn:date
+V 27
+2011-05-24T15:46:14.518711Z
+PROPS-END
+
+Node-path: branches
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: tags
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Revision-number: 2
+Prop-content-length: 111
+Content-length: 111
+
+K 7
+svn:log
+V 11
+Added fileA
+K 10
+svn:author
+V 5
+augie
+K 8
+svn:date
+V 27
+2011-05-24T15:46:14.922304Z
+PROPS-END
+
+Node-path: trunk/fileA
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 6
+Text-content-md5: 017715e60b9a9450d604e0d489ebc83a
+Text-content-sha1: d0bcb0015aaadb5317419294648c8da6714af81f
+Content-length: 16
+
+PROPS-END
+fileA
+
+
+Revision-number: 3
+Prop-content-length: 112
+Content-length: 112
+
+K 7
+svn:log
+V 12
+added branch
+K 10
+svn:author
+V 5
+augie
+K 8
+svn:date
+V 27
+2011-05-24T15:46:15.328642Z
+PROPS-END
+
+Node-path: branches/A
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 1
+Node-copyfrom-path: trunk
+
+
+Node-path: branches/A/fileA
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 2
+Node-copyfrom-path: trunk/fileA
+Text-copy-source-md5: 017715e60b9a9450d604e0d489ebc83a
+Text-copy-source-sha1: d0bcb0015aaadb5317419294648c8da6714af81f
+
+
+Revision-number: 4
+Prop-content-length: 111
+Content-length: 111
+
+K 7
+svn:log
+V 11
+Added fileB
+K 10
+svn:author
+V 5
+augie
+K 8
+svn:date
+V 27
+2011-05-24T15:46:15.616098Z
+PROPS-END
+
+Node-path: trunk/fileB
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 6
+Text-content-md5: 4eb63bbdec5dfa425e3735dc1d4c5ee8
+Text-content-sha1: 03939175ceac92b9c6464d037a0243e22563c423
+Content-length: 16
+
+PROPS-END
+fileB
+
+
+Revision-number: 5
+Prop-content-length: 113
+Content-length: 113
+
+K 7
+svn:log
+V 13
+added bad tag
+K 10
+svn:author
+V 5
+augie
+K 8
+svn:date
+V 27
+2011-05-24T15:46:16.057440Z
+PROPS-END
+
+Node-path: tags/A
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 1
+Node-copyfrom-path: trunk
+
+
+Node-path: tags/A/fileA
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 2
+Node-copyfrom-path: trunk/fileA
+Text-copy-source-md5: 017715e60b9a9450d604e0d489ebc83a
+Text-copy-source-sha1: d0bcb0015aaadb5317419294648c8da6714af81f
+
+
+Node-path: tags/A/fileB
+Node-kind: file
+Node-action: add
+Node-copyfrom-rev: 4
+Node-copyfrom-path: trunk/fileB
+Text-copy-source-md5: 4eb63bbdec5dfa425e3735dc1d4c5ee8
+Text-copy-source-sha1: 03939175ceac92b9c6464d037a0243e22563c423
+
+
diff --git a/tests/fixtures/externals.sh b/tests/fixtures/externals.sh
index 45bc1f9..26722e6 100755
--- a/tests/fixtures/externals.sh
+++ b/tests/fixtures/externals.sh
@@ -37,7 +37,10 @@ svn propset -F externals svn:externals .
svn ci -m "set externals on ."
# Add another one
cat > externals <<EOF
+# A comment, then an empty line, then a blank line
+
^/externals/project1 deps/project1
+
-r2 ^/externals/project2@2 deps/project2
EOF
svn propset -F externals svn:externals .
diff --git a/tests/fixtures/externals.svndump b/tests/fixtures/externals.svndump
index cebf4b5..824e4b9 100644
--- a/tests/fixtures/externals.svndump
+++ b/tests/fixtures/externals.svndump
@@ -1,6 +1,6 @@
SVN-fs-dump-format-version: 2
-UUID: ac40e40a-7fbf-47e1-90a7-c1de12a5b013
+UUID: 2fcff1c7-6cef-40bf-9072-468ceec83032
Revision-number: 0
Prop-content-length: 56
@@ -9,7 +9,7 @@ Content-length: 56
K 8
svn:date
V 27
-2009-05-03T14:07:14.149596Z
+2011-02-25T14:33:01.299441Z
PROPS-END
Revision-number: 1
@@ -27,7 +27,7 @@ pmezard
K 8
svn:date
V 27
-2009-05-03T14:07:14.234026Z
+2011-02-25T14:33:01.321997Z
PROPS-END
Node-path: branches
@@ -72,7 +72,7 @@ pmezard
K 8
svn:date
V 27
-2009-05-03T14:07:15.135488Z
+2011-02-25T14:33:02.082464Z
PROPS-END
Node-path: externals/project1
@@ -134,7 +134,7 @@ pmezard
K 8
svn:date
V 27
-2009-05-03T14:07:16.180110Z
+2011-02-25T14:33:03.076026Z
PROPS-END
Node-path: trunk
@@ -179,19 +179,22 @@ pmezard
K 8
svn:date
V 27
-2009-05-03T14:07:17.092210Z
+2011-02-25T14:33:04.058124Z
PROPS-END
Node-path: trunk
Node-kind: dir
Node-action: change
-Prop-content-length: 111
-Content-length: 111
+Prop-content-length: 169
+Content-length: 169
K 13
svn:externals
-V 76
+V 133
+# A comment, then an empty line, then a blank line
+
^/externals/project1 deps/project1
+
-r2 ^/externals/project2@2 deps/project2
PROPS-END
@@ -212,7 +215,7 @@ pmezard
K 8
svn:date
V 27
-2009-05-03T14:07:18.165337Z
+2011-02-25T14:33:05.096545Z
PROPS-END
Node-path: trunk
@@ -272,7 +275,7 @@ pmezard
K 8
svn:date
V 27
-2009-05-03T14:07:21.092911Z
+2011-02-25T14:33:08.059874Z
PROPS-END
Node-path: branches/branch1
@@ -306,7 +309,7 @@ pmezard
K 8
svn:date
V 27
-2009-05-03T14:07:23.097507Z
+2011-02-25T14:33:10.059295Z
PROPS-END
Node-path: branches/branch2
@@ -344,7 +347,7 @@ pmezard
K 8
svn:date
V 27
-2009-05-03T14:07:24.086967Z
+2011-02-25T14:33:11.058317Z
PROPS-END
Node-path: trunk/subdir
@@ -366,7 +369,7 @@ pmezard
K 8
svn:date
V 27
-2009-05-03T14:07:25.093557Z
+2011-02-25T14:33:12.058270Z
PROPS-END
Node-path: trunk/subdir2
@@ -393,7 +396,7 @@ pmezard
K 8
svn:date
V 27
-2009-05-03T14:07:27.088306Z
+2011-02-25T14:33:14.058780Z
PROPS-END
Node-path: externals/project2
@@ -415,7 +418,7 @@ pmezard
K 8
svn:date
V 27
-2009-05-03T14:07:28.065953Z
+2011-02-25T14:33:15.045928Z
PROPS-END
Node-path: trunk/a
diff --git a/tests/fixtures/mergeexternals.sh b/tests/fixtures/mergeexternals.sh
new file mode 100644
index 0000000..af413ab
--- /dev/null
+++ b/tests/fixtures/mergeexternals.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+#
+# Generate mergeexternals.svndump
+#
+
+mkdir temp
+cd temp
+
+mkdir project-orig
+cd project-orig
+mkdir trunk
+mkdir branches
+cd ..
+
+svnadmin create testrepo
+svnurl=file://`pwd`/testrepo
+svn import project-orig $svnurl -m "init project"
+
+svn co $svnurl project
+cd project/trunk
+mkdir d1
+echo a > d1/a
+mkdir d2
+echo b > d2/b
+mkdir -p common/ext
+echo c > common/ext/c
+svn add d1 d2 common
+svn ci -m addfiles
+svn up
+svn propset svn:externals '^/trunk/common/ext ext' d1
+svn propset svn:externals '^/trunk/common/ext ext' d2
+svn ci -m addexternals
+cd ..
+svn up
+svn cp trunk branches/branch
+cd branches
+svn ci -m addbranch
+cd branch
+mkdir d3
+echo d > d3/d
+svn add d3
+svn propset svn:externals '^/trunk/common/ext ext3' d3
+svn ci -m touchbranch
+cd ../../trunk
+svn merge '^/branches/branch'
+svn up
+svn ci -m 'merge'
+cd ../..
+
+svnadmin dump testrepo > ../mergeexternals.svndump
diff --git a/tests/fixtures/mergeexternals.svndump b/tests/fixtures/mergeexternals.svndump
new file mode 100644
index 0000000..2aee90a
--- /dev/null
+++ b/tests/fixtures/mergeexternals.svndump
@@ -0,0 +1,306 @@
+SVN-fs-dump-format-version: 2
+
+UUID: b402ceb9-6185-4dce-93a1-92de515c5c8b
+
+Revision-number: 0
+Prop-content-length: 56
+Content-length: 56
+
+K 8
+svn:date
+V 27
+2011-02-25T13:54:38.654361Z
+PROPS-END
+
+Revision-number: 1
+Prop-content-length: 114
+Content-length: 114
+
+K 7
+svn:log
+V 12
+init project
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2011-02-25T13:54:38.675100Z
+PROPS-END
+
+Node-path: branches
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Revision-number: 2
+Prop-content-length: 109
+Content-length: 109
+
+K 7
+svn:log
+V 8
+addfiles
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2011-02-25T13:54:39.078800Z
+PROPS-END
+
+Node-path: trunk/common
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk/common/ext
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk/common/ext/c
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 2cd6ee2c70b0bde53fbe6cac3c8b8bb1
+Text-content-sha1: 2b66fd261ee5c6cfc8de7fa466bab600bcfe4f69
+Content-length: 12
+
+PROPS-END
+c
+
+
+Node-path: trunk/d1
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk/d1/a
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 60b725f10c9c85c70d97880dfe8191b3
+Text-content-sha1: 3f786850e387550fdab836ed7e6dc881de23001b
+Content-length: 12
+
+PROPS-END
+a
+
+
+Node-path: trunk/d2
+Node-kind: dir
+Node-action: add
+Prop-content-length: 10
+Content-length: 10
+
+PROPS-END
+
+
+Node-path: trunk/d2/b
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: 3b5d5c3712955042212316173ccf37be
+Text-content-sha1: 89e6c98d92887913cadf06b2adb97f26cde4849b
+Content-length: 12
+
+PROPS-END
+b
+
+
+Revision-number: 3
+Prop-content-length: 114
+Content-length: 114
+
+K 7
+svn:log
+V 12
+addexternals
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2011-02-25T13:54:41.071346Z
+PROPS-END
+
+Node-path: trunk/d1
+Node-kind: dir
+Node-action: change
+Prop-content-length: 58
+Content-length: 58
+
+K 13
+svn:externals
+V 23
+^/trunk/common/ext ext
+
+PROPS-END
+
+
+Node-path: trunk/d2
+Node-kind: dir
+Node-action: change
+Prop-content-length: 58
+Content-length: 58
+
+K 13
+svn:externals
+V 23
+^/trunk/common/ext ext
+
+PROPS-END
+
+
+Revision-number: 4
+Prop-content-length: 110
+Content-length: 110
+
+K 7
+svn:log
+V 9
+addbranch
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2011-02-25T13:54:44.043149Z
+PROPS-END
+
+Node-path: branches/branch
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 3
+Node-copyfrom-path: trunk
+
+
+Revision-number: 5
+Prop-content-length: 113
+Content-length: 113
+
+K 7
+svn:log
+V 11
+touchbranch
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2011-02-25T13:54:45.080319Z
+PROPS-END
+
+Node-path: branches/branch/d3
+Node-kind: dir
+Node-action: add
+Prop-content-length: 59
+Content-length: 59
+
+K 13
+svn:externals
+V 24
+^/trunk/common/ext ext3
+
+PROPS-END
+
+
+Node-path: branches/branch/d3/d
+Node-kind: file
+Node-action: add
+Prop-content-length: 10
+Text-content-length: 2
+Text-content-md5: e29311f6f1bf1af907f9ef9f44b8328b
+Text-content-sha1: e983f374794de9c64e3d1c1de1d490c0756eeeff
+Content-length: 12
+
+PROPS-END
+d
+
+
+Revision-number: 6
+Prop-content-length: 106
+Content-length: 106
+
+K 7
+svn:log
+V 5
+merge
+K 10
+svn:author
+V 7
+pmezard
+K 8
+svn:date
+V 27
+2011-02-25T13:54:48.049151Z
+PROPS-END
+
+Node-path: trunk
+Node-kind: dir
+Node-action: change
+Prop-content-length: 55
+Content-length: 55
+
+K 13
+svn:mergeinfo
+V 20
+/branches/branch:4-5
+PROPS-END
+
+
+Node-path: trunk/d3
+Node-kind: dir
+Node-action: add
+Node-copyfrom-rev: 5
+Node-copyfrom-path: branches/branch/d3
+Prop-content-length: 59
+Content-length: 59
+
+K 13
+svn:externals
+V 24
+^/trunk/common/ext ext3
+
+PROPS-END
+
+
diff --git a/tests/fixtures/rsvn.py b/tests/fixtures/rsvn.py
index d92c1e8..b48a5d8 100755
--- a/tests/fixtures/rsvn.py
+++ b/tests/fixtures/rsvn.py
@@ -169,7 +169,7 @@ def rsvn(pool):
sys.stderr.write(str(e) + '\n\n')
usage()
sys.exit(1)
-
+
for opt, value in opts:
if opt == '--version':
print '%s version %s' % (os.path.basename(sys.argv[0]), VERSION)
@@ -181,75 +181,75 @@ def rsvn(pool):
username = value
elif opt == '--message':
log_msg = value
-
+
if log_msg == None:
usage('Missing --message argument')
sys.exit(1)
-
+
if len(args) != 1:
usage('Missing repository path argument')
sys.exit(1)
-
+
repos_path = args[0]
print 'Accessing repository at [%s]' % repos_path
repository = Repository(repos_path, pool)
sub = repository.subpool()
-
+
try:
txn = repository.begin(username, log_msg)
-
+
# Read commands from STDIN
lineno = 0
for line in sys.stdin:
lineno += 1
-
+
core.svn_pool_clear(sub)
try:
if COMMENT_RE.search(line):
continue
-
+
match = RCOPY_RE.search(line)
if match:
src = match.group(1)
dest = match.group(2)
txn.copy(src, dest, sub)
continue
-
+
match = RMOVE_RE.search(line)
if match:
src = match.group(1)
dest = match.group(2)
txn.move(src, dest, sub)
continue
-
+
match = RMKDIR_RE.search(line)
if match:
entry = match.group(1)
txn.mkdir(entry, sub)
continue
-
+
match = RDELETE_RE.search(line)
if match:
entry = match.group(1)
txn.delete(entry, sub)
continue
-
+
raise NameError, ('Unknown command [%s] on line %d' %
(line, lineno))
-
+
except:
- sys.stderr.write(('Exception occured while processing line %d:\n' %
+ sys.stderr.write(('Exception occured while processing line %d:\n' %
lineno))
etype, value, tb = sys.exc_info()
traceback.print_exception(etype, value, tb, None, sys.stderr)
sys.stderr.write('\n')
txn.rollback()
sys.exit(1)
-
+
new_rev = txn.commit()
print '\nCommitted revision %d.' % new_rev
-
+
finally:
print '\nRepository closed.'
diff --git a/tests/run.py b/tests/run.py
index ce4ad34..98cf0a6 100644
--- a/tests/run.py
+++ b/tests/run.py
@@ -93,23 +93,23 @@ if __name__ == '__main__':
import tempfile
sys.stdout = tempfile.TemporaryFile()
- all = tests()
+ all_tests = tests()
args = [i.split('.py')[0].replace('-', '_') for i in args]
if not args:
check = lambda x: options.comprehensive or not comprehensive(x)
- mods = [m for (n, m) in sorted(all.iteritems()) if check(m)]
+ mods = [m for (n, m) in sorted(all_tests.iteritems()) if check(m)]
suite = [m.suite() for m in mods]
else:
suite = []
for arg in args:
if arg == 'test_util':
continue
- elif arg not in all:
+ elif arg not in all_tests:
print >> sys.stderr, 'test module %s not available' % arg
else:
- suite.append(all[arg].suite())
+ suite.append(all_tests[arg].suite())
runner = unittest.TextTestRunner(**testargs)
result = runner.run(unittest.TestSuite(suite))
diff --git a/tests/test_binaryfiles.py b/tests/test_binaryfiles.py
index dcdaa6d..7be3747 100644
--- a/tests/test_binaryfiles.py
+++ b/tests/test_binaryfiles.py
@@ -11,6 +11,6 @@ class TestFetchBinaryFiles(test_util.TestBase):
self.test_binaryfiles(True)
def suite():
- all = [unittest.TestLoader().loadTestsFromTestCase(TestFetchBinaryFiles),
+ all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestFetchBinaryFiles),
]
- return unittest.TestSuite(all)
+ return unittest.TestSuite(all_tests)
diff --git a/tests/test_diff.py b/tests/test_diff.py
index 43d40ed..464ae76 100644
--- a/tests/test_diff.py
+++ b/tests/test_diff.py
@@ -33,11 +33,11 @@ class DiffTests(test_util.TestBase):
])
u = ui.ui()
u.pushbuffer()
- wrappers.diff(lambda x,y,z: None, u, self.repo, svn=True)
+ wrappers.diff(lambda x, y, z: None, u, self.repo, svn=True)
self.assertEqual(u.popbuffer(), expected_diff_output)
def suite():
- all = [unittest.TestLoader().loadTestsFromTestCase(DiffTests),
+ all_tests = [unittest.TestLoader().loadTestsFromTestCase(DiffTests),
]
- return unittest.TestSuite(all)
+ return unittest.TestSuite(all_tests)
diff --git a/tests/test_externals.py b/tests/test_externals.py
index 9fcab76..2927b11 100644
--- a/tests/test_externals.py
+++ b/tests/test_externals.py
@@ -10,7 +10,7 @@ try:
subrepo.svnsubrepo
hgutil.checknlink
except (ImportError, AttributeError), e:
- print >>sys.stderr, 'test_externals: skipping .hgsub tests'
+ print >> sys.stderr, 'test_externals: skipping .hgsub tests'
subrepo = None
from hgsubversion import svnexternals
@@ -80,12 +80,16 @@ class TestFetchExternals(test_util.TestBase):
ref0 = """[.]
^/externals/project1 deps/project1
"""
- self.assertEqual(ref0, repo[0]['.hgsvnexternals'].data())
- ref1 = """[.]
+ self.assertMultiLineEqual(ref0, repo[0]['.hgsvnexternals'].data())
+ ref1 = """\
+[.]
+ # A comment, then an empty line, then a blank line
+
^/externals/project1 deps/project1
+
-r2 ^/externals/project2@2 deps/project2
"""
- self.assertEqual(ref1, repo[1]['.hgsvnexternals'].data())
+ self.assertMultiLineEqual(ref1, repo[1]['.hgsvnexternals'].data())
ref2 = """[.]
-r2 ^/externals/project2@2 deps/project2
@@ -149,6 +153,8 @@ class TestFetchExternals(test_util.TestBase):
checkdeps(['subdir/deps/project1'], ['deps/project2'], repo, 4)
def test_hgsub(self, stupid=False):
+ if subrepo is None:
+ return
repo = self._load_fixture_and_fetch('externals.svndump',
externals='subrepos',
stupid=stupid)
@@ -179,7 +185,7 @@ HEAD subdir/deps/project1
HEAD subdir2/deps/project1
""", repo[2]['.hgsubstate'].data())
- self.assertEqual("""\
+ self.assertMultiLineEqual("""\
deps/project2 = [hgsubversion] :-r{REV} ^/externals/project2@2 deps/project2
subdir/deps/project1 = [hgsubversion] subdir:^/externals/project1 deps/project1
""", repo[3]['.hgsub'].data())
@@ -254,6 +260,22 @@ deps/project2 = [hgsubversion] :-r{REV} ^/externals/project2@2 deps/project2
repo.wwrite('subdir/deps/project1/a', 'foobar', '')
commands.update(ui, repo, node='4', clean=True)
+ def test_mergeexternals(self, stupid=False):
+ if subrepo is None:
+ return
+ repo = self._load_fixture_and_fetch('mergeexternals.svndump',
+ externals='subrepos',
+ stupid=stupid)
+ # Check merged directories externals are fine
+ self.assertEqual("""\
+d1/ext = [hgsubversion] d1:^/trunk/common/ext ext
+d2/ext = [hgsubversion] d2:^/trunk/common/ext ext
+d3/ext3 = [hgsubversion] d3:^/trunk/common/ext ext3
+""", repo['tip']['.hgsub'].data())
+
+ def test_mergeexternals_stupid(self):
+ self.test_mergeexternals(True)
+
class TestPushExternals(test_util.TestBase):
def test_push_externals(self, stupid=False):
test_util.load_fixture_and_fetch('pushexternals.svndump',
@@ -336,7 +358,7 @@ HEAD subdir2/deps/project2
self.assertchanges(changes, self.repo['tip'])
# Check .hgsub and .hgsubstate were not pushed
- self.assertEqual(['dir', 'subdir1', 'subdir1/a','subdir2',
+ self.assertEqual(['dir', 'subdir1', 'subdir1/a', 'subdir2',
'subdir2/a'], self.svnls('trunk'))
# Remove all references from one directory, add a new one
@@ -386,7 +408,7 @@ HEAD subdir1/deps/project1
self.assertchanges(changes, self.repo['tip'])
def suite():
- all = [unittest.TestLoader().loadTestsFromTestCase(TestFetchExternals),
+ all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestFetchExternals),
unittest.TestLoader().loadTestsFromTestCase(TestPushExternals),
]
- return unittest.TestSuite(all)
+ return unittest.TestSuite(all_tests)
diff --git a/tests/test_fetch_branches.py b/tests/test_fetch_branches.py
index 5c00354..a9645f0 100644
--- a/tests/test_fetch_branches.py
+++ b/tests/test_fetch_branches.py
@@ -16,14 +16,19 @@ class TestFetchBranches(test_util.TestBase):
def _load_fixture_and_fetch_with_anchor(self, fixture_name, anchor):
test_util.load_svndump_fixture(self.repo_path, fixture_name)
source = '%s#%s' % (test_util.fileurl(self.repo_path), anchor)
- repo = hg.clone(self.ui(), source=source, dest=self.wc_path)
+ test_util.hgclone(self.ui(), source, self.wc_path)
return hg.repository(self.ui(), self.wc_path)
- def openbranches(self, repo):
+ def branches(self, repo):
hctxs = [repo[hn] for hn in repo.heads()]
- branches = set(ctx.branch() for ctx in hctxs if
- ctx.extra().get('close', None) != '1')
- return sorted(branches)
+ openbranches = set(ctx.branch() for ctx in hctxs if
+ ctx.extra().get('close', None) != '1')
+ closedbranches = set(ctx.branch() for ctx in hctxs if
+ ctx.extra().get('close', None) == '1')
+ return sorted(openbranches), sorted(closedbranches)
+
+ def openbranches(self, repo):
+ return self.branches(repo)[0]
def test_rename_branch_parent(self, stupid=False):
repo = self._load_fixture_and_fetch('rename_branch_parent_dir.svndump', stupid)
@@ -58,10 +63,10 @@ class TestFetchBranches(test_util.TestBase):
def test_renamed_branch_to_trunk(self, stupid=False):
repo = self._load_fixture_and_fetch('branch_rename_to_trunk.svndump',
stupid)
- self.assertEqual(node.hex(repo['default'].node()),
- '14d252aef315857df241dd3fa4bc7833b09bd2f5')
self.assertEqual(repo['default'].parents()[0].branch(), 'dev_branch')
+ self.assert_('iota' in repo['default'])
self.assertEqual(repo['old_trunk'].parents()[0].branch(), 'default')
+ self.assert_('iota' not in repo['old_trunk'])
expected = ['default', 'old_trunk']
self.assertEqual(self.openbranches(repo), expected)
@@ -127,8 +132,10 @@ class TestFetchBranches(test_util.TestBase):
def test_branch_delete_parent_dir(self, stupid=False):
repo = self._load_fixture_and_fetch('branch_delete_parent_dir.svndump',
stupid)
- self.assertEqual(node.hex(repo['tip'].node()),
- '4108a81a82c7925d5551091165dc54c41b06a8a8')
+ openb, closedb = self.branches(repo)
+ self.assertEqual(openb, [])
+ self.assertEqual(closedb, ['dev_branch'])
+ self.assertEqual(list(repo['dev_branch']), ['foo'])
def test_replace_branch_with_branch(self, stupid=False):
repo = self._load_fixture_and_fetch('replace_branch_with_branch.svndump',
@@ -156,6 +163,6 @@ class TestFetchBranches(test_util.TestBase):
self.test_replace_branch_with_branch(True)
def suite():
- all = [unittest.TestLoader().loadTestsFromTestCase(TestFetchBranches),
+ all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestFetchBranches),
]
- return unittest.TestSuite(all)
+ return unittest.TestSuite(all_tests)
diff --git a/tests/test_fetch_command.py b/tests/test_fetch_command.py
index 02db7e1..f86416c 100644
--- a/tests/test_fetch_command.py
+++ b/tests/test_fetch_command.py
@@ -165,7 +165,7 @@ class TestBasicRepoLayout(test_util.TestBase):
commands.clone(ui, repo_url + subdir, wc_path)
commands.clone(ui, repo_url + quoted_subdir, wc2_path)
- repo = hg.repository(ui, wc_path)
+ repo = hg.repository(ui, wc_path)
repo2 = hg.repository(ui, wc2_path)
self.assertEqual(repo['tip'].extra()['convert_revision'],
@@ -224,7 +224,7 @@ class TestStupidPull(test_util.TestBase):
'1a6c3f30911d57abb67c257ec0df3e7bc44786f7')
def suite():
- all = [unittest.TestLoader().loadTestsFromTestCase(TestBasicRepoLayout),
+ all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestBasicRepoLayout),
unittest.TestLoader().loadTestsFromTestCase(TestStupidPull),
]
- return unittest.TestSuite(all)
+ return unittest.TestSuite(all_tests)
diff --git a/tests/test_fetch_exec.py b/tests/test_fetch_exec.py
index 2b2bec6..4742d27 100644
--- a/tests/test_fetch_exec.py
+++ b/tests/test_fetch_exec.py
@@ -33,6 +33,6 @@ class TestFetchExec(test_util.TestBase):
self.test_empty_prop_val_executable(True)
def suite():
- all = [unittest.TestLoader().loadTestsFromTestCase(TestFetchExec),
+ all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestFetchExec),
]
- return unittest.TestSuite(all)
+ return unittest.TestSuite(all_tests)
diff --git a/tests/test_fetch_mappings.py b/tests/test_fetch_mappings.py
index 2eba177..83149ef 100644
--- a/tests/test_fetch_mappings.py
+++ b/tests/test_fetch_mappings.py
@@ -26,7 +26,7 @@ class MapTests(test_util.TestBase):
@property
def branchmap(self):
return os.path.join(self.tmpdir, 'branchmap')
-
+
@property
def tagmap(self):
return os.path.join(self.tmpdir, 'tagmap')
@@ -96,8 +96,8 @@ class MapTests(test_util.TestBase):
test = maps.AuthorMap(self.ui(), self.authors)
fromself = set(test)
test.load(orig)
- all = set(test)
- self.assertEqual(fromself.symmetric_difference(all), set())
+ all_tests = set(test)
+ self.assertEqual(fromself.symmetric_difference(all_tests), set())
def test_file_map(self, stupid=False):
test_util.load_svndump_fixture(self.repo_path, 'replace_trunk_with_branch.svndump')
@@ -112,7 +112,8 @@ class MapTests(test_util.TestBase):
self.assertEqual(node.hex(self.repo['default'].node()), 'e524296152246b3837fe9503c83b727075835155')
def test_file_map_stupid(self):
- self.test_file_map(True)
+ # TODO: re-enable test if we ever reinstate this feature
+ self.assertRaises(hgutil.Abort, self.test_file_map, True)
def test_file_map_exclude(self, stupid=False):
test_util.load_svndump_fixture(self.repo_path, 'replace_trunk_with_branch.svndump')
@@ -127,7 +128,8 @@ class MapTests(test_util.TestBase):
self.assertEqual(node.hex(self.repo['default'].node()), 'b37a3c0297b71f989064d9b545b5a478bbed7cc1')
def test_file_map_exclude_stupid(self):
- self.test_file_map_exclude(True)
+ # TODO: re-enable test if we ever reinstate this feature
+ self.assertRaises(hgutil.Abort, self.test_file_map_exclude, True)
def test_branchmap(self, stupid=False):
test_util.load_svndump_fixture(self.repo_path, 'branchmap.svndump')
@@ -220,8 +222,8 @@ class MapTests(test_util.TestBase):
# clone & rebuild
ui = self.ui(stupid)
- src, dest = hg.clone(ui, self.wc_path, self.wc_path + '_clone',
- update=False)
+ src, dest = test_util.hgclone(ui, self.wc_path, self.wc_path + '_clone',
+ update=False)
svncommands.rebuildmeta(ui, dest,
args=[test_util.fileurl(self.repo_path)])
diff --git a/tests/test_fetch_renames.py b/tests/test_fetch_renames.py
index c15ad92..64b69d3 100644
--- a/tests/test_fetch_renames.py
+++ b/tests/test_fetch_renames.py
@@ -75,6 +75,6 @@ class TestFetchRenames(test_util.TestBase):
self._test_case(True)
def suite():
- all = [unittest.TestLoader().loadTestsFromTestCase(TestFetchRenames),
+ all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestFetchRenames),
]
- return unittest.TestSuite(all)
+ return unittest.TestSuite(all_tests)
diff --git a/tests/test_fetch_symlinks.py b/tests/test_fetch_symlinks.py
index 8f6504d..ecb2522 100644
--- a/tests/test_fetch_symlinks.py
+++ b/tests/test_fetch_symlinks.py
@@ -39,7 +39,7 @@ class TestFetchSymlinks(test_util.TestBase):
'linka4': 'link to this',
},
}
-
+
for rev in repo:
ctx = repo[rev]
for f in ctx.manifest():
@@ -53,6 +53,6 @@ class TestFetchSymlinks(test_util.TestBase):
self.test_symlinks(True)
def suite():
- all = [unittest.TestLoader().loadTestsFromTestCase(TestFetchSymlinks),
+ all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestFetchSymlinks),
]
- return unittest.TestSuite(all)
+ return unittest.TestSuite(all_tests)
diff --git a/tests/test_fetch_truncated.py b/tests/test_fetch_truncated.py
index 0f7d21d..9cb7300 100644
--- a/tests/test_fetch_truncated.py
+++ b/tests/test_fetch_truncated.py
@@ -31,6 +31,6 @@ class TestFetchTruncatedHistory(test_util.TestBase):
self.test_truncated_history(True)
def suite():
- all = [unittest.TestLoader().loadTestsFromTestCase(TestFetchTruncatedHistory),
+ all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestFetchTruncatedHistory),
]
- return unittest.TestSuite(all)
+ return unittest.TestSuite(all_tests)
diff --git a/tests/test_pull.py b/tests/test_pull.py
index fb3a4f5..b0f61b2 100644
--- a/tests/test_pull.py
+++ b/tests/test_pull.py
@@ -2,6 +2,7 @@ import test_util
import os.path
import subprocess
+from mercurial import node
from mercurial import ui
from mercurial import util as hgutil
from mercurial import commands
@@ -28,7 +29,7 @@ class TestPull(test_util.TestBase):
commands.pull(self.repo.ui, repo)
self.assertEqual(state, repo.parents())
self.assertTrue('tip' not in repo[None].tags())
-
+
def test_onerevision_doupdate(self):
repo = self._load_fixture_and_fetch('single_rev.svndump')
state = repo.parents()
@@ -42,12 +43,21 @@ class TestPull(test_util.TestBase):
self.commitchanges((('alpha', 'alpha', 'Changed another way'),))
state = repo.parents()
self._add_svn_rev({'trunk/alpha': 'Changed one way'})
- self.assertRaises(hgutil.Abort, commands.pull,
- self.repo.ui, repo, update=True)
+ try:
+ commands.pull(self.repo.ui, repo, update=True)
+ except hgutil.Abort:
+ # hg < 1.9 raised when crossing branches
+ pass
self.assertEqual(state, repo.parents())
self.assertTrue('tip' not in repo[None].tags())
self.assertEqual(len(repo.heads()), 2)
+ def test_tag_repull_doesnt_happen(self):
+ repo = self._load_fixture_and_fetch('branchtagcollision.svndump')
+ oldheads = map(node.hex, repo.heads())
+ commands.pull(repo.ui, repo)
+ self.assertEqual(oldheads, map(node.hex, repo.heads()))
+
def suite():
import unittest, sys
return unittest.findTestCases(sys.modules[__name__])
diff --git a/tests/test_push_command.py b/tests/test_push_command.py
index 60209c0..0f078b4 100644
--- a/tests/test_push_command.py
+++ b/tests/test_push_command.py
@@ -43,7 +43,7 @@ class PushTests(test_util.TestBase):
file_callback,
'an_author',
'2008-10-07 20:59:48 -0500',
- {'branch': 'default',})
+ {'branch': 'default', })
new_hash = repo.commitctx(ctx)
hg.update(repo, repo['tip'].node())
old_tip = repo['tip'].node()
@@ -64,7 +64,7 @@ class PushTests(test_util.TestBase):
file_callback,
'an_author',
'2008-10-07 20:59:48 -0500',
- {'branch': 'default',})
+ {'branch': 'default', })
new_hash = repo.commitctx(ctx)
hg.update(repo, repo['tip'].node())
# Touch an existing file
@@ -116,7 +116,7 @@ class PushTests(test_util.TestBase):
filectxfn=file_callback,
user='an_author',
date='2008-10-07 20:59:48 -0500',
- extra={'branch': 'default',})
+ extra={'branch': 'default', })
new_hash = repo.commitctx(ctx)
if not commit:
return # some tests use this test as an extended setup.
@@ -161,7 +161,7 @@ class PushTests(test_util.TestBase):
file_callback,
'an_author',
'2008-10-07 20:59:48 -0500',
- {'branch': 'default',})
+ {'branch': 'default', })
new_hash = repo.commitctx(ctx)
if not commit:
return # some tests use this test as an extended setup.
@@ -183,7 +183,7 @@ class PushTests(test_util.TestBase):
copied=False)
oldtiphash = self.repo['default'].node()
ctx = context.memctx(self.repo,
- (self.repo[0].node(), revlog.nullid, ),
+ (self.repo[0].node(), revlog.nullid,),
'automated test',
['gamma', ],
filectxfn,
@@ -229,7 +229,7 @@ class PushTests(test_util.TestBase):
file_callback,
'an_author',
'2008-10-07 20:59:48 -0500',
- {'branch': 'default',})
+ {'branch': 'default', })
new_hash = repo.commitctx(ctx)
hg.update(repo, repo['tip'].node())
self.pushrevisions()
@@ -264,7 +264,7 @@ class PushTests(test_util.TestBase):
file_callback,
'an_author',
'2008-10-07 20:59:48 -0500',
- {'branch': 'the_branch',})
+ {'branch': 'the_branch', })
new_hash = repo.commitctx(ctx)
hg.update(repo, repo['tip'].node())
if push:
@@ -278,20 +278,20 @@ class PushTests(test_util.TestBase):
self.test_push_to_branch(push=False)
wc2path = self.wc_path + '_clone'
u = self.repo.ui
- hg.clone(self.repo.ui, self.wc_path, wc2path, update=False)
+ test_util.hgclone(self.repo.ui, self.wc_path, wc2path, update=False)
res = self.pushrevisions()
self.assertEqual(0, res)
oldf = open(os.path.join(self.wc_path, '.hg', 'hgrc'))
hgrc = oldf.read()
oldf.close()
shutil.rmtree(self.wc_path)
- hg.clone(u, wc2path, self.wc_path, update=False)
+ test_util.hgclone(u, wc2path, self.wc_path, update=False)
oldf = open(os.path.join(self.wc_path, '.hg', 'hgrc'), 'w')
oldf.write(hgrc)
oldf.close()
# do a commit here
- self.commitchanges([('foobaz', 'foobaz', 'This file is added on default.', ),
+ self.commitchanges([('foobaz', 'foobaz', 'This file is added on default.',),
],
parent='default',
message='commit to default')
@@ -469,13 +469,13 @@ class PushTests(test_util.TestBase):
def test_push_outdated_base_text(self):
self.test_push_two_revs()
- changes = [('adding_file', 'adding_file', 'different_content', ),
+ changes = [('adding_file', 'adding_file', 'different_content',),
]
par = self.repo['tip'].rev()
self.commitchanges(changes, parent=par)
self.pushrevisions()
changes = [('adding_file', 'adding_file',
- 'even_more different_content', ),
+ 'even_more different_content',),
]
self.commitchanges(changes, parent=par)
try:
@@ -490,12 +490,12 @@ class PushTests(test_util.TestBase):
def suite():
test_classes = [PushTests, ]
- tests = []
+ all_tests = []
# This is the quickest hack I could come up with to load all the tests from
# both classes. Would love a patch that simplifies this without adding
# dependencies.
for tc in test_classes:
for attr in dir(tc):
if attr.startswith('test_'):
- tests.append(tc(attr))
- return unittest.TestSuite(tests)
+ all_tests.append(tc(attr))
+ return unittest.TestSuite(all_tests)
diff --git a/tests/test_push_dirs.py b/tests/test_push_dirs.py
index 7d828fd..3b43130 100644
--- a/tests/test_push_dirs.py
+++ b/tests/test_push_dirs.py
@@ -48,7 +48,7 @@ class TestPushDirectories(test_util.TestBase):
def test_push_new_dir_project_root_not_repo_root(self):
self._load_fixture_and_fetch('fetch_missing_files_subdir.svndump',
subdir='foo')
- changes = [('magic_new/a', 'magic_new/a', 'ohai', ),
+ changes = [('magic_new/a', 'magic_new/a', 'ohai',),
]
self.commitchanges(changes)
self.pushrevisions()
@@ -64,20 +64,21 @@ class TestPushDirectories(test_util.TestBase):
def test_push_new_file_existing_dir_root_not_repo_root(self):
self._load_fixture_and_fetch('empty_dir_in_trunk_not_repo_root.svndump',
subdir='project')
- changes = [('narf/a', 'narf/a', 'ohai', ),
+ changes = [('narf/a', 'narf/a', 'ohai',),
]
self.commitchanges(changes)
self.assertEqual(self.svnls('project/trunk'), ['a',
- 'narf',])
+ 'narf',
+ ])
self.pushrevisions()
self.assertEqual(self.svnls('project/trunk'), ['a',
'narf',
'narf/a'])
- changes = [('narf/a', None, None, ),
+ changes = [('narf/a', None, None,),
]
self.commitchanges(changes)
self.pushrevisions()
- self.assertEqual(self.svnls('project/trunk'), ['a' ,])
+ self.assertEqual(self.svnls('project/trunk'), ['a'])
def test_push_single_dir_change_in_subdir(self):
# Tests simple pushing from default branch to a single dir repo
@@ -104,6 +105,6 @@ class TestPushDirectories(test_util.TestBase):
'tag_r3/new'])
def suite():
- all = [unittest.TestLoader().loadTestsFromTestCase(TestPushDirectories),
+ all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestPushDirectories),
]
- return unittest.TestSuite(all)
+ return unittest.TestSuite(all_tests)
diff --git a/tests/test_push_eol.py b/tests/test_push_eol.py
index 9ef754a..fe89529 100644
--- a/tests/test_push_eol.py
+++ b/tests/test_push_eol.py
@@ -37,6 +37,6 @@ class TestPushEol(test_util.TestBase):
self._test_push_dirs(True)
def suite():
- all = [unittest.TestLoader().loadTestsFromTestCase(TestPushEol),
+ all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestPushEol),
]
- return unittest.TestSuite(all)
+ return unittest.TestSuite(all_tests)
diff --git a/tests/test_push_renames.py b/tests/test_push_renames.py
index b38df37..ea7acff 100644
--- a/tests/test_push_renames.py
+++ b/tests/test_push_renames.py
@@ -79,9 +79,9 @@ class TestPushRenames(test_util.TestBase):
('geek/delta', 'geek/delta', 'content',),
('geek/gamma', 'geek/gamma', 'content',),
('geek/later/pi', 'geek/later/pi', 'content geek/later/pi',),
- ('geek/later/rho', 'geek/later/rho', 'content geek/later/rho', ),
- ('geek/other/blah', 'geek/other/blah', 'content geek/other/blah', ),
- ('geek/other/another/layer', 'geek/other/another/layer', 'content deep file', ),
+ ('geek/later/rho', 'geek/later/rho', 'content geek/later/rho',),
+ ('geek/other/blah', 'geek/other/blah', 'content geek/other/blah',),
+ ('geek/other/another/layer', 'geek/other/another/layer', 'content deep file',),
]
self.commitchanges(changes)
@@ -90,35 +90,35 @@ class TestPushRenames(test_util.TestBase):
changes = [
# rename (copy + remove) all of geek to greek
- ('geek/alpha', 'greek/alpha', None, ),
- ('geek/beta', 'greek/beta', None, ),
- ('geek/delta', 'greek/delta', None, ),
- ('geek/gamma', 'greek/gamma', None, ),
- ('geek/later/pi', 'greek/later/pi', None, ),
- ('geek/later/rho', 'greek/later/rho', None, ),
- ('geek/other/blah', 'greek/other/blah', None, ),
- ('geek/other/another/layer', 'greek/other/another/layer', None, ),
+ ('geek/alpha', 'greek/alpha', None,),
+ ('geek/beta', 'greek/beta', None,),
+ ('geek/delta', 'greek/delta', None,),
+ ('geek/gamma', 'greek/gamma', None,),
+ ('geek/later/pi', 'greek/later/pi', None,),
+ ('geek/later/rho', 'greek/later/rho', None,),
+ ('geek/other/blah', 'greek/other/blah', None,),
+ ('geek/other/another/layer', 'greek/other/another/layer', None,),
- ('geek/alpha', None, None, ),
- ('geek/beta', None, None, ),
- ('geek/delta', None, None, ),
- ('geek/gamma', None, None, ),
- ('geek/later/pi', None, None, ),
- ('geek/later/rho', None, None, ),
- ('geek/other/blah', None, None, ),
- ('geek/other/another/layer', None, None, ),
+ ('geek/alpha', None, None,),
+ ('geek/beta', None, None,),
+ ('geek/delta', None, None,),
+ ('geek/gamma', None, None,),
+ ('geek/later/pi', None, None,),
+ ('geek/later/rho', None, None,),
+ ('geek/other/blah', None, None,),
+ ('geek/other/another/layer', None, None,),
]
self.commitchanges(changes)
self.pushrevisions()
# print '\n'.join(sorted(self.svnls('trunk')))
assert reduce(lambda x, y: x and y,
- ('geek' not in f for f in self.svnls('trunk'))),(
+ ('geek' not in f for f in self.svnls('trunk'))), (
'This failure means rename of an entire tree is broken.'
' There is a print on the preceding line commented out '
'that should help you.')
def suite():
- all = [unittest.TestLoader().loadTestsFromTestCase(TestPushRenames),
+ all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestPushRenames),
]
- return unittest.TestSuite(all)
+ return unittest.TestSuite(all_tests)
diff --git a/tests/test_rebuildmeta.py b/tests/test_rebuildmeta.py
index 5a38aad..7182dbb 100644
--- a/tests/test_rebuildmeta.py
+++ b/tests/test_rebuildmeta.py
@@ -12,6 +12,17 @@ from mercurial import ui
from hgsubversion import svncommands
from hgsubversion import svnmeta
+# These test repositories have harmless skew in rebuildmeta for the
+# last-pulled-rev because the last rev in svn causes absolutely no
+# changes in hg.
+expect_youngest_skew = [('file_mixed_with_branches.svndump', False, False),
+ ('file_mixed_with_branches.svndump', True, False),
+ ('unrelatedbranch.svndump', False, False),
+ ('unrelatedbranch.svndump', True, False),
+ ]
+
+
+
def _do_case(self, name, stupid, single):
subdir = test_util.subdir.get(name, '')
layout = 'auto'
@@ -21,7 +32,7 @@ def _do_case(self, name, stupid, single):
assert len(self.repo) > 0
wc2_path = self.wc_path + '_clone'
u = ui.ui()
- src, dest = hg.clone(u, self.wc_path, wc2_path, update=False)
+ src, dest = test_util.hgclone(u, self.wc_path, wc2_path, update=False)
# insert a wrapper that prevents calling changectx.children()
def failfn(orig, ctx):
@@ -44,12 +55,18 @@ def _do_case(self, name, stupid, single):
self.assertTrue(os.path.isdir(os.path.join(src.path, 'svn')),
'no .hg/svn directory in the destination!')
dest = hg.repository(u, os.path.dirname(dest.path))
- for tf in ('rev_map', 'uuid', 'tagmap', 'layout', 'subdir', ):
+ for tf in ('lastpulled', 'rev_map', 'uuid', 'tagmap', 'layout', 'subdir',):
+
stf = os.path.join(src.path, 'svn', tf)
self.assertTrue(os.path.isfile(stf), '%r is missing!' % stf)
dtf = os.path.join(dest.path, 'svn', tf)
self.assertTrue(os.path.isfile(dtf), '%r is missing!' % tf)
old, new = open(stf).read(), open(dtf).read()
+ if tf == 'lastpulled' and (name,
+ stupid, single) in expect_youngest_skew:
+ self.assertNotEqual(old, new,
+ 'rebuildmeta unexpected match on youngest rev!')
+ continue
self.assertMultiLineEqual(old, new)
self.assertEqual(src.branchtags(), dest.branchtags())
srcbi = pickle.load(open(os.path.join(src.path, 'svn', 'branch_info')))
@@ -96,10 +113,10 @@ for case in [f for f in os.listdir(test_util.FIXTURES) if f.endswith('.svndump')
name = bname + '_single'
attrs[name] = buildmethod(case, name, False, True)
-RebuildMetaTests = type('RebuildMetaTests', (test_util.TestBase, ), attrs)
+RebuildMetaTests = type('RebuildMetaTests', (test_util.TestBase,), attrs)
def suite():
- all = [unittest.TestLoader().loadTestsFromTestCase(RebuildMetaTests),
+ all_tests = [unittest.TestLoader().loadTestsFromTestCase(RebuildMetaTests),
]
- return unittest.TestSuite(all)
+ return unittest.TestSuite(all_tests)
diff --git a/tests/test_single_dir_clone.py b/tests/test_single_dir_clone.py
index 2def325..2e035a5 100644
--- a/tests/test_single_dir_clone.py
+++ b/tests/test_single_dir_clone.py
@@ -4,7 +4,6 @@ import errno
import shutil
import unittest
-from mercurial import dispatch
from mercurial import commands
from mercurial import context
from mercurial import hg
@@ -92,19 +91,32 @@ class TestSingleDir(test_util.TestBase):
islink=False,
isexec=False,
copied=False)
+ elif path == 'adding_binary':
+ return context.memfilectx(path=path,
+ data='\0binary',
+ islink=False,
+ isexec=False,
+ copied=False)
raise IOError(errno.EINVAL, 'Invalid operation: ' + path)
ctx = context.memctx(repo,
(repo['tip'].node(), node.nullid),
'automated test',
- ['adding_file'],
+ ['adding_file', 'adding_binary'],
file_callback,
'an_author',
'2009-10-19 18:49:30 -0500',
- {'branch': 'default',})
+ {'branch': 'default', })
repo.commitctx(ctx)
hg.update(repo, repo['tip'].node())
self.pushrevisions()
self.assertTrue('adding_file' in self.svnls(''))
+ self.assertEqual('application/octet-stream',
+ self.svnpropget('adding_binary', 'svn:mime-type'))
+ # Now add another commit and test mime-type being reset
+ changes = [('adding_binary', 'adding_binary', 'no longer binary')]
+ self.commitchanges(changes)
+ self.pushrevisions()
+ self.assertEqual('', self.svnpropget('adding_binary', 'svn:mime-type'))
def test_push_single_dir_at_subdir(self):
repo = self._load_fixture_and_fetch('branch_from_tag.svndump',
@@ -124,7 +136,7 @@ class TestSingleDir(test_util.TestBase):
filectxfn,
'an_author',
'2009-10-19 18:49:30 -0500',
- {'branch': 'localhacking',})
+ {'branch': 'localhacking', })
n = repo.commitctx(ctx)
self.assertEqual(self.repo['tip']['bogus'].data(),
'contents of bogus')
@@ -159,7 +171,7 @@ class TestSingleDir(test_util.TestBase):
file_callback,
'an_author',
'2009-10-19 18:49:30 -0500',
- {'branch': 'default',})
+ {'branch': 'default', })
repo.commitctx(ctx)
hg.update(repo, repo['tip'].node())
self.pushrevisions(expected_extra_back=1)
@@ -194,7 +206,7 @@ class TestSingleDir(test_util.TestBase):
file_callback(name),
'an_author',
'2009-10-19 18:49:30 -0500',
- {'branch': name,}))
+ {'branch': name, }))
parent = repo['tip'].node()
commit_to_branch('default', parent)
@@ -223,7 +235,7 @@ class TestSingleDir(test_util.TestBase):
if stupid:
cmd.append('--stupid')
cmd += [test_util.fileurl(self.repo_path), self.wc_path]
- dispatch.dispatch(cmd)
+ test_util.dispatch(cmd)
def file_callback(repo, memctx, path):
if path == 'adding_file':
@@ -240,7 +252,7 @@ class TestSingleDir(test_util.TestBase):
file_callback,
'an_author',
'2009-10-19 18:49:30 -0500',
- {'branch': 'default',})
+ {'branch': 'default', })
self.repo.commitctx(ctx)
hg.update(self.repo, self.repo['tip'].node())
self.pushrevisions()
@@ -254,5 +266,5 @@ class TestSingleDir(test_util.TestBase):
self.test_push_single_dir_renamed_branch(True)
def suite():
- all = [unittest.TestLoader().loadTestsFromTestCase(TestSingleDir)]
- return unittest.TestSuite(all)
+ all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestSingleDir)]
+ return unittest.TestSuite(all_tests)
diff --git a/tests/test_startrev.py b/tests/test_startrev.py
index 7e51fb9..026e5be 100644
--- a/tests/test_startrev.py
+++ b/tests/test_startrev.py
@@ -61,10 +61,10 @@ for case in [f for f in os.listdir(test_util.FIXTURES) if f.endswith('.svndump')
name = bname + '_stupid'
attrs[name] = buildmethod(case, name, subdir, True)
-StartRevTests = type('StartRevTests', (test_util.TestBase, ), attrs)
+StartRevTests = type('StartRevTests', (test_util.TestBase,), attrs)
def suite():
- all = [unittest.TestLoader().loadTestsFromTestCase(StartRevTests),
+ all_tests = [unittest.TestLoader().loadTestsFromTestCase(StartRevTests),
]
- return unittest.TestSuite(all)
+ return unittest.TestSuite(all_tests)
diff --git a/tests/test_svnwrap.py b/tests/test_svnwrap.py
index 5fe6aab..c5a5d2e 100644
--- a/tests/test_svnwrap.py
+++ b/tests/test_svnwrap.py
@@ -22,10 +22,10 @@ class TestBasicRepoLayout(unittest.TestCase):
def setUp(self):
self.tmpdir = tempfile.mkdtemp('svnwrap_test')
self.repo_path = '%s/testrepo' % self.tmpdir
- subprocess.call(['svnadmin', 'create', self.repo_path,])
+ subprocess.call(['svnadmin', 'create', self.repo_path, ])
inp = open(os.path.join(os.path.dirname(__file__), 'fixtures',
'project_root_at_repo_root.svndump'))
- proc = subprocess.call(['svnadmin', 'load', self.repo_path,],
+ proc = subprocess.call(['svnadmin', 'load', self.repo_path, ],
stdin=inp,
close_fds=test_util.canCloseFds,
stdout=subprocess.PIPE,
@@ -57,10 +57,10 @@ class TestRootAsSubdirOfRepo(TestBasicRepoLayout):
def setUp(self):
self.tmpdir = tempfile.mkdtemp('svnwrap_test')
self.repo_path = '%s/testrepo' % self.tmpdir
- subprocess.call(['svnadmin', 'create', self.repo_path,])
+ subprocess.call(['svnadmin', 'create', self.repo_path, ])
inp = open(os.path.join(os.path.dirname(__file__), 'fixtures',
'project_root_not_repo_root.svndump'))
- ret = subprocess.call(['svnadmin', 'load', self.repo_path,],
+ ret = subprocess.call(['svnadmin', 'load', self.repo_path, ],
stdin=inp,
close_fds=test_util.canCloseFds,
stdout=subprocess.PIPE,
@@ -71,6 +71,6 @@ class TestRootAsSubdirOfRepo(TestBasicRepoLayout):
))
def suite():
- all = [unittest.TestLoader().loadTestsFromTestCase(TestBasicRepoLayout),
+ all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestBasicRepoLayout),
unittest.TestLoader().loadTestsFromTestCase(TestRootAsSubdirOfRepo)]
- return unittest.TestSuite(all)
+ return unittest.TestSuite(all_tests)
diff --git a/tests/test_tags.py b/tests/test_tags.py
index 297591e..55cbb0c 100644
--- a/tests/test_tags.py
+++ b/tests/test_tags.py
@@ -115,7 +115,7 @@ rename a tag
"Note: this test failing may be because of a rebuildmeta failure.\n"
"You should check that before assuming issues with this test.\n")
wc2_path = self.wc_path + '2'
- src, dest = hg.clone(repo.ui, self.wc_path, wc2_path, update=False)
+ src, dest = test_util.hgclone(repo.ui, self.wc_path, wc2_path, update=False)
svncommands.rebuildmeta(repo.ui,
dest,
args=[test_util.fileurl(self.repo_path), ])
@@ -138,9 +138,9 @@ rename a tag
openheads = [h for h in heads if not repo[h].extra().get('close', False)]
closedheads = set(heads) - set(openheads)
self.assertEqual(len(openheads), 1)
- self.assertEqual(len(closedheads), headcount-1)
+ self.assertEqual(len(closedheads), headcount - 1)
closedheads = sorted(list(closedheads),
- cmp=lambda x,y: cmp(repo[x].rev(), repo[y].rev()))
+ cmp=lambda x, y: cmp(repo[x].rev(), repo[y].rev()))
# closeme has no open heads
for h in openheads:
diff --git a/tests/test_template_keywords.py b/tests/test_template_keywords.py
index 87449ba..be1b4a7 100644
--- a/tests/test_template_keywords.py
+++ b/tests/test_template_keywords.py
@@ -15,7 +15,7 @@ try:
from mercurial import revset
revset.methods
except ImportError:
- revset = None
+ revset = None
class CapturingUI(ui.ui):
@@ -82,5 +82,5 @@ class TestLogKeywords(test_util.TestBase):
template='{rev}:{svnrev} ', **defaults)
def suite():
- all = [unittest.TestLoader().loadTestsFromTestCase(TestLogKeywords),]
- return unittest.TestSuite(all)
+ all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestLogKeywords), ]
+ return unittest.TestSuite(all_tests)
diff --git a/tests/test_unaffected_core.py b/tests/test_unaffected_core.py
index 4fe1dea..f680ada 100644
--- a/tests/test_unaffected_core.py
+++ b/tests/test_unaffected_core.py
@@ -10,6 +10,13 @@ from mercurial import hg
from mercurial import node
from mercurial import ui
+def _dispatch(ui, cmd):
+ try:
+ req = dispatch.request(cmd, ui=ui)
+ dispatch._dispatch(req)
+ except AttributeError:
+ dispatch._dispatch(ui, cmd)
+
class TestMercurialCore(test_util.TestBase):
'''
Test that the core Mercurial operations aren't broken by hgsubversion.
@@ -19,7 +26,7 @@ class TestMercurialCore(test_util.TestBase):
def test_update(self):
''' Test 'clone --updaterev' '''
ui = self.ui()
- dispatch._dispatch(ui, ['init', self.wc_path])
+ _dispatch(ui, ['init', self.wc_path])
repo = self.repo
repo.ui.setconfig('ui', 'username', 'anonymous')
@@ -39,7 +46,7 @@ class TestMercurialCore(test_util.TestBase):
self.assertEqual(len(repo), 3)
updaterev = 1
- dispatch._dispatch(ui, ['clone', self.wc_path, self.wc_path + '2',
+ _dispatch(ui, ['clone', self.wc_path, self.wc_path + '2',
'--updaterev=%s' % updaterev])
repo2 = hg.repository(ui, self.wc_path + '2')
@@ -50,7 +57,7 @@ class TestMercurialCore(test_util.TestBase):
def test_branch(self):
''' Test 'clone --branch' '''
ui = self.ui()
- dispatch._dispatch(ui, ['init', self.wc_path])
+ _dispatch(ui, ['init', self.wc_path])
repo = self.repo
repo.ui.setconfig('ui', 'username', 'anonymous')
@@ -73,7 +80,7 @@ class TestMercurialCore(test_util.TestBase):
self.assertEqual(len(repo), 3)
branch = 'B1'
- dispatch._dispatch(ui, ['clone', self.wc_path, self.wc_path + '2',
+ _dispatch(ui, ['clone', self.wc_path, self.wc_path + '2',
'--branch', branch])
repo2 = hg.repository(ui, self.wc_path + '2')
@@ -81,5 +88,5 @@ class TestMercurialCore(test_util.TestBase):
self.assertEqual(repo[branch].hex(), repo2['.'].hex())
def suite():
- all = [unittest.TestLoader().loadTestsFromTestCase(TestMercurialCore)]
- return unittest.TestSuite(all)
+ all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestMercurialCore)]
+ return unittest.TestSuite(all_tests)
diff --git a/tests/test_urls.py b/tests/test_urls.py
index cdde420..d18aeb5 100644
--- a/tests/test_urls.py
+++ b/tests/test_urls.py
@@ -29,16 +29,16 @@ class TestSubversionUrls(test_util.TestBase):
def test_svnssh_preserve_user(self):
self.assertEqual(
- ('user', 't3stpw', 'svn+ssh://user@svn.testurl.com/repo', ),
+ ('user', 't3stpw', 'svn+ssh://user@svn.testurl.com/repo',),
parse_url('svn+ssh://user:t3stpw@svn.testurl.com/repo'))
self.assertEqual(
- ('bob', '123abc', 'svn+ssh://bob@svn.testurl.com/repo', ),
+ ('bob', '123abc', 'svn+ssh://bob@svn.testurl.com/repo',),
parse_url('svn+ssh://user:t3stpw@svn.testurl.com/repo', 'bob', '123abc'))
self.assertEqual(
- ('user2', None, 'svn+ssh://user2@svn.testurl.com/repo', ),
+ ('user2', None, 'svn+ssh://user2@svn.testurl.com/repo',),
parse_url('svn+ssh://user2@svn.testurl.com/repo'))
self.assertEqual(
- ('bob', None, 'svn+ssh://bob@svn.testurl.com/repo', ),
+ ('bob', None, 'svn+ssh://bob@svn.testurl.com/repo',),
parse_url('svn+ssh://user2@svn.testurl.com/repo', 'bob'))
def test_user_password_url(self):
@@ -75,5 +75,5 @@ class TestSubversionUrls(test_util.TestBase):
self.assertEqual(repo1.svnurl, repo2.svnurl)
def suite():
- all = [unittest.TestLoader().loadTestsFromTestCase(TestSubversionUrls)]
- return unittest.TestSuite(all)
+ all_tests = [unittest.TestLoader().loadTestsFromTestCase(TestSubversionUrls)]
+ return unittest.TestSuite(all_tests)
diff --git a/tests/test_util.py b/tests/test_util.py
index 0239618..63b02f8 100644
--- a/tests/test_util.py
+++ b/tests/test_util.py
@@ -18,7 +18,7 @@ sys.path.insert(0, _rootdir)
from mercurial import cmdutil
from mercurial import commands
from mercurial import context
-from mercurial import dispatch
+from mercurial import dispatch as dispatchmod
from mercurial import hg
from mercurial import i18n
from mercurial import node
@@ -43,7 +43,7 @@ from hgsubversion import util
# "Note that on Windows, you cannot set close_fds to true and
# also redirect the standard handles by setting stdin, stdout or
# stderr."
-canCloseFds='win32' not in sys.platform
+canCloseFds = 'win32' not in sys.platform
if not 'win32' in sys.platform:
def kill_process(popen_obj):
@@ -75,7 +75,7 @@ else:
DWORD, 'dwProcessId',
)
- CloseHandle = WINAPI(BOOL, ctypes.windll.kernel32.CloseHandle,
+ CloseHandle = WINAPI(BOOL, ctypes.windll.kernel32.CloseHandle,
HANDLE, 'hObject'
)
@@ -163,13 +163,20 @@ def load_svndump_fixture(path, fixture_name):
already exist.
'''
if os.path.exists(path): rmtree(path)
- subprocess.call(['svnadmin', 'create', path,],
+ subprocess.call(['svnadmin', 'create', path, ],
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
inp = open(os.path.join(FIXTURES, fixture_name))
- proc = subprocess.Popen(['svnadmin', 'load', path,], stdin=inp,
+ proc = subprocess.Popen(['svnadmin', 'load', path, ], stdin=inp,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
proc.communicate()
+def dispatch(cmd):
+ try:
+ req = dispatchmod.request(cmd)
+ dispatchmod.dispatch(req)
+ except AttributeError, e:
+ dispatchmod.dispatch(cmd)
+
def load_fixture_and_fetch(fixture_name, repo_path, wc_path, stupid=False,
subdir='', noupdate=True, layout='auto',
startrev=0, externals=None):
@@ -191,7 +198,7 @@ def load_fixture_and_fetch(fixture_name, repo_path, wc_path, stupid=False,
if externals:
cmd[:0] = ['--config', 'hgsubversion.externals=%s' % externals]
- dispatch.dispatch(cmd)
+ dispatch(cmd)
return hg.repository(testui(), wc_path)
@@ -229,12 +236,20 @@ def _verify_our_modules():
'from the wrong path!'
)
+def hgclone(ui, source, dest, update=True):
+ if getattr(hg, 'peer', None):
+ # Since 1.9 (d976542986d2)
+ src, dest = hg.clone(ui, {}, source, dest, update=update)
+ else:
+ src, dest = hg.clone(ui, source, dest, update=update)
+ return src, dest
+
class TestBase(unittest.TestCase):
def setUp(self):
_verify_our_modules()
- self.oldenv = dict([(k, os.environ.get(k, None), ) for k in
- ('LANG', 'LC_ALL', 'HGRCPATH', )])
+ self.oldenv = dict([(k, os.environ.get(k, None),) for k in
+ ('LANG', 'LC_ALL', 'HGRCPATH',)])
self.oldt = i18n.t
os.environ['LANG'] = os.environ['LC_ALL'] = 'C'
i18n.t = gettext.translation('hg', i18n.localedir, fallback=True)
@@ -351,6 +366,18 @@ class TestBase(unittest.TestCase):
if p.returncode:
raise Exception('svn co failed on %s: %r' % (svnpath, stderr))
+ def svnpropget(self, path, prop, rev='HEAD'):
+ path = self.repo_path + '/' + path
+ path = util.normalize_url(fileurl(path))
+ args = ['svn', 'propget', '-r', str(rev), prop, path]
+ p = subprocess.Popen(args,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ stdout, stderr = p.communicate()
+ if p.returncode:
+ raise Exception('svn ls failed on %s: %r' % (path, stderr))
+ return stdout.strip()
+
def commitchanges(self, changes, parent='tip', message='automated test'):
"""Commit changes to mercurial directory
diff --git a/tests/test_utility_commands.py b/tests/test_utility_commands.py
index b91613e..2de14bb 100644
--- a/tests/test_utility_commands.py
+++ b/tests/test_utility_commands.py
@@ -112,7 +112,7 @@ class UtilityTests(test_util.TestBase):
self._load_fixture_and_fetch('two_heads.svndump')
u = self.ui()
u.pushbuffer()
- parents = (self.repo['the_branch'].node(), revlog.nullid, )
+ parents = (self.repo['the_branch'].node(), revlog.nullid,)
def filectxfn(repo, memctx, path):
return context.memfilectx(path=path,
data='added',
@@ -155,7 +155,7 @@ class UtilityTests(test_util.TestBase):
def test_outgoing_output(self):
self._load_fixture_and_fetch('two_heads.svndump')
u = self.ui()
- parents = (self.repo['the_branch'].node(), revlog.nullid, )
+ parents = (self.repo['the_branch'].node(), revlog.nullid,)
def filectxfn(repo, memctx, path):
return context.memfilectx(path=path,
data='added',
@@ -185,7 +185,7 @@ class UtilityTests(test_util.TestBase):
def test_rebase(self):
self._load_fixture_and_fetch('two_revs.svndump')
- parents = (self.repo[0].node(), revlog.nullid, )
+ parents = (self.repo[0].node(), revlog.nullid,)
def filectxfn(repo, memctx, path):
return context.memfilectx(path=path,
data='added',
@@ -251,6 +251,6 @@ class UtilityTests(test_util.TestBase):
def suite():
- all = [unittest.TestLoader().loadTestsFromTestCase(UtilityTests),
+ all_tests = [unittest.TestLoader().loadTestsFromTestCase(UtilityTests),
]
- return unittest.TestSuite(all)
+ return unittest.TestSuite(all_tests)