# HG changeset patch # User Augie Fackler # Date 1422630012 18000 # Node ID 553c4002372939807439312a6ccac8da2422f27f # Parent b5520673f6f243a511070d45e6c63ead2f3e135c# Parent 9d5cff8d7f67241cc7a959f2e7b212b0902a2ed3 Merge default into stable for a release. diff --git a/hgsubversion/layouts/__init__.py b/hgsubversion/layouts/__init__.py --- a/hgsubversion/layouts/__init__.py +++ b/hgsubversion/layouts/__init__.py @@ -13,14 +13,12 @@ from mercurial import util as hgutil import custom import detect -import persist import single import standard __all__ = [ "detect", "layout_from_name", - "persist", ] # This is the authoritative store of what layouts are available. @@ -33,7 +31,7 @@ NAME_TO_CLASS = { } -def layout_from_name(name, ui): +def layout_from_name(name, meta): """Returns a layout module given the layout name You should use one of the layout.detect.* functions to get the @@ -42,5 +40,5 @@ def layout_from_name(name, ui): """ if name not in NAME_TO_CLASS: - raise hgutil.Abort('Unknown hgsubversion layout: %s' %name) - return NAME_TO_CLASS[name](ui) + raise hgutil.Abort('Unknown hgsubversion layout: %s' % name) + return NAME_TO_CLASS[name](meta) diff --git a/hgsubversion/layouts/base.py b/hgsubversion/layouts/base.py --- a/hgsubversion/layouts/base.py +++ b/hgsubversion/layouts/base.py @@ -9,8 +9,8 @@ from mercurial import util as hgutil class BaseLayout(object): - def __init__(self, ui): - self.ui = ui + def __init__(self, meta): + self.meta = meta def __unimplemented(self, method_name): raise NotImplementedError( @@ -48,7 +48,8 @@ class BaseLayout(object): """ self.__unimplemented('remotepath') - def taglocations(self, metapath): + @property + def taglocations(self): """Return a list of locations within svn to search for tags Should be returned in reverse-sorted order. diff --git a/hgsubversion/layouts/custom.py b/hgsubversion/layouts/custom.py --- a/hgsubversion/layouts/custom.py +++ b/hgsubversion/layouts/custom.py @@ -12,13 +12,13 @@ import base class CustomLayout(base.BaseLayout): - def __init__(self, ui): - base.BaseLayout.__init__(self, ui) + def __init__(self, meta): + base.BaseLayout.__init__(self, meta) self.svn_to_hg = {} self.hg_to_svn = {} - for hg_branch, svn_path in ui.configitems('hgsubversionbranch'): + for hg_branch, svn_path in meta.ui.configitems('hgsubversionbranch'): hg_branch = hg_branch.strip() if hg_branch == 'default' or not hg_branch: @@ -64,7 +64,8 @@ class CustomLayout(base.BaseLayout): subdir += '/' return subdir + self.remotename(branch) - def taglocations(self, metapath): + @property + def taglocations(self): return [] def get_path_tag(self, path, taglocations): diff --git a/hgsubversion/layouts/detect.py b/hgsubversion/layouts/detect.py --- a/hgsubversion/layouts/detect.py +++ b/hgsubversion/layouts/detect.py @@ -12,7 +12,7 @@ from mercurial import util as hgutil import __init__ as layouts -def layout_from_subversion(svn, revision=None, ui=None): +def layout_from_subversion(svn, revision=None, meta=None): """ Guess what layout to use based on directories under the svn root. This is intended for use during bootstrapping. It guesses which @@ -39,10 +39,10 @@ def layout_from_subversion(svn, revision layout = 'standard' else: layout = 'single' - ui.setconfig('hgsubversion', 'layout', layout) + meta.ui.setconfig('hgsubversion', 'layout', layout) return layout -def layout_from_config(ui, allow_auto=False): +def layout_from_config(meta, allow_auto=False): """ Load the layout we are using based on config We will read the config from the ui object. Pass allow_auto=True @@ -51,32 +51,29 @@ def layout_from_config(ui, allow_auto=Fa detect the layout as auto. """ - layout = ui.config('hgsubversion', 'layout', default='auto') + layout = meta.ui.config('hgsubversion', 'layout', default='auto') if layout == 'auto' and not allow_auto: raise hgutil.Abort('layout not yet determined') elif layout not in layouts.NAME_TO_CLASS and layout != 'auto': raise hgutil.Abort("unknown layout '%s'" % layout) return layout -def layout_from_file(metapath, ui=None): +def layout_from_file(meta): """ Load the layout in use from the metadata file. - - If you pass the ui arg, we will also write the layout to the - config for that ui. - """ - layout = None - layoutfile = os.path.join(metapath, 'layout') - if os.path.exists(layoutfile): - f = open(layoutfile) - layout = f.read().strip() - f.close() - if ui: - ui.setconfig('hgsubversion', 'layout', layout) + # import late to avoid trouble when running the test suite + try: + from hgext_hgsubversion import util + except ImportError: + from hgsubversion import util + + layout = util.load(meta.layout_file) + if layout: + meta.ui.setconfig('hgsubversion', 'layout', layout) return layout -def layout_from_commit(subdir, revpath, branch, ui): +def layout_from_commit(subdir, revpath, branch, meta): """ Guess what the layout is based existing commit info Specifically, this compares the subdir for the repository and the @@ -93,7 +90,7 @@ def layout_from_commit(subdir, revpath, candidates = set() for layout in layouts.NAME_TO_CLASS: - layoutobj = layouts.layout_from_name(layout, ui) + layoutobj = layouts.layout_from_name(layout, meta) try: remotepath = layoutobj.remotepath(branch, subdir) except KeyError: @@ -104,7 +101,7 @@ def layout_from_commit(subdir, revpath, if len(candidates) == 1: return candidates.pop() elif candidates: - config_layout = layout_from_config(ui, allow_auto=True) + config_layout = layout_from_config(meta, allow_auto=True) if config_layout in candidates: return config_layout diff --git a/hgsubversion/layouts/persist.py b/hgsubversion/layouts/persist.py deleted file mode 100644 --- a/hgsubversion/layouts/persist.py +++ /dev/null @@ -1,16 +0,0 @@ -"""Code for persisting the layout config in various locations. - -Basically, if you want to save the layout, this is where you should go -to do it. - -""" - -import os.path - -def layout_to_file(metapath, layout): - """Save the given layout to a file under the given metapath""" - - layoutfile = os.path.join(metapath, 'layout') - f = open(layoutfile, 'w') - f.write(layout) - f.close() diff --git a/hgsubversion/layouts/single.py b/hgsubversion/layouts/single.py --- a/hgsubversion/layouts/single.py +++ b/hgsubversion/layouts/single.py @@ -14,7 +14,8 @@ class SingleLayout(base.BaseLayout): def remotepath(self, branch, subdir='/'): return subdir or '/' - def taglocations(self, metapath): + @property + def taglocations(self): return [] def get_path_tag(self, path, taglocations): diff --git a/hgsubversion/layouts/standard.py b/hgsubversion/layouts/standard.py --- a/hgsubversion/layouts/standard.py +++ b/hgsubversion/layouts/standard.py @@ -5,80 +5,70 @@ import base class StandardLayout(base.BaseLayout): """The standard trunk, branches, tags layout""" - def __init__(self, ui): - base.BaseLayout.__init__(self, ui) + def __init__(self, meta): + base.BaseLayout.__init__(self, meta) self._tag_locations = None - self._branch_dir = ui.config('hgsubversion', 'branchdir', 'branches') - if self._branch_dir[0] == '/': - self._branch_dir = self._branch_dir[1:] - if self._branch_dir[-1] != '/': - self._branch_dir += '/' - - self._infix = ui.config('hgsubversion', 'infix', '').strip('/') - if self._infix: - self._infix = '/' + self._infix - - self._trunk = 'trunk%s' % self._infix + # branchdir is expected to be stripped of leading slashes but retain + # its last slash + meta._gen_cachedconfig('branchdir', 'branches', + pre=lambda x: '/'.join(p for p in x.split('/') + if p) + '/') + + # infix is expected to be stripped of trailing slashes but retain + # its first slash + def _infix_transform(x): + x = '/'.join(p for p in x.split('/') if p) + if x: + x = '/' + x + return x + meta._gen_cachedconfig('infix', '', pre=_infix_transform) + + # the lambda is to ensure nested paths are handled properly + meta._gen_cachedconfig('taglocations', ['tags'], 'tag_locations', + 'tagpaths', lambda x: list(reversed(sorted(x)))) + + @property + def trunk(self): + return 'trunk' + self.meta.infix def localname(self, path): - if path == self._trunk: + if path == self.trunk: return None - elif path.startswith(self._branch_dir) and path.endswith(self._infix): - path = path[len(self._branch_dir):] - if self._infix: - path = path[:-len(self._infix)] + elif path.startswith(self.meta.branchdir) and path.endswith(self.meta.infix): + path = path[len(self.meta.branchdir):] + if self.meta.infix: + path = path[:-len(self.meta.infix)] return path return '../%s' % path def remotename(self, branch): if branch == 'default' or branch is None: - path = self._trunk + path = self.trunk elif branch.startswith('../'): path = branch[3:] else: - path = ''.join((self._branch_dir, branch, self._infix)) + path = ''.join((self.meta.branchdir, branch, self.meta.infix)) return path def remotepath(self, branch, subdir='/'): if subdir == '/': subdir = '' - branchpath = self._trunk + branchpath = self.trunk if branch and branch != 'default': if branch.startswith('../'): branchpath = branch[3:] else: - branchpath = ''.join((self._branch_dir, branch, self._infix)) + branchpath = ''.join((self.meta.branchdir, branch, + self.meta.infix)) return '%s/%s' % (subdir or '', branchpath) - def taglocations(self, metapath): - # import late to avoid trouble when running the test suite - try: - # newer versions of mercurial >= 2.8 will import this because the - # hgext_ logic is already being done in core - from hgsubversion import util - except ImportError: - from hgext_hgsubversion import util - - if self._tag_locations is None: - - tag_locations_file = os.path.join(metapath, 'tag_locations') - self._tag_locations = util.load(tag_locations_file) - - if not self._tag_locations: - self._tag_locations = self.ui.configlist('hgsubversion', - 'tagpaths', - ['tags']) - util.dump(self._tag_locations, tag_locations_file) - - # ensure nested paths are handled properly - self._tag_locations.sort() - self._tag_locations.reverse() - - return self._tag_locations + @property + def taglocations(self): + return self.meta.taglocations def get_path_tag(self, path, taglocations): for tagspath in taglocations: @@ -109,22 +99,22 @@ class StandardLayout(base.BaseLayout): return candidate, '/'.join(components) if path == 'trunk' or path.startswith('trunk/'): - return self._trunk, path[len(self._trunk) + 1:] + return self.trunk, path[len(self.trunk) + 1:] - if path.startswith(self._branch_dir): - path = path[len(self._branch_dir):] + if path.startswith(self.meta.branchdir): + path = path[len(self.meta.branchdir):] components = path.split('/', 1) - branch_path = ''.join((self._branch_dir, components[0])) + branch_path = ''.join((self.meta.branchdir, components[0])) if len(components) == 1: local_path = '' else: local_path = components[1] if local_path == '': - branch_path += self._infix - elif local_path.startswith(self._infix[1:] + '/'): - branch_path += self._infix - local_path = local_path[len(self._infix):] + branch_path += self.meta.infix + elif local_path.startswith(self.meta.infix[1:] + '/'): + branch_path += self.meta.infix + local_path = local_path[len(self.meta.infix):] return branch_path, local_path components = path.split('/') diff --git a/hgsubversion/maps.py b/hgsubversion/maps.py --- a/hgsubversion/maps.py +++ b/hgsubversion/maps.py @@ -194,6 +194,7 @@ class RevMap(dict): def __init__(self, meta): dict.__init__(self) self.meta = meta + self._hashes = None if os.path.isfile(self.meta.revmap_file): self._load() @@ -201,7 +202,9 @@ class RevMap(dict): self._write() def hashes(self): - return dict((v, k) for (k, v) in self.iteritems()) + if self._hashes is None: + self._hashes = dict((v, k) for (k, v) in self.iteritems()) + return self._hashes def branchedits(self, branch, rev): check = lambda x: x[0][1] == branch and x[0][0] < rev.revnum @@ -256,6 +259,8 @@ class RevMap(dict): if revnum < self.meta.firstpulled or not self.meta.firstpulled: self.meta.firstpulled = revnum dict.__setitem__(self, (revnum, branch), ha) + if self._hashes is not None: + self._hashes[ha] = (revnum, branch) class FileMap(object): diff --git a/hgsubversion/replay.py b/hgsubversion/replay.py --- a/hgsubversion/replay.py +++ b/hgsubversion/replay.py @@ -177,7 +177,7 @@ def _convert_rev(ui, meta, svn, r, tbdel meta.mapbranch(extra) current_ctx = context.memctx(meta.repo, parents, - util.getmessage(ui, rev), + meta.getmessage(rev), files.keys(), filectxfn, meta.authors[rev.author], @@ -214,7 +214,7 @@ def _convert_rev(ui, meta, svn, r, tbdel current_ctx = context.memctx(meta.repo, (ha, node.nullid), - util.getmessage(ui, rev), + meta.getmessage(rev), files, del_all_files, meta.authors[rev.author], diff --git a/hgsubversion/stupid.py b/hgsubversion/stupid.py --- a/hgsubversion/stupid.py +++ b/hgsubversion/stupid.py @@ -171,61 +171,23 @@ 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): - # In Mercurial >= 3.2, if fname is missing, data will be None and we - # should return None, None in that case. Earlier versions will raise - # an IOError which we let propagate up the stack. - f = super(svnbackend, self).getfile(fname) - if f is None: - return None, None - data, flags = f - if data is None: - return None, None - islink, isexec = flags - if islink: - data = 'link ' + data - return data, (islink, isexec) -except AttributeError: - svnbackend = None +class svnbackend(patch.repobackend): + def getfile(self, fname): + # In Mercurial >= 3.2, if fname is missing, data will be None and we + # should return None, None in that case. Earlier versions will raise + # an IOError which we let propagate up the stack. + f = super(svnbackend, self).getfile(fname) + if f is None: + return None, None + data, flags = f + if data is None: + return None, None + islink, isexec = flags + if islink: + data = 'link ' + data + return data, (islink, isexec) def patchrepo(ui, meta, parentctx, patchfp): - if not svnbackend: - return patchrepoold(ui, meta, parentctx, patchfp) store = patch.filestore(util.getfilestoresize(ui)) try: touched = set() @@ -806,7 +768,7 @@ def convert_rev(ui, meta, svn, r, tbdelt meta.mapbranch(extra) current_ctx = context.memctx(meta.repo, [parentctx.node(), revlog.nullid], - util.getmessage(ui, r), + meta.getmessage(r), files_touched, filectxfn, meta.authors[r.author], diff --git a/hgsubversion/svncommands.py b/hgsubversion/svncommands.py --- a/hgsubversion/svncommands.py +++ b/hgsubversion/svncommands.py @@ -189,11 +189,11 @@ def _buildmeta(ui, repo, args, partial=F if layout is None: layout = layouts.detect.layout_from_commit(subdir, revpath, - ctx.branch(), ui) - existing_layout = layouts.detect.layout_from_file(meta.metapath) + ctx.branch(), meta) + existing_layout = layouts.detect.layout_from_file(meta) if layout != existing_layout: - layouts.persist.layout_to_file(meta.metapath, layout) - layoutobj = layouts.layout_from_name(layout, ui) + util.dump(layout, meta.layout_file) + layoutobj = layouts.layout_from_name(layout, meta) elif layout == 'single': assert (subdir or '/') == revpath, ('Possible layout detection' ' defect in replay') @@ -219,7 +219,7 @@ def _buildmeta(ui, repo, args, partial=F # find commitpath, write to revmap commitpath = revpath[len(subdir)+1:] - tag_locations = layoutobj.taglocations(meta.metapath) + tag_locations = layoutobj.taglocations found_tag = False for location in tag_locations: if commitpath.startswith(location + '/'): diff --git a/hgsubversion/svnexternals.py b/hgsubversion/svnexternals.py --- a/hgsubversion/svnexternals.py +++ b/hgsubversion/svnexternals.py @@ -390,6 +390,10 @@ class svnsubrepo(subrepo.svnsubrepo): def __init__(self, ctx, path, state): state = (state[0].split(':', 1)[1], state[1]) super(svnsubrepo, self).__init__(ctx, path, state) + # Mercurial 3.3+ set 'ui' rather than '_ui' -- set that and use 'ui' + # everywhere to maintain compatibility across versions + if not hgutil.safehasattr(self, 'ui'): + self.ui = ctx._repo.ui def get(self, state, *args, **kwargs): # Resolve source first @@ -398,11 +402,11 @@ class svnsubrepo(subrepo.svnsubrepo): try: # Getting the root SVN repository URL is expensive. # Assume the externals is absolute. - source = resolvesource(self._ui, None, source) + source = resolvesource(self.ui, None, source) except RelativeSourceError: svnurl = self._ctx._repo.ui.expandpath('default') svnroot = getsvninfo(util.normalize_url(svnurl))[1] - source = resolvesource(self._ui, svnroot, source) + source = resolvesource(self.ui, svnroot, source) # hg 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 diff --git a/hgsubversion/svnmeta.py b/hgsubversion/svnmeta.py --- a/hgsubversion/svnmeta.py +++ b/hgsubversion/svnmeta.py @@ -22,44 +22,47 @@ class SVNMeta(object): subdir is the subdirectory of the edits *on the svn server*. It is needed for stripping paths off in certain cases. """ + # simple and public variables self.ui = repo.ui self.repo = repo self.path = os.path.normpath(repo.join('..')) + self.firstpulled = 0 + self.lastdate = '1970-01-01 00:00:00 -0000' + self.addedtags = {} + self.deletedtags = {} + + # private variables self._skiperror = skiperrorcheck + self._tags = None + self._layoutobj = None + self._revmap = None + self._authors = None + self._branchmap = None + self._tagmap = None + self._filemap = None + # create .hg/svn folder if it doesn't exist if not os.path.isdir(self.metapath): os.makedirs(self.metapath) + + # properties that need .hg/svn to exist self.uuid = uuid self.subdir = subdir - self._revmap = None - self.firstpulled = 0 + # generated properties that have a persistent file stored on disk self._gen_cachedconfig('lastpulled', 0, configname=False) self._gen_cachedconfig('defaultauthors', True) self._gen_cachedconfig('caseignoreauthors', False) self._gen_cachedconfig('defaulthost', self.uuid) self._gen_cachedconfig('usebranchnames', True) + self._gen_cachedconfig('defaultmessage', '') + # misc self.branches = util.load(self.branch_info_file) or {} self.prevbranches = dict(self.branches) - self._tags = None - self._layout = layouts.detect.layout_from_file(self.metapath, - ui=self.repo.ui) - self._layoutobj = None - - self._authors = None - - self._branchmap = None - - self._tagmap = None - - self._filemap = None - - self.lastdate = '1970-01-01 00:00:00 -0000' - self.addedtags = {} - self.deletedtags = {} + self._layout = layouts.detect.layout_from_file(self) - def _get_cachedconfig(self, name, filename, configname, default): + def _get_cachedconfig(self, name, filename, configname, default, pre): """Return a cached value for a config option. If the cache is uninitialized then try to read its value from disk. Option can be overridden by the commandline. @@ -67,6 +70,7 @@ class SVNMeta(object): filename: name of file in .hg/svn configname: commandline option name default: default value + pre: transformation to apply to a value before caching it. """ varname = '_' + name if getattr(self, varname) is None: @@ -97,6 +101,10 @@ class SVNMeta(object): if c is not None and c != val and c != default: val = c + # apply transformation if necessary + if pre: + val = pre(val) + # set the value as the one from disk (or default if not found) setattr(self, varname, val) @@ -112,7 +120,7 @@ class SVNMeta(object): util.dump(value, f) def _gen_cachedconfig(self, name, default=None, filename=None, - configname=None): + configname=None, pre=None): """Generate an attribute for reading (and caching) config data. This method constructs a new attribute on self with the given name. @@ -125,29 +133,34 @@ class SVNMeta(object): filename = name if configname is None: configname = name - prop = property(lambda x: x._get_cachedconfig(name, - filename, - configname, - default), - lambda x, y: x._set_cachedconfig(y, - name, - filename)) + prop = property(lambda x: self._get_cachedconfig(name, + filename, + configname, + default, + pre=pre), + lambda x, y: self._set_cachedconfig(y, + name, + filename)) setattr(SVNMeta, name, prop) + @property + def layout_file(self): + return os.path.join(self.metapath, 'layout') + @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': - self._layout = layouts.detect.layout_from_config(self.repo.ui) - layouts.persist.layout_to_file(self.metapath, self._layout) + self._layout = layouts.detect.layout_from_config(self) + util.dump(self._layout, self.layout_file) return self._layout @property def layoutobj(self): if not self._layoutobj: - self._layoutobj = layouts.layout_from_name(self.layout, self.ui) + self._layoutobj = layouts.layout_from_name(self.layout, self) return self._layoutobj @property @@ -350,9 +363,19 @@ class SVNMeta(object): path = path[1:] return path - @property - def taglocations(self): - return self.layoutobj.taglocations(self.metapath) + def getmessage(self, rev): + msg = rev.message + + if msg: + try: + msg.decode('utf-8') + return msg + + except UnicodeDecodeError: + # ancient svn failed to enforce utf8 encoding + return msg.decode('iso-8859-1').encode('utf-8') + else: + return self.defaultmessage def get_path_tag(self, path): """If path could represent the path to a tag, returns the @@ -362,7 +385,7 @@ class SVNMeta(object): (or tag) we have, for our purposes. """ path = self.normalize(path) - return self.layoutobj.get_path_tag(path, self.taglocations) + return self.layoutobj.get_path_tag(path, self.layoutobj.taglocations) def split_branch_path(self, path, existing=True): """Figure out which branch inside our repo this path represents, and @@ -694,7 +717,7 @@ class SVNMeta(object): revnum, branch = self.get_source_rev(ctx=parentctx)[:2] ctx = context.memctx(self.repo, (parentctx.node(), node.nullid), - util.getmessage(self.ui, rev), + self.getmessage(rev), ['.hgtags', ], hgtagsfn, self.authors[rev.author], @@ -762,7 +785,7 @@ class SVNMeta(object): ctx = context.memctx(self.repo, (parent.node(), node.nullid), - util.getmessage(self.ui, rev), + self.getmessage(rev), ['.hgtags'], fctxfun, self.authors[rev.author], @@ -784,7 +807,7 @@ class SVNMeta(object): self.mapbranch(extra, True) ctx = context.memctx(self.repo, (node, revlog.nullid), - util.getmessage(self.ui, rev), + self.getmessage(rev), [], lambda x, y, z: None, self.authors[rev.author], diff --git a/hgsubversion/util.py b/hgsubversion/util.py --- a/hgsubversion/util.py +++ b/hgsubversion/util.py @@ -251,20 +251,6 @@ def outgoing_common_and_heads(repo, reve return ([sourcecx.node()], [sourcerev]) return ([sourcerev], [sourcerev]) # nothing outgoing -def getmessage(ui, rev): - msg = rev.message - - if msg: - try: - msg.decode('utf-8') - return msg - - except UnicodeDecodeError: - # ancient svn failed to enforce utf8 encoding - return msg.decode('iso-8859-1').encode('utf-8') - else: - return ui.config('hgsubversion', 'defaultmessage', '') - def describe_commit(ui, h, b): ui.note(' committed to "%s" as %s\n' % ((b or 'default'), node.short(h))) diff --git a/hgsubversion/wrappers.py b/hgsubversion/wrappers.py --- a/hgsubversion/wrappers.py +++ b/hgsubversion/wrappers.py @@ -261,6 +261,8 @@ def push(repo, dest, force, revs): # Don't trust the pre-rebase repo and context. repo = getlocalpeer(ui, {}, meta.path) + meta = repo.svnmeta(svn.uuid, svn.subdir) + hashes = meta.revmap.hashes() tip_ctx = repo[tip_ctx.node()] for c in tip_ctx.descendants(): rebasesrc = c.extra().get('rebase_source') @@ -289,10 +291,8 @@ def push(repo, dest, force, revs): # 5. Pull the latest changesets from subversion, which will # include the one we just committed (and possibly others). - r = pull(repo, dest, force=force) + r = pull(repo, dest, force=force, meta=meta) assert not r or r == 0 - meta = repo.svnmeta(svn.uuid, svn.subdir) - hashes = meta.revmap.hashes() # 6. Move our tip to the latest pulled tip for c in tip_ctx.descendants(): @@ -379,7 +379,7 @@ def exchangepush(orig, repo, remote, for else: return orig(repo, remote, force, revs, newbranch, bookmarks=bookmarks) -def pull(repo, source, heads=[], force=False): +def pull(repo, source, heads=[], force=False, meta=None): """pull new revisions from Subversion""" assert source.capable('subversion') svn_url = source.svnurl @@ -394,15 +394,16 @@ def pull(repo, source, heads=[], force=F repo.ui.note('fetching stupidly...\n') svn = source.svn - meta = repo.svnmeta(svn.uuid, svn.subdir) + if meta is None: + meta = repo.svnmeta(svn.uuid, svn.subdir) stopat_rev = util.parse_revnum(svn, checkout) - layout = layouts.detect.layout_from_config(repo.ui, allow_auto=True) + layout = layouts.detect.layout_from_config(meta, allow_auto=True) if layout == 'auto': layout = layouts.detect.layout_from_subversion(svn, (stopat_rev or None), - repo.ui) + meta) repo.ui.note('using %s layout\n' % layout) branch = repo.ui.config('hgsubversion', 'branch') @@ -461,7 +462,7 @@ def pull(repo, source, heads=[], force=F converted = False while not converted: try: - msg = util.getmessage(ui, r).strip() + msg = meta.getmessage(r).strip() if msg: msg = [s.strip() for s in msg.splitlines() if s][0] if getattr(ui, 'termwidth', False):