Support for single-directory clones.

This commit is contained in:
Augie Fackler 2009-10-16 23:33:41 -04:00
parent 2bd7b60221
commit b0da25dd93
13 changed files with 293 additions and 79 deletions

View File

@ -66,6 +66,8 @@ wrapcmds = { # cmd: generic, target, fixdoc, ppopts, opts
'file mapping Subversion usernames to Mercurial authors'),
('', 'filemap', '',
'file containing rules for remapping Subversion repository paths'),
('', 'layout', 'auto', ('import standard layout or single '
'directory? Can be standard, single, or auto.')),
]),
}

View File

@ -94,7 +94,7 @@ class RevisionData(object):
self.ui.flush()
if p[-1] == '/':
dir = p[len(root):]
new = [dir + f for f, k in svn.list_files(dir, r) if k == 'f']
new = [p + f for f, k in svn.list_files(dir, r) if k == 'f']
files.update(new)
else:
files.add(p[len(root):])
@ -107,7 +107,7 @@ class RevisionData(object):
if i % 50 == 0:
svn.init_ra_and_client()
i += 1
data, mode = svn.get_file(p, r)
data, mode = svn.get_file(p[len(root):], r)
self.set(p, data, 'x' in mode, 'l' in mode)
self.missing = set()
@ -304,7 +304,7 @@ class HgEditor(delta.Editor):
def open_directory(self, path, parent_baton, base_revision, dir_pool=None):
self.current.batons[path] = path
p_, branch = self.meta.split_branch_path(path)[:2]
if p_ == '':
if p_ == '' or (self.meta.layout == 'single' and p_):
self.current.emptybranches[branch] = False
return path

View File

@ -29,14 +29,13 @@ def convert_rev(ui, meta, svn, r, tbdelta):
current.findmissing(svn)
# update externals
if current.externals:
# TODO fix and re-enable externals for single-directory clones
if current.externals and not meta.layout == 'single':
# accumulate externals records for all branches
revnum = current.rev.revnum
branches = {}
for path, entry in current.externals.iteritems():
if not meta.is_path_valid(path):
ui.warn('WARNING: Invalid path %s in externals\n' % path)
continue
@ -56,7 +55,9 @@ def convert_rev(ui, meta, svn, r, tbdelta):
# register externals file changes
for bp, external in branches.iteritems():
path = bp + '/.hgsvnexternals'
if bp and bp[-1] != '/':
bp += '/'
path = (bp and bp + '.hgsvnexternals') or '.hgsvnexternals'
if external:
current.set(path, external.write(), False, False)
else:

View File

