# HG changeset patch # User Augie Fackler # Date 1462975919 14400 # Node ID 85981b27e740227c8e58c0911c21c25309e17256 # Parent c79fdd5f615da63d1fdfbb2f929745c6bd0fd107# Parent fc80c25bc94bf3e87bb52922cfeac78b62fe9fbc Merge with stable. diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -20,3 +20,4 @@ 38be7a6b6def3298fe9ffff141eb58e1370a53cc 759cafce6becef077fb1a152b554a05ff66b04cd 1.8.3 89997a5fc18163c5f65b83272b4521cdbf29984e 1.8.4 bd979667611d9df733c61251e7668899f3e77a8f 1.8.5 +49d324e11856f5d65bd7f83f7ffb3a2f07bf82c1 1.8.6 diff --git a/hgsubversion/__init__.py b/hgsubversion/__init__.py --- a/hgsubversion/__init__.py +++ b/hgsubversion/__init__.py @@ -15,7 +15,7 @@ details. For more information and instructions, see :hg:`help subversion`. ''' -testedwith = '2.8.2 3.0.1 3.1 3.2.2 3.3 3.4 3.5 3.6 3.7' +testedwith = '2.8.2 3.0.1 3.1 3.2.2 3.3 3.4 3.5 3.6 3.7 3.8' import os import sys @@ -42,7 +42,6 @@ demandimport.ignore.extend([ 'svn.ra', ]) -from mercurial import templatekw from mercurial import revset from mercurial import subrepo @@ -51,6 +50,7 @@ import util import svnrepo import wrappers import svnexternals +import compathacks svnopts = [ ('', 'stupid', None, @@ -165,8 +165,6 @@ def extsetup(ui): help.helptable.extend(entries) - templatekw.keywords.update(util.templatekeywords) - revset.symbols.update(util.revsets) subrepo.types['hgsubversion'] = svnexternals.svnsubrepo @@ -219,3 +217,74 @@ cmdtable = { # only these methods are public __all__ = ('cmdtable', 'reposetup', 'uisetup') + +# set up templatekeywords (written this way to maintain backwards compatibility +# until we drop support for 3.7) +try: + from mercurial import registrar + templatekeyword = registrar.templatekeyword() + loadkeyword = lambda registrarobj: None # no-op +except (ImportError, AttributeError): + # registrar.templatekeyword isn't available = loading by old hg + + templatekeyword = compathacks._funcregistrarbase() + templatekeyword._docformat = ":%s: %s" + + # minimum copy from templatekw.loadkeyword + def loadkeyword(registrarobj): + from mercurial import templatekw + for name, func in registrarobj._table.iteritems(): + templatekw.keywords[name] = func + +def _templatehelper(ctx, kw): + ''' + Helper function for displaying information about converted changesets. + ''' + convertinfo = util.getsvnrev(ctx, '') + + if not convertinfo or not convertinfo.startswith('svn:'): + return '' + + if kw == 'svnuuid': + return convertinfo[4:40] + elif kw == 'svnpath': + return convertinfo[40:].rsplit('@', 1)[0] + elif kw == 'svnrev': + return convertinfo[40:].rsplit('@', 1)[-1] + else: + raise hgutil.Abort('unrecognized hgsubversion keyword %s' % kw) + +@templatekeyword('svnrev') +def svnrevkw(**args): + """:svnrev: String. Converted subversion revision number.""" + return _templatehelper(args['ctx'], 'svnrev') + +@templatekeyword('svnpath') +def svnpathkw(**args): + """:svnpath: String. Converted subversion revision project path.""" + return _templatehelper(args['ctx'], 'svnpath') + +@templatekeyword('svnuuid') +def svnuuidkw(**args): + """:svnuuid: String. Converted subversion revision repository identifier.""" + return _templatehelper(args['ctx'], 'svnuuid') + +def listsvnkeys(repo): + keys = {} + repo = repo.local() + metadir = os.path.join(repo.path, 'svn') + + if util.subversionmetaexists(repo.path): + w = repo.wlock() + try: + for key in util.pushkeyfiles: + fullpath = os.path.join(metadir, key) + if os.path.isfile(fullpath): + data = open(fullpath).read() + + # Some of the files could be large, but also quite compressible + keys[key] = base85.b85encode(zlib.compress(data)) + finally: + w.release() + + return keys diff --git a/hgsubversion/compathacks.py b/hgsubversion/compathacks.py --- a/hgsubversion/compathacks.py +++ b/hgsubversion/compathacks.py @@ -3,6 +3,8 @@ import errno import sys +from mercurial import util + def branchset(repo): """Return the set of branches present in a repo. @@ -67,3 +69,83 @@ def filectxfn_deleted_reraise(memctx): return None # preserve traceback info raise exc_info[0], exc_info[1], exc_info[2] + +# copied from hg 3.8 +class _funcregistrarbase(object): + """Base of decorator to register a fuction for specific purpose + + This decorator stores decorated functions into own dict 'table'. + + The least derived class can be defined by overriding 'formatdoc', + for example:: + + class keyword(_funcregistrarbase): + _docformat = ":%s: %s" + + This should be used as below: + + keyword = registrar.keyword() + + @keyword('bar') + def barfunc(*args, **kwargs): + '''Explanation of bar keyword .... + ''' + pass + + In this case: + + - 'barfunc' is stored as 'bar' in '_table' of an instance 'keyword' above + - 'barfunc.__doc__' becomes ":bar: Explanation of bar keyword" + """ + def __init__(self, table=None): + if table is None: + self._table = {} + else: + self._table = table + + def __call__(self, decl, *args, **kwargs): + return lambda func: self._doregister(func, decl, *args, **kwargs) + + def _doregister(self, func, decl, *args, **kwargs): + name = self._getname(decl) + + if func.__doc__ and not util.safehasattr(func, '_origdoc'): + doc = func.__doc__.strip() + func._origdoc = doc + func.__doc__ = self._formatdoc(decl, doc) + + self._table[name] = func + self._extrasetup(name, func, *args, **kwargs) + + return func + + def _parsefuncdecl(self, decl): + """Parse function declaration and return the name of function in it + """ + i = decl.find('(') + if i >= 0: + return decl[:i] + else: + return decl + + def _getname(self, decl): + """Return the name of the registered function from decl + + Derived class should override this, if it allows more + descriptive 'decl' string than just a name. + """ + return decl + + _docformat = None + + def _formatdoc(self, decl, doc): + """Return formatted document of the registered function for help + + 'doc' is '__doc__.strip()' of the registered function. + """ + return self._docformat % (decl, doc) + + def _extrasetup(self, name, func): + """Execute exra setup for registered function, if needed + """ + pass diff --git a/hgsubversion/svnexternals.py b/hgsubversion/svnexternals.py --- a/hgsubversion/svnexternals.py +++ b/hgsubversion/svnexternals.py @@ -457,10 +457,17 @@ def parse(ui, ctx): raise hgutil.Abort(_('unknown externals modes: %s') % mode) return external +_notset = object() + class svnsubrepo(subrepo.svnsubrepo): - def __init__(self, ctx, path, state): + def __init__(self, ctx, path, state, allowcreate=_notset): state = (state[0].split(':', 1)[1], state[1]) - super(svnsubrepo, self).__init__(ctx, path, state) + if allowcreate is _notset: + # Mercurial 3.7 and earlier + super(svnsubrepo, self).__init__(ctx, path, state) + else: + # Mercurial 3.8 and later + super(svnsubrepo, self).__init__(ctx, path, state, allowcreate) # 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'): diff --git a/hgsubversion/util.py b/hgsubversion/util.py --- a/hgsubversion/util.py +++ b/hgsubversion/util.py @@ -307,48 +307,10 @@ def issamefile(parentctx, childctx, f): # parentctx is not an ancestor of childctx, files are unrelated return False - def getsvnrev(ctx, defval=None): '''Extract SVN revision from commit metadata''' return ctx.extra().get('convert_revision', defval) - -def _templatehelper(ctx, kw): - ''' - Helper function for displaying information about converted changesets. - ''' - convertinfo = getsvnrev(ctx, '') - - if not convertinfo or not convertinfo.startswith('svn:'): - return '' - - if kw == 'svnuuid': - return convertinfo[4:40] - elif kw == 'svnpath': - return convertinfo[40:].rsplit('@', 1)[0] - elif kw == 'svnrev': - return convertinfo[40:].rsplit('@', 1)[-1] - 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': svnrevkw, - 'svnpath': svnpathkw, - 'svnuuid': svnuuidkw, -} - def revset_fromsvn(repo, subset, x): '''``fromsvn()`` Select changesets that originate from Subversion.