diff --git a/hgext/convert/__init__.py b/hgext/convert/__init__.py --- a/hgext/convert/__init__.py +++ b/hgext/convert/__init__.py @@ -29,7 +29,7 @@ testedwith = 'internal' _('FILE')), ('s', 'source-type', '', _('source repository type'), _('TYPE')), ('d', 'dest-type', '', _('destination repository type'), _('TYPE')), - ('r', 'rev', '', _('import up to source revision REV'), _('REV')), + ('r', 'rev', [], _('import up to source revision REV'), _('REV')), ('A', 'authormap', '', _('remap usernames using this file'), _('FILE')), ('', 'filemap', '', _('remap file names using contents of file'), _('FILE')), diff --git a/hgext/convert/bzr.py b/hgext/convert/bzr.py --- a/hgext/convert/bzr.py +++ b/hgext/convert/bzr.py @@ -33,8 +33,8 @@ supportedkinds = ('file', 'symlink') class bzr_source(converter_source): """Reads Bazaar repositories by using the Bazaar Python libraries""" - def __init__(self, ui, path, rev=None): - super(bzr_source, self).__init__(ui, path, rev=rev) + def __init__(self, ui, path, revs=None): + super(bzr_source, self).__init__(ui, path, revs=revs) if not os.path.exists(os.path.join(path, '.bzr')): raise NoRepo(_('%s does not look like a Bazaar repository') @@ -95,20 +95,20 @@ class bzr_source(converter_source): return self.sourcerepo.find_branches(using=True) def getheads(self): - if not self.rev: + if not self.revs: # Set using=True to avoid nested repositories (see issue3254) heads = sorted([b.last_revision() for b in self._bzrbranches()]) else: revid = None for branch in self._bzrbranches(): try: - r = RevisionSpec.from_string(self.rev) + r = RevisionSpec.from_string(self.revs[0]) info = r.in_history(branch) except errors.BzrError: pass revid = info.rev_id if revid is None: - raise util.Abort(_('%s is not a valid revision') % self.rev) + raise util.Abort(_('%s is not a valid revision') % self.revs[0]) heads = [revid] # Empty repositories return 'null:', which cannot be retrieved heads = [h for h in heads if h != 'null:'] diff --git a/hgext/convert/common.py b/hgext/convert/common.py --- a/hgext/convert/common.py +++ b/hgext/convert/common.py @@ -59,12 +59,12 @@ class commit(object): class converter_source(object): """Conversion source interface""" - def __init__(self, ui, path=None, rev=None): + def __init__(self, ui, path=None, revs=None): """Initialize conversion source (or raise NoRepo("message") exception if path is not a valid repository)""" self.ui = ui self.path = path - self.rev = rev + self.revs = revs self.encoding = 'utf-8' diff --git a/hgext/convert/convcmd.py b/hgext/convert/convcmd.py --- a/hgext/convert/convcmd.py +++ b/hgext/convert/convcmd.py @@ -46,14 +46,14 @@ sink_converters = [ ('svn', svn_sink), ] -def convertsource(ui, path, type, rev): +def convertsource(ui, path, type, revs): exceptions = [] if type and type not in [s[0] for s in source_converters]: raise util.Abort(_('%s: invalid source repository type') % type) for name, source, sortmode in source_converters: try: if not type or name == type: - return source(ui, path, rev), sortmode + return source(ui, path, revs), sortmode except (NoRepo, MissingTool) as inst: exceptions.append(inst) if not ui.quiet: diff --git a/hgext/convert/cvs.py b/hgext/convert/cvs.py --- a/hgext/convert/cvs.py +++ b/hgext/convert/cvs.py @@ -15,8 +15,8 @@ from common import makedatetimestamp import cvsps class convert_cvs(converter_source): - def __init__(self, ui, path, rev=None): - super(convert_cvs, self).__init__(ui, path, rev=rev) + def __init__(self, ui, path, revs=None): + super(convert_cvs, self).__init__(ui, path, revs=revs) cvs = os.path.join(path, "CVS") if not os.path.exists(cvs): @@ -41,14 +41,17 @@ class convert_cvs(converter_source): self.changeset = {} maxrev = 0 - if self.rev: + if self.revs: + if len(self.revs) > 1: + raise util.Abort(_('cvs source does not support specifying ' + 'multiple revs')) # TODO: handle tags try: # patchset number? - maxrev = int(self.rev) + maxrev = int(self.revs[0]) except ValueError: raise util.Abort(_('revision %s is not a patchset number') - % self.rev) + % self.revs[0]) d = os.getcwd() try: diff --git a/hgext/convert/darcs.py b/hgext/convert/darcs.py --- a/hgext/convert/darcs.py +++ b/hgext/convert/darcs.py @@ -27,8 +27,8 @@ except ImportError: pass class darcs_source(converter_source, commandline): - def __init__(self, ui, path, rev=None): - converter_source.__init__(self, ui, path, rev=rev) + def __init__(self, ui, path, revs=None): + converter_source.__init__(self, ui, path, revs=revs) commandline.__init__(self, ui, 'darcs') # check for _darcs, ElementTree so that we can easily skip diff --git a/hgext/convert/git.py b/hgext/convert/git.py --- a/hgext/convert/git.py +++ b/hgext/convert/git.py @@ -86,8 +86,12 @@ class convert_git(converter_source): data = fh.read() return data, fh.close() - def __init__(self, ui, path, rev=None): - super(convert_git, self).__init__(ui, path, rev=rev) + def __init__(self, ui, path, revs=None): + super(convert_git, self).__init__(ui, path, revs=revs) + + if revs and len(revs) > 1: + raise util.Abort(_("git source does not support specifying " + "multiple revs")) if os.path.isdir(path + "/.git"): path += "/.git" @@ -119,11 +123,12 @@ class convert_git(converter_source): f.close() def getheads(self): - if not self.rev: + if not self.revs: heads, ret = self.gitread('git rev-parse --branches --remotes') heads = heads.splitlines() else: - heads, ret = self.gitread("git rev-parse --verify %s" % self.rev) + heads, ret = self.gitread("git rev-parse --verify %s" % + self.revs[0]) heads = [heads[:-1]] if ret: raise util.Abort(_('cannot retrieve git heads')) diff --git a/hgext/convert/gnuarch.py b/hgext/convert/gnuarch.py --- a/hgext/convert/gnuarch.py +++ b/hgext/convert/gnuarch.py @@ -27,8 +27,8 @@ class gnuarch_source(converter_source, c self.ren_files = {} self.ren_dirs = {} - def __init__(self, ui, path, rev=None): - super(gnuarch_source, self).__init__(ui, path, rev=rev) + def __init__(self, ui, path, revs=None): + super(gnuarch_source, self).__init__(ui, path, revs=revs) if not os.path.exists(os.path.join(path, '{arch}')): raise NoRepo(_("%s does not look like a GNU Arch repository") diff --git a/hgext/convert/hg.py b/hgext/convert/hg.py --- a/hgext/convert/hg.py +++ b/hgext/convert/hg.py @@ -372,8 +372,11 @@ class mercurial_sink(converter_sink): return rev in self.repo class mercurial_source(converter_source): - def __init__(self, ui, path, rev=None): - converter_source.__init__(self, ui, path, rev) + def __init__(self, ui, path, revs=None): + converter_source.__init__(self, ui, path, revs) + if revs and len(revs) > 1: + raise util.Abort(_("mercurial source does not support specifying " + "multiple revisions")) self.ignoreerrors = ui.configbool('convert', 'hg.ignoreerrors', False) self.ignored = set() self.saverev = ui.configbool('convert', 'hg.saverev', False) @@ -407,12 +410,12 @@ class mercurial_source(converter_source) self.keep = children.__contains__ else: self.keep = util.always - if rev: - self._heads = [self.repo[rev].node()] + if revs: + self._heads = [self.repo[revs[0]].node()] else: self._heads = self.repo.heads() else: - if rev or startnode is not None: + if revs or startnode is not None: raise util.Abort(_('hg.revs cannot be combined with ' 'hg.startrev or --rev')) nodes = set() diff --git a/hgext/convert/monotone.py b/hgext/convert/monotone.py --- a/hgext/convert/monotone.py +++ b/hgext/convert/monotone.py @@ -13,14 +13,17 @@ from common import commandline from mercurial.i18n import _ class monotone_source(converter_source, commandline): - def __init__(self, ui, path=None, rev=None): - converter_source.__init__(self, ui, path, rev) + def __init__(self, ui, path=None, revs=None): + converter_source.__init__(self, ui, path, revs) + if revs and len(revs) > 1: + raise util.Abort(_('monotone source does not support specifying ' + 'multiple revs')) commandline.__init__(self, ui, 'mtn') self.ui = ui self.path = path self.automatestdio = False - self.rev = rev + self.revs = revs norepo = NoRepo(_("%s does not look like a monotone repository") % path) @@ -219,10 +222,10 @@ class monotone_source(converter_source, # implement the converter_source interface: def getheads(self): - if not self.rev: + if not self.revs: return self.mtnrun("leaves").splitlines() else: - return [self.rev] + return self.revs def getchanges(self, rev, full): if full: diff --git a/hgext/convert/p4.py b/hgext/convert/p4.py --- a/hgext/convert/p4.py +++ b/hgext/convert/p4.py @@ -24,8 +24,8 @@ def loaditer(f): pass class p4_source(converter_source): - def __init__(self, ui, path, rev=None): - super(p4_source, self).__init__(ui, path, rev=rev) + def __init__(self, ui, path, revs=None): + super(p4_source, self).__init__(ui, path, revs=revs) if "/" in path and not path.startswith('//'): raise NoRepo(_('%s does not look like a P4 repository') % path) @@ -49,6 +49,9 @@ class p4_source(converter_source): r":[^$\n]*\$") self.re_keywords_old = re.compile("\$(Id|Header):[^$\n]*\$") + if revs and len(revs) > 1: + raise util.Abort(_("p4 source does not support specifying " + "multiple revisions")) self._parse(ui, path) def _parse_view(self, path): @@ -99,7 +102,7 @@ class p4_source(converter_source): startrev = self.ui.config('convert', 'p4.startrev', default=0) self.p4changes = [x for x in self.p4changes if ((not startrev or int(x) >= int(startrev)) and - (not self.rev or int(x) <= int(self.rev)))] + (not self.revs or int(x) <= int(self.revs[0])))] # now read the full changelists to get the list of file revisions ui.status(_('collecting p4 changelists\n')) diff --git a/hgext/convert/subversion.py b/hgext/convert/subversion.py --- a/hgext/convert/subversion.py +++ b/hgext/convert/subversion.py @@ -268,8 +268,8 @@ def issvnurl(ui, url): # the parent module. A revision has at most one parent. # class svn_source(converter_source): - def __init__(self, ui, url, rev=None): - super(svn_source, self).__init__(ui, url, rev=rev) + def __init__(self, ui, url, revs=None): + super(svn_source, self).__init__(ui, url, revs=revs) if not (url.startswith('svn://') or url.startswith('svn+ssh://') or (os.path.exists(url) and @@ -325,11 +325,15 @@ class svn_source(converter_source): "to libsvn version %s") % (self.url, svnversion)) - if rev: + if revs: + if len(revs) > 1: + raise util.Abort(_('subversion source does not support ' + 'specifying multiple revisions')) try: - latest = int(rev) + latest = int(revs[0]) except ValueError: - raise util.Abort(_('svn: revision %s is not an integer') % rev) + raise util.Abort(_('svn: revision %s is not an integer') % + revs[0]) self.trunkname = self.ui.config('convert', 'svn.trunk', 'trunk').strip('/') diff --git a/tests/test-convert.t b/tests/test-convert.t --- a/tests/test-convert.t +++ b/tests/test-convert.t @@ -304,11 +304,11 @@ does not convert tags from the source repo to the target repo. The default is False. - options: + options ([+] can be repeated): -s --source-type TYPE source repository type -d --dest-type TYPE destination repository type - -r --rev REV import up to source revision REV + -r --rev REV [+] import up to source revision REV -A --authormap FILE remap usernames using this file --filemap FILE remap file names using contents of file --full apply filemap changes by converting all files again