@ -103,6 +103,8 @@ def diff_branchrev(ui, svn, meta, branch, r, parentctx):
error.
"""
def make_diff_path(branch):
if meta.layout == 'single':
return ''
if branch == 'trunk' or branch is None:
return 'trunk'
elif branch.startswith('../'):
@ -203,7 +205,10 @@ def diff_branchrev(ui, svn, meta, branch, r, parentctx):
for p in r.paths:
if p.startswith(diff_path) and r.paths[p].action == 'D':
p2 = p[len(diff_path)+1:].strip('/')
if diff_path:
p2 = p[len(diff_path)+1:].strip('/')
else:
p2 = p
if p2 in parentctx:
files_data[p2] = None
continue
@ -221,7 +226,10 @@ def diff_branchrev(ui, svn, meta, branch, r, parentctx):
raise IOError()
if path in binary_files:
data, mode = svn.get_file(diff_path + '/' + path, r.revnum)
pa = path
if diff_path:
pa = diff_path + '/' + path
data, mode = svn.get_file(pa, r.revnum)
isexe = 'x' in mode
islink = 'l' in mode
else:
@ -236,6 +244,10 @@ def diff_branchrev(ui, svn, meta, branch, r, parentctx):
data = parentctx[path].data()
copied = copies.get(path)
# TODO this branch feels like it should not be required,
# and this may actually imply a bug in getcopies
if copied not in parentctx.manifest():
copied = None
return context.memfilectx(path=path, data=data, islink=islink,
isexec=isexe, copied=copied)
@ -347,7 +359,7 @@ def fetch_externals(svn, branchpath, r, parentctx):
dirs.update([p for p,k in svn.list_files(branchpath, r.revnum) if k == 'd'])
dirs.add('')
else:
branchprefix = branchpath + '/'
branchprefix = (branchpath and branchpath + '/') or branchpath
for path, e in r.paths.iteritems():
if e.action == 'D':
continue
@ -369,7 +381,8 @@ def fetch_externals(svn, branchpath, r, parentctx):
# Retrieve new or updated values
for dir in dirs:
try:
values = svn.list_props(branchpath + '/' + dir, r.revnum)
dpath = (branchpath and branchpath + '/' + dir) or dir
values = svn.list_props(dpath, r.revnum)
externals[dir] = values.get('svn:externals', '')
except IOError:
externals[dir] = ''
@ -394,7 +407,7 @@ def fetch_branchrev(svn, meta, branch, branchpath, r, parentctx):
if kind == 'f':
files.append(path)
else:
branchprefix = branchpath + '/'
branchprefix = (branchpath and branchpath + '/') or ''
for path, e in r.paths.iteritems():
if not path.startswith(branchprefix):
continue
@ -423,7 +436,10 @@ def fetch_branchrev(svn, meta, branch, branchpath, r, parentctx):
copies = getcopies(svn, meta, branch, branchpath, r, files, parentctx)
def filectxfn(repo, memctx, path):
data, mode = svn.get_file(branchpath + '/' + path, r.revnum)
svnpath = path
if branchpath:
svnpath = branchpath + '/' + path
data, mode = svn.get_file(svnpath, r.revnum)
isexec = 'x' in mode
islink = 'l' in mode
copied = copies.get(path)
@ -509,7 +525,6 @@ def branches_in_paths(meta, tbdelta, paths, revnum, checkpath, listdir):
if branchname and branchname.startswith('../'):
continue
branches[branchname] = branchpath
return branches
def convert_rev(ui, meta, svn, r, tbdelta):
@ -549,7 +564,6 @@ def convert_rev(ui, meta, svn, r, tbdelta):
date = meta.fixdate(r.date)
check_deleted_branches = set(tbdelta['branches'][1])
for b in branches:
parentctx = meta.repo[meta.get_parent_revision(r.revnum, b)]
if parentctx.branch() != (b or 'default'):
check_deleted_branches.add(b)
@ -570,9 +584,10 @@ def convert_rev(ui, meta, svn, r, tbdelta):
files_touched, filectxfn2 = fetch_branchrev(
svn, meta, b, branches[b], r, parentctx)
externals = fetch_externals(svn, branches[b], r, parentctx)
if externals is not None:
files_touched.append('.hgsvnexternals')
if meta.layout != 'single':
externals = fetch_externals(svn, branches[b], r, parentctx)
if externals is not None:
files_touched.append('.hgsvnexternals')
def filectxfn(repo, memctx, path):
if path == '.hgsvnexternals':

View File

@ -32,17 +32,23 @@ def verify(ui, repo, *args, **opts):
if args:
url = args[0]
svn = svnrepo.svnremoterepo(ui, url).svn
meta = repo.svnmeta(svn.uuid, svn.subdir)
btypes = {'default': 'trunk'}
branchpath = btypes.get(ctx.branch(), 'branches/%s' % ctx.branch())
branchpath = posixpath.normpath(branchpath)
if meta.layout == 'standard':
branchpath = btypes.get(ctx.branch(), 'branches/%s' % ctx.branch())
else:
branchpath = ''
svnfiles = set()
result = 0
for fn, type in svn.list_files(branchpath, srev):
for fn, type in svn.list_files(posixpath.normpath(branchpath), srev):
if type != 'f':
continue
svnfiles.add(fn)
data, mode = svn.get_file(branchpath + '/' + fn, srev)
fp = fn
if branchpath:
fp = branchpath + '/' + fn
data, mode = svn.get_file(posixpath.normpath(fp), srev)
fctx = ctx[fn]
dmatch = fctx.data() == data
mmatch = fctx.flags() == mode
@ -87,6 +93,8 @@ def rebuildmeta(ui, repo, hg_repo_path, args, **opts):
os.unlink(maps.TagMap.filepath(repo))
tags = maps.TagMap(repo)
layout = None
skipped = set()
for rev in repo:
@ -126,6 +134,18 @@ def rebuildmeta(ui, repo, hg_repo_path, args, **opts):
assert revpath.startswith(subdir), ('That does not look like the '
'right location in the repo.')
if layout is None:
if (subdir or '/') == revpath:
layout = 'single'
else:
layout = 'standard'
f = open(os.path.join(svnmetadir, 'layout'), 'w')
f.write(layout)
f.close()
elif layout == 'single':
assert (subdir or '/') == revpath, ('Possible layout detection'
' defect in replay')
# write repository uuid if required
if uuid is None:
uuid = convinfo[4:40]
@ -142,17 +162,17 @@ def rebuildmeta(ui, repo, hg_repo_path, args, **opts):
# find commitpath, write to revmap
commitpath = revpath[len(subdir)+1:]
bp = posixpath.normpath('/'.join([subdir, 'branches', ctx.branch()]))
if revpath == bp:
commitpath = ctx.branch()
elif commitpath == 'trunk':
commitpath = ''
elif commitpath.startswith('tags'):
if ctx.extra().get('close'):
continue
commitpath = '../' + commitpath
if layout == 'standard':
if commitpath.startswith('branches/'):
commitpath = commitpath[len('branches/'):]
elif commitpath == 'trunk':
commitpath = ''
else:
if commitpath.startswith('tags/') and ctx.extra().get('close'):
continue
commitpath = '../' + commitpath
else:
assert False, 'unhandled rev %s: %s' % (rev, convinfo)
commitpath = ''
revmap.write('%s %s %s\n' % (revision, ctx.hex(), commitpath))
revision = int(revision)

View File

@ -69,6 +69,13 @@ class SVNMeta(object):
f.close()
else:
self.tag_locations = tag_locations
if os.path.exists(self.layoutfile):
f = open(self.layoutfile)
self._layout = f.read().strip()
f.close()
self.repo.ui.setconfig('hgsubversion', 'layout', self._layout)
else:
self._layout = None
pickle_atomic(self.tag_locations, self.tag_locations_file,
self.meta_data_dir)
# ensure nested paths are handled properly
@ -82,6 +89,21 @@ class SVNMeta(object):
self.lastdate = '1970-01-01 00:00:00 -0000'
self.filemap = maps.FileMap(repo)
@property
def layout(self):
# this method can't determine the layout, but it needs to be
# resolved into something other than auto before this ever
# gets called
if not self._layout or self._layout == 'auto':
lo = self.repo.ui.config('hgsubversion', 'layout', default='auto')
if lo == 'auto':
raise hgutil.Abort('layout not yet determined')
self._layout = lo
f = open(self.layoutfile, 'w')
f.write(self._layout)
f.close()
return self._layout
@property
def editor(self):
if not hasattr(self, '_editor'):
@ -127,6 +149,10 @@ class SVNMeta(object):
def authors_file(self):
return os.path.join(self.meta_data_dir, 'authors')
@property
def layoutfile(self):
return os.path.join(self.meta_data_dir, 'layout')
def fixdate(self, date):
if date is not None:
date = date.replace('T', ' ').replace('Z', '').split('.')[0]
@ -145,6 +171,8 @@ class SVNMeta(object):
def localname(self, path):
"""Compute the local name for a branch located at path.
"""
if self.layout == 'single':
return 'default'
if path == 'trunk':
return None
elif path.startswith('branches/'):
@ -152,6 +180,8 @@ class SVNMeta(object):
return '../%s' % path
def remotename(self, branch):
if self.layout == 'single':
return ''
if branch == 'default' or branch is None:
return 'trunk'
elif branch.startswith('../'):
@ -160,23 +190,27 @@ class SVNMeta(object):
def genextra(self, revnum, branch):
extra = {}
branchpath = 'trunk'
if branch:
extra['branch'] = branch
if branch.startswith('../'):
branchpath = branch[3:]
else:
branchpath = 'branches/%s' % branch
subdir = self.subdir
if subdir and subdir[-1] == '/':
subdir = subdir[:-1]
if subdir and subdir[0] != '/':
subdir = '/' + subdir
if self.layout == 'single':
path = subdir or '/'
else:
branchpath = 'trunk'
if branch:
extra['branch'] = branch
if branch.startswith('../'):
branchpath = branch[3:]
else:
branchpath = 'branches/%s' % branch
path = '%s/%s' % (subdir , branchpath)
extra['convert_revision'] = 'svn:%(uuid)s%(path)s@%(rev)s' % {
'uuid': self.uuid,
'path': '%s/%s' % (subdir , branchpath),
'path': path,
'rev': revnum,
}
return extra
@ -185,6 +219,8 @@ class SVNMeta(object):
'''Normalize a path to strip of leading slashes and our subdir if we
have one.
'''
if self.subdir and path == self.subdir[:-1]:
return ''
if path and path[0] == '/':
path = path[1:]
if path and path.startswith(self.subdir):
@ -200,6 +236,8 @@ class SVNMeta(object):
Note that it's only a tag if it was copied from the path '' in a branch
(or tag) we have, for our purposes.
"""
if self.layout == 'single':
return False
path = self.normalize(path)
for tagspath in self.tag_locations:
onpath = path.startswith(tagspath)
@ -217,9 +255,11 @@ class SVNMeta(object):
If existing=True, will return None, None, None if the file isn't on some known
branch. If existing=False, then it will guess what the branch would be if it were
known.
known. Server-side branch path should be relative to our subdirectory.
"""
path = self.normalize(path)
if self.layout == 'single':
return (path, None, '')
if self.is_path_tag(path):
tag = self.is_path_tag(path)
matched = [t for t in self.tags.iterkeys() if tag.startswith(t+'/')]
@ -325,6 +365,19 @@ class SVNMeta(object):
return int(revnum), self.localname(self.normalize(branch))
def update_branch_tag_map_for_rev(self, revision):
"""Given a revision object, determine changes to branches and tags.
Returns: a dict of {
'tags': (added_tags, rmtags),
'branches': (added_branches, self.closebranches),
} where adds are dicts where the keys are branch/tag names and
values are the place the branch/tag came from. The deletions are
sets of the deleted branches.
"""
if self.layout == 'single':
return {'tags': ({}, set()),
'branches': ({None: (None, 0, -1), }, set()),
}
paths = revision.paths
added_branches = {}
added_tags = {}

View File

@ -345,7 +345,8 @@ class SubversionRepo(object):
dir: the directory to list, no leading slash
rev: the revision at which to list the directory, defaults to HEAD
"""
if dir[-1] == '/':
# TODO this should just not accept leading slashes like the docstring says
if dir and dir[-1] == '/':
dir = dir[:-1]
if revision is None:
revision = self.HEAD
@ -555,6 +556,7 @@ class SubversionRepo(object):
otherwise. If the file does not exist at this revision, raise
IOError.
"""
assert not path.startswith('/')
mode = ''
try:
out = cStringIO.StringIO()
@ -633,7 +635,9 @@ class SubversionRepo(object):
def path2url(self, path):
"""Build svn URL for path, URL-escaping path.
"""
assert path[0] != '/'
if not path or path == '.':
return self.svn_url
assert path[0] != '/', path
return '/'.join((self.svn_url,
urllib.quote(path).rstrip('/'),
))

View File

@ -228,6 +228,16 @@ def pull(repo, source, heads=[], force=False):
svn = svnrepo.svnremoterepo(repo.ui, svn_url).svn
meta = repo.svnmeta(svn.uuid, svn.subdir)
layout = repo.ui.config('hgsubversion', 'layout', 'auto')
if layout == 'auto':
rootlist = svn.list_dir('', revision=(stopat_rev or None))
if sum(map(lambda x: x in rootlist, ('branches', 'tags', 'trunk'))):
layout = 'standard'
else:
layout = 'single'
repo.ui.setconfig('hgsubversion', 'layout', layout)
repo.ui.note('using %s layout\n' % layout)
start = max(meta.revmap.seen, skipto_rev)
initializing_repo = meta.revmap.seen <= 0
ui = repo.ui
@ -351,9 +361,10 @@ optionmap = {
'defaulthost': ('hgsubversion', 'defaulthost'),
'defaultauthors': ('hgsubversion', 'defaultauthors'),
'usebranchnames': ('hgsubversion', 'usebranchnames'),
'layout': ('hgsubversion', 'layout'),
}
dontretain = { 'hgsubversion': set(['authormap', 'filemap']) }
dontretain = { 'hgsubversion': set(['authormap', 'filemap', 'layout', ]) }
def clone(orig, ui, source, dest=None, **opts):
"""

View File

@ -9,9 +9,9 @@ from tests import test_util
from hgsubversion import wrappers
def _do_case(self, name):
def _do_case(self, name, layout):
subdir = test_util.subdir.get(name, '')
self._load_fixture_and_fetch(name, subdir=subdir, stupid=False)
self._load_fixture_and_fetch(name, subdir=subdir, stupid=False, layout=layout)
assert len(self.repo) > 0, 'Repo had no changes, maybe you need to add a subdir entry in test_util?'
wc2_path = self.wc_path + '_stupid'
u = ui.ui()
@ -19,22 +19,28 @@ def _do_case(self, name):
if subdir:
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)
if layout == 'single':
self.assertEqual(len(self.repo.heads()), 1)
self.repo2 = hg.repository(ui.ui(), wc2_path)
self.assertEqual(self.repo.heads(), self.repo2.heads())
def buildmethod(case, name):
m = lambda self: self._do_case(case)
def buildmethod(case, name, layout):
m = lambda self: self._do_case(case, layout)
m.__name__ = name
m.__doc__ = 'Test stupid produces same as real on %s.' % case
m.__doc__ = 'Test stupid produces same as real on %s. (%s)' % (case, layout)
return m
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)
attrs[name] = buildmethod(case, name, 'auto')
name += '_single'
attrs[name] = buildmethod(case, name, 'single')
StupidPullTests = type('StupidPullTests', (test_util.TestBase, ), attrs)

View File

@ -14,19 +14,19 @@ from mercurial import ui
from hgsubversion import svncommands
def _do_case(self, name, stupid):
def _do_case(self, name, stupid, layout):
subdir = test_util.subdir.get(name, '')
repo = self._load_fixture_and_fetch(name, subdir=subdir, stupid=stupid)
repo = self._load_fixture_and_fetch(name, subdir=subdir, stupid=stupid, layout=layout)
assert len(self.repo) > 0
for i in repo:
ctx = repo[i]
self.assertEqual(svncommands.verify(repo.ui, repo, rev=ctx.node()), 0)
def buildmethod(case, name, stupid):
m = lambda self: self._do_case(case, stupid)
def buildmethod(case, name, stupid, layout):
m = lambda self: self._do_case(case, stupid, layout)
m.__name__ = name
bits = case, stupid and 'stupid' or 'real'
m.__doc__ = 'Test verify on %s with %s replay.' % bits
bits = case, stupid and 'stupid' or 'real', layout
m.__doc__ = 'Test verify on %s with %s replay. (%s)' % bits
return m
attrs = {'_do_case': _do_case}
@ -35,10 +35,16 @@ for case in fixtures:
# this fixture results in an empty repository, don't use it
if case == 'project_root_not_repo_root.svndump':
continue
name = 'test_' + case[:-len('.svndump')]
attrs[name] = buildmethod(case, name, False)
name += '_stupid'
attrs[name] = buildmethod(case, name, True)
bname = 'test_' + case[:-len('.svndump')]
attrs[bname] = buildmethod(case, bname, False, 'standard')
name = bname + '_stupid'
attrs[name] = buildmethod(case, name, True, 'standard')
name = bname + '_single'
attrs[name] = buildmethod(case, name, False, 'single')
# Disabled because the "stupid and real are the same" tests
# verify this plus even more.
# name = bname + '_single_stupid'
# attrs[name] = buildmethod(case, name, True, 'single')
VerifyTests = type('VerifyTests', (test_util.TestBase,), attrs)

View File

@ -10,9 +10,12 @@ from mercurial import ui
from hgsubversion import svncommands
from hgsubversion import svnmeta
def _do_case(self, name, stupid):
def _do_case(self, name, stupid, single):
subdir = test_util.subdir.get(name, '')
self._load_fixture_and_fetch(name, subdir=subdir, stupid=stupid)
layout = 'auto'
if single:
layout = 'single'
self._load_fixture_and_fetch(name, subdir=subdir, stupid=stupid, layout=layout)
assert len(self.repo) > 0
wc2_path = self.wc_path + '_clone'
u = ui.ui()
@ -27,7 +30,7 @@ def _do_case(self, name, stupid):
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', ):
for tf in ('rev_map', 'uuid', 'tagmap', 'layout', ):
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)
@ -54,11 +57,15 @@ def _do_case(self, name, stupid):
self.assertEqual(srcinfo[2], destinfo[2])
def buildmethod(case, name, stupid):
m = lambda self: self._do_case(case, stupid)
def buildmethod(case, name, stupid, single):
m = lambda self: self._do_case(case, stupid, single)
m.__name__ = name
m.__doc__ = ('Test rebuildmeta on %s with %s replay.' %
(case, (stupid and 'stupid') or 'real'))
m.__doc__ = ('Test rebuildmeta on %s with %s replay. (%s)' %
(case,
(stupid and 'stupid') or 'real',
(single and 'single') or 'standard',
)
)
return m
@ -68,10 +75,13 @@ for case in [f for f in os.listdir(test_util.FIXTURES) if f.endswith('.svndump')
# this fixture results in an empty repository, don't use it
if case == 'project_root_not_repo_root.svndump':
continue
name = 'test_' + case[:-len('.svndump')]
attrs[name] = buildmethod(case, name, False)
name += '_stupid'
attrs[name] = buildmethod(case, name, True)
bname = 'test_' + case[:-len('.svndump')]
attrs[bname] = buildmethod(case, bname, False, False)
name = bname + '_stupid'
attrs[name] = buildmethod(case, name, True, False)
name = bname + '_single'
attrs[name] = buildmethod(case, name, False, True)
RebuildMetaTests = type('RebuildMetaTests', (test_util.TestBase, ), attrs)

View File

@ -0,0 +1,72 @@
import shutil
import test_util
class TestSingleDir(test_util.TestBase):
def test_clone_single_dir_simple(self):
repo = self._load_fixture_and_fetch('branch_from_tag.svndump',
stupid=False,
layout='single',
subdir='')
self.assertEqual(repo.branchtags().keys(), ['default'])
self.assertEqual(repo['tip'].manifest().keys(),
['trunk/beta',
'tags/copied_tag/alpha',
'trunk/alpha',
'tags/copied_tag/beta',
'branches/branch_from_tag/alpha',
'tags/tag_r3/alpha',
'tags/tag_r3/beta',
'branches/branch_from_tag/beta'])
def test_auto_detect_single(self):
repo = self._load_fixture_and_fetch('branch_from_tag.svndump',
stupid=False,
layout='auto')
self.assertEqual(repo.branchtags().keys(), ['default',
'branch_from_tag'])
oldmanifest = test_util.filtermanifest(repo['default'].manifest().keys())
# remove standard layout
shutil.rmtree(self.wc_path)
# try again with subdir to get single dir clone
repo = self._load_fixture_and_fetch('branch_from_tag.svndump',
stupid=False,
layout='auto',
subdir='trunk')
self.assertEqual(repo.branchtags().keys(), ['default', ])
self.assertEqual(repo['default'].manifest().keys(), oldmanifest)
def test_externals_single(self):
repo = self._load_fixture_and_fetch('externals.svndump',
stupid=False,
layout='single')
for rev in repo:
assert '.hgsvnexternals' not in repo[rev].manifest()
return # TODO enable test when externals in single are fixed
expect = """[.]
-r2 ^/externals/project2@2 deps/project2
[subdir]
^/externals/project1 deps/project1
[subdir2]
^/externals/project1 deps/project1
"""
test = 2
self.assertEqual(self.repo[test]['.hgsvnexternals'].data(), expect)
def test_externals_single_whole_repo(self):
# This is the test which demonstrates the brokenness of externals
return # TODO enable test when externals in single are fixed
repo = self._load_fixture_and_fetch('externals.svndump',
stupid=False,
layout='single',
subdir='')
for rev in repo:
rc = repo[rev]
if '.hgsvnexternals' in rc:
extdata = rc['.hgsvnexternals'].data()
assert '[.]' not in extdata
print extdata
expect = '' # Not honestly sure what this should be...
test = 4
self.assertEqual(self.repo[test]['.hgsvnexternals'].data(), expect)

View File

@ -82,6 +82,10 @@ subdir = {'truncatedhistory.svndump': '/project2',
FIXTURES = os.path.join(os.path.abspath(os.path.dirname(__file__)),
'fixtures')
def filtermanifest(manifest):
return filter(lambda x: x not in ('.hgtags', '.hgsvnexternals', ),
manifest)
def fileurl(path):
path = os.path.abspath(path)
drive, path = os.path.splitdrive(path)
@ -103,16 +107,21 @@ def load_svndump_fixture(path, fixture_name):
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
proc.communicate()
def load_fixture_and_fetch(fixture_name, repo_path, wc_path, stupid=False, subdir='', noupdate=True):
def load_fixture_and_fetch(fixture_name, repo_path, wc_path, stupid=False, subdir='',
noupdate=True, layout='auto'):
load_svndump_fixture(repo_path, fixture_name)
if subdir:
repo_path += '/' + subdir
_ui = ui.ui()
_ui.setconfig('hgsubversion', 'stupid', str(stupid))
confvars = locals()
def conf():
for var in ('stupid', 'layout'):
_ui = ui.ui()
_ui.setconfig('hgsubversion', var, confvars[var])
return _ui
_ui = conf()
commands.clone(_ui, fileurl(repo_path), wc_path, noupdate=noupdate)
_ui = ui.ui()
_ui.setconfig('hgsubversion', 'stupid', str(stupid))
_ui = conf()
return hg.repository(_ui, wc_path)
def rmtree(path):
@ -170,10 +179,15 @@ class TestBase(unittest.TestCase):
os.chdir(self.oldwd)
setattr(ui.ui, self.patch[0].func_name, self.patch[0])
def _load_fixture_and_fetch(self, fixture_name, subdir='', stupid=False):
def _load_fixture_and_fetch(self, fixture_name, subdir=None, stupid=False, layout='auto'):
if layout == 'single':
if subdir is None:
subdir = 'trunk'
elif subdir is None:
subdir = ''
return load_fixture_and_fetch(fixture_name, self.repo_path,
self.wc_path, subdir=subdir,
stupid=stupid)
stupid=stupid, layout=layout)
# define this as a property so that it reloads anytime we need it
@property