def get_repo(remote): if not changegroup or experiment('wire'): if not changegroup: logging.warning('Mercurial libraries not found. Falling back to ' 'native access.') logging.warning( 'Native access to mercurial repositories is experimental!') stream = HgRepoHelper.connect(remote.url) if stream: return bundlerepo(remote.url, stream) return HelperRepo(remote.url) if remote.parsed_url.scheme == 'file': path = remote.parsed_url.path if sys.platform == 'win32': # TODO: This probably needs more thought. path = path.lstrip('/') if not os.path.isdir(path): return bundlerepo(path) ui = get_ui() if changegroup and remote.parsed_url.scheme == 'file': repo = localpeer(ui, path) else: try: repo = hg.peer(ui, {}, remote.url) except (error.RepoError, urllib2.HTTPError, IOError): return bundlerepo(remote.url, url.open(ui, remote.url)) assert repo.capable('getbundle') return repo
def main(argv=None): if argv is None: argv = sys.argv parser = OptionParser() (options, args) = parser.parse_args() myui = ui.ui() repo = hg.repository(myui, '.') if len(args) == 0: # we should use the current diff, or if that is empty, the top applied # patch in the patch queue myui.pushbuffer() commands.diff(myui, repo, git=True) diff = myui.popbuffer() changedFiles = fileRe.findall(diff) if len(changedFiles) == 0: print("Patch source: top patch in mq queue") myui.pushbuffer() commands.diff(myui, repo, change="qtip", git=True) diff = myui.popbuffer() else: print("Patch source: current diff") else: diff = url.open(myui, args[0]).read() print("Patch source: %s" % args[0]) changedFiles = fileRe.findall(diff) changes = {} for changedFile in changedFiles: changes[changedFile] = [] for revNum in xrange(len(repo) - SEARCH_DEPTH, len(repo)): rev = repo[revNum] for file in changedFiles: if file in rev.files(): changes[file].append(rev) suckers = Counter() supersuckers = Counter() for file in changes: for change in changes[file]: suckers.update(canon(x) for x in suckerRe.findall(change.description())) supersuckers.update(canon(x) for x in supersuckerRe.findall(change.description())) print "Potential reviewers:" for (reviewer, count) in suckers.most_common(10): print " %s: %d" % (reviewer, count) print print "Potential super-reviewers:" for (reviewer, count) in supersuckers.most_common(10): print " %s: %d" % (reviewer, count) print return 0
def _fetch(self, burl): try: resp = url.open(self.ui, burl) return json.loads(resp.read()) except util.urlerr.httperror as inst: if inst.code == 401: raise error.Abort(_('authorization failed')) if inst.code == 404: raise NotFound() else: raise
def clone(self, remote, heads=[], stream=False): supported = True if not remote.capable('bundles'): supported = False self.ui.debug(_('bundle clone not supported\n')) elif heads: supported = False self.ui.debug(_('cannot perform bundle clone if heads requested\n')) if not supported: return super(bundleclonerepo, self).clone(remote, heads=heads, stream=stream) result = remote._call('bundles') if not result: self.ui.note(_('no bundles available; using normal clone\n')) return super(bundleclonerepo, self).clone(remote, heads=heads, stream=stream) # Eventually we'll support choosing the best options. Until then, # use the first entry. entry = result.splitlines()[0] fields = entry.split() url = fields[0] if not url: self.ui.note(_('invalid bundle manifest; using normal clone\n')) return super(bundleclonerepo, self).clone(remote, heads=heads, stream=stream) self.ui.status(_('downloading bundle %s\n' % url)) try: fh = hgurl.open(self.ui, url) cg = exchange.readbundle(self.ui, fh, 'stream') changegroup.addchangegroup(self, cg, 'bundleclone', url) self.ui.status(_('finishing applying bundle; pulling\n')) return exchange.pull(self, remote, heads=heads) except urllib2.HTTPError as e: self.ui.warn(_('HTTP error fetching bundle; using normal clone: %s\n') % str(e)) return super(bundleclonerepo, self).clone(remote, heads=heads, stream=stream) # This typically means a connectivity, DNS, etc problem. except urllib2.URLError as e: self.ui.warn(_('error fetching bundle; using normal clone: %s\n') % e.reason) return super(bundleclonerepo, self).clone(remote, heads=heads, stream=stream)
changedFiles = fileRe.findall(diff) if len(changedFiles) > 0: source = "current diff" elif repo.mq: source = "top patch in mq queue" ui.pushbuffer() try: commands.diff(ui, repo, change="qtip", git=True) except error.RepoLookupError, e: raise util.Abort("no current diff, no mq patch to use") diff = ui.popbuffer() else: raise util.Abort("no changes found") else: try: diff = url.open(ui, patchfile).read() source = "patch file %s" % patchfile except IOError, e: q = repo.mq if q: diff = url.open(ui, q.lookup(patchfile)).read() source = "mq patch %s" % patchfile else: pass changedFiles = fileRe.findall(diff) if ui.verbose: ui.write("Patch source: %s\n" % source) if len(changedFiles) == 0: ui.write("Warning: no modified files found in patch. Did you mean to use the -f option?\n")
def clone(self, remote, heads=[], stream=False): supported = True if (exchange and hasattr(exchange, '_maybeapplyclonebundle') and remote.capable('clonebundles')): supported = False self.ui.warn( _('(mercurial client has built-in support for ' 'bundle clone features; the "bundleclone" ' 'extension can likely safely be removed)\n')) if not self.ui.configbool('experimental', 'clonebundles', False): self.ui.warn( _('(but the experimental.clonebundles config ' 'flag is not enabled: enable it before ' 'disabling bundleclone or cloning from ' 'pre-generated bundles may not work)\n')) # We assume that presence of the bundleclone extension # means they want clonebundles enabled. Otherwise, why do # they have bundleclone enabled? So silently enable it. ui.setconfig('experimental', 'clonebundles', True) elif not remote.capable('bundles'): supported = False self.ui.debug(_('bundle clone not supported\n')) elif heads: supported = False self.ui.debug( _('cannot perform bundle clone if heads requested\n')) elif stream: supported = False self.ui.debug( _('ignoring bundle clone because stream was ' 'requested\n')) if not supported: return super(bundleclonerepo, self).clone(remote, heads=heads, stream=stream) result = remote._call('bundles') if not result: self.ui.note(_('no bundles available; using normal clone\n')) return super(bundleclonerepo, self).clone(remote, heads=heads, stream=stream) pyver = sys.version_info pyver = (pyver[0], pyver[1], pyver[2]) hgver = util.version() # Discard bit after '+'. hgver = hgver.split('+')[0] try: hgver = tuple([int(i) for i in hgver.split('.')[0:2]]) except ValueError: hgver = (0, 0) # Testing backdoors. if ui.config('bundleclone', 'fakepyver'): pyver = ui.configlist('bundleclone', 'fakepyver') pyver = tuple(int(v) for v in pyver) if ui.config('bundleclone', 'fakehgver'): hgver = ui.configlist('bundleclone', 'fakehgver') hgver = tuple(int(v) for v in hgver[0:2]) entries = [] snifilteredfrompython = False snifilteredfromhg = False for line in result.splitlines(): fields = line.split() url = fields[0] attrs = {} for rawattr in fields[1:]: key, value = rawattr.split('=', 1) attrs[urllib.unquote(key)] = urllib.unquote(value) # Filter out SNI entries if we don't support SNI. if attrs.get('requiresni') == 'true': skip = False if pyver < (2, 7, 9): # Take this opportunity to inform people they are using an # old, insecure Python. if not snifilteredfrompython: self.ui.warn( _('(your Python is older than 2.7.9 ' 'and does not support modern and ' 'secure SSL/TLS; please consider ' 'upgrading your Python to a secure ' 'version)\n')) snifilteredfrompython = True skip = True if hgver < (3, 3): if not snifilteredfromhg: self.ui.warn( _('(you Mercurial is old and does ' 'not support modern and secure ' 'SSL/TLS; please consider ' 'upgrading your Mercurial to 3.3+ ' 'which supports modern and secure ' 'SSL/TLS)\n')) snifilteredfromhg = True skip = True if skip: self.ui.warn( _('(ignoring URL on server that requires ' 'SNI)\n')) continue entries.append((url, attrs)) if not entries: # Don't fall back to normal clone because we don't want mass # fallback in the wild to barage servers expecting bundle # offload. raise util.Abort(_('no appropriate bundles available'), hint=_('you may wish to complain to the ' 'server operator')) # The configuration is allowed to define lists of preferred # attributes and values. If this is present, sort results according # to that preference. Otherwise, use manifest order and select the # first entry. prefers = self.ui.configlist('bundleclone', 'prefers', default=[]) if prefers: prefers = [p.split('=', 1) for p in prefers] def compareentry(a, b): aattrs = a[1] battrs = b[1] # Itereate over local preferences. for pkey, pvalue in prefers: avalue = aattrs.get(pkey) bvalue = battrs.get(pkey) # Special case for b is missing attribute and a matches # exactly. if avalue is not None and bvalue is None and avalue == pvalue: return -1 # Special case for a missing attribute and b matches # exactly. if bvalue is not None and avalue is None and bvalue == pvalue: return 1 # We can't compare unless the attribute is defined on # both entries. if avalue is None or bvalue is None: continue # Same values should fall back to next attribute. if avalue == bvalue: continue # Exact matches come first. if avalue == pvalue: return -1 if bvalue == pvalue: return 1 # Fall back to next attribute. continue # Entries could not be sorted based on attributes. This # says they are equal, which will fall back to index order, # which is what we want. return 0 entries = sorted(entries, cmp=compareentry) url, attrs = entries[0] if not url: self.ui.note( _('invalid bundle manifest; using normal clone\n')) return super(bundleclonerepo, self).clone(remote, heads=heads, stream=stream) self.ui.status(_('downloading bundle %s\n' % url)) try: fh = hgurl.open(self.ui, url) # Stream clone data is not changegroup data. Handle it # specially. if 'stream' in attrs: reqs = set(attrs['stream'].split(',')) l = fh.readline() filecount, bytecount = map(int, l.split(' ', 1)) self.ui.status(_('streaming all changes\n')) consumev1(self, fh, filecount, bytecount) else: if exchange: cg = exchange.readbundle(self.ui, fh, 'stream') else: cg = changegroup.readbundle(fh, 'stream') # Mercurial 3.6 introduced cgNunpacker.apply(). # Before that, there was changegroup.addchangegroup(). # Before that, there was localrepository.addchangegroup(). if hasattr(cg, 'apply'): cg.apply(self, 'bundleclone', url) elif hasattr(changegroup, 'addchangegroup'): changegroup.addchangegroup(self, cg, 'bundleclone', url) else: self.addchangegroup(cg, 'bundleclone', url) self.ui.status(_('finishing applying bundle; pulling\n')) # Maintain compatibility with Mercurial 2.x. if exchange: return exchange.pull(self, remote, heads=heads) else: return self.pull(remote, heads=heads) except (urllib2.HTTPError, urllib2.URLError) as e: if isinstance(e, urllib2.HTTPError): msg = _('HTTP error fetching bundle: %s') % str(e) else: msg = _('error fetching bundle: %s') % e.reason # Don't fall back to regular clone unless explicitly told to. if not self.ui.configbool('bundleclone', 'fallbackonerror', False): raise util.Abort( msg, hint=_('consider contacting the ' 'server operator if this error persists')) self.ui.warn(msg + '\n') self.ui.warn(_('falling back to normal clone\n')) return super(bundleclonerepo, self).clone(remote, heads=heads, stream=stream)
def clone(self, remote, heads=[], stream=False): supported = True if (exchange and hasattr(exchange, '_maybeapplyclonebundle') and remote.capable('clonebundles')): supported = False self.ui.warn(_('(mercurial client has built-in support for ' 'bundle clone features; the "bundleclone" ' 'extension can likely safely be removed)\n')) if not self.ui.configbool('experimental', 'clonebundles', False): self.ui.warn(_('(but the experimental.clonebundles config ' 'flag is not enabled: enable it before ' 'disabling bundleclone or cloning from ' 'pre-generated bundles may not work)\n')) # We assume that presence of the bundleclone extension # means they want clonebundles enabled. Otherwise, why do # they have bundleclone enabled? So silently enable it. ui.setconfig('experimental', 'clonebundles', True) elif not remote.capable('bundles'): supported = False self.ui.debug(_('bundle clone not supported\n')) elif heads: supported = False self.ui.debug(_('cannot perform bundle clone if heads requested\n')) elif stream: supported = False self.ui.debug(_('ignoring bundle clone because stream was ' 'requested\n')) if not supported: return super(bundleclonerepo, self).clone(remote, heads=heads, stream=stream) result = remote._call('bundles') if not result: self.ui.note(_('no bundles available; using normal clone\n')) return super(bundleclonerepo, self).clone(remote, heads=heads, stream=stream) pyver = sys.version_info pyver = (pyver[0], pyver[1], pyver[2]) hgver = util.version() # Discard bit after '+'. hgver = hgver.split('+')[0] try: hgver = tuple([int(i) for i in hgver.split('.')[0:2]]) except ValueError: hgver = (0, 0) # Testing backdoors. if ui.config('bundleclone', 'fakepyver'): pyver = ui.configlist('bundleclone', 'fakepyver') pyver = tuple(int(v) for v in pyver) if ui.config('bundleclone', 'fakehgver'): hgver = ui.configlist('bundleclone', 'fakehgver') hgver = tuple(int(v) for v in hgver[0:2]) entries = [] snifilteredfrompython = False snifilteredfromhg = False for line in result.splitlines(): fields = line.split() url = fields[0] attrs = {} for rawattr in fields[1:]: key, value = rawattr.split('=', 1) attrs[urllib.unquote(key)] = urllib.unquote(value) # Filter out SNI entries if we don't support SNI. if attrs.get('requiresni') == 'true': skip = False if pyver < (2, 7, 9): # Take this opportunity to inform people they are using an # old, insecure Python. if not snifilteredfrompython: self.ui.warn(_('(your Python is older than 2.7.9 ' 'and does not support modern and ' 'secure SSL/TLS; please consider ' 'upgrading your Python to a secure ' 'version)\n')) snifilteredfrompython = True skip = True if hgver < (3, 3): if not snifilteredfromhg: self.ui.warn(_('(you Mercurial is old and does ' 'not support modern and secure ' 'SSL/TLS; please consider ' 'upgrading your Mercurial to 3.3+ ' 'which supports modern and secure ' 'SSL/TLS)\n')) snifilteredfromhg = True skip = True if skip: self.ui.warn(_('(ignoring URL on server that requires ' 'SNI)\n')) continue entries.append((url, attrs)) if not entries: # Don't fall back to normal clone because we don't want mass # fallback in the wild to barage servers expecting bundle # offload. raise util.Abort(_('no appropriate bundles available'), hint=_('you may wish to complain to the ' 'server operator')) # The configuration is allowed to define lists of preferred # attributes and values. If this is present, sort results according # to that preference. Otherwise, use manifest order and select the # first entry. prefers = self.ui.configlist('bundleclone', 'prefers', default=[]) if prefers: prefers = [p.split('=', 1) for p in prefers] def compareentry(a, b): aattrs = a[1] battrs = b[1] # Itereate over local preferences. for pkey, pvalue in prefers: avalue = aattrs.get(pkey) bvalue = battrs.get(pkey) # Special case for b is missing attribute and a matches # exactly. if avalue is not None and bvalue is None and avalue == pvalue: return -1 # Special case for a missing attribute and b matches # exactly. if bvalue is not None and avalue is None and bvalue == pvalue: return 1 # We can't compare unless the attribute is defined on # both entries. if avalue is None or bvalue is None: continue # Same values should fall back to next attribute. if avalue == bvalue: continue # Exact matches come first. if avalue == pvalue: return -1 if bvalue == pvalue: return 1 # Fall back to next attribute. continue # Entries could not be sorted based on attributes. This # says they are equal, which will fall back to index order, # which is what we want. return 0 entries = sorted(entries, cmp=compareentry) url, attrs = entries[0] if not url: self.ui.note(_('invalid bundle manifest; using normal clone\n')) return super(bundleclonerepo, self).clone(remote, heads=heads, stream=stream) self.ui.status(_('downloading bundle %s\n' % url)) try: fh = hgurl.open(self.ui, url) # Stream clone data is not changegroup data. Handle it # specially. if 'stream' in attrs: reqs = set(attrs['stream'].split(',')) l = fh.readline() filecount, bytecount = map(int, l.split(' ', 1)) self.ui.status(_('streaming all changes\n')) consumev1(self, fh, filecount, bytecount) else: if exchange: cg = exchange.readbundle(self.ui, fh, 'stream') else: cg = changegroup.readbundle(fh, 'stream') # Mercurial 3.6 introduced cgNunpacker.apply(). # Before that, there was changegroup.addchangegroup(). # Before that, there was localrepository.addchangegroup(). if hasattr(cg, 'apply'): cg.apply(self, 'bundleclone', url) elif hasattr(changegroup, 'addchangegroup'): changegroup.addchangegroup(self, cg, 'bundleclone', url) else: self.addchangegroup(cg, 'bundleclone', url) self.ui.status(_('finishing applying bundle; pulling\n')) # Maintain compatibility with Mercurial 2.x. if exchange: return exchange.pull(self, remote, heads=heads) else: return self.pull(remote, heads=heads) except (urllib2.HTTPError, urllib2.URLError) as e: if isinstance(e, urllib2.HTTPError): msg = _('HTTP error fetching bundle: %s') % str(e) else: msg = _('error fetching bundle: %s') % e.reason # Don't fall back to regular clone unless explicitly told to. if not self.ui.configbool('bundleclone', 'fallbackonerror', False): raise util.Abort(msg, hint=_('consider contacting the ' 'server operator if this error persists')) self.ui.warn(msg + '\n') self.ui.warn(_('falling back to normal clone\n')) return super(bundleclonerepo, self).clone(remote, heads=heads, stream=stream)
def choose_changes(ui, repo, patchfile, opts): if opts.get('file'): changedFiles = fullpaths(ui, repo, opts['file']) return (changedFiles, 'file', opts['file']) if opts.get('dir'): changedFiles = opts['dir'] # For --debug printout only return (changedFiles, 'dir', opts['dir']) if opts.get('rev'): revs = scmutil.revrange(repo, opts['rev']) if not revs: raise error.Abort("no changes found") filesInRevs = set() for rev in revs: for f in repo[rev].files(): filesInRevs.add(f) changedFiles = sorted(filesInRevs) return (changedFiles, 'rev', opts['rev']) diff = None changedFiles = None if patchfile is not None: source = None if hasattr(patchfile, 'getvalue'): diff = patchfile.getvalue() source = ('patchdata', None) else: try: diff = url.open(ui, patchfile).read() source = ('patch', patchfile) except IOError: if hasattr(repo, 'mq'): q = repo.mq if q: diff = url.open(ui, q.lookup(patchfile)).read() source = ('mqpatch', patchfile) else: # try using: # 1. current diff (if nonempty) # 2. top applied patch in mq patch queue (if mq enabled) # 3. parent of working directory ui.pushbuffer() commands.diff(ui, repo, git=True) diff = ui.popbuffer() changedFiles = fileRe.findall(diff) if len(changedFiles) > 0: source = ('current diff', None) else: changedFiles = None diff = None if hasattr(repo, 'mq') and repo.mq: ui.pushbuffer() try: commands.diff(ui, repo, change="qtip", git=True) except error.RepoLookupError: pass diff = ui.popbuffer() if diff == '': diff = None else: source = ('qtip', None) if diff is None: changedFiles = sorted(repo[b'.'].files()) source = ('rev', '.') if changedFiles is None: changedFiles = fileRe.findall(diff) return (changedFiles, source[0], source[1])
changedFiles = fileRe.findall(diff) if len(changedFiles) > 0: source = "current diff" elif repo.mq: source = "top patch in mq queue" ui.pushbuffer() try: commands.diff(ui, repo, change="qtip", git=True) except error.RepoLookupError, e: raise util.Abort("no current diff, no mq patch to use") diff = ui.popbuffer() else: raise util.Abort("no changes found") else: try: diff = url.open(ui, patchfile).read() source = "patch file %s" % patchfile except IOError, e: q = repo.mq if q: diff = url.open(ui, q.lookup(patchfile)).read() source = "mq patch %s" % patchfile else: pass changedFiles = fileRe.findall(diff) if ui.verbose: ui.write("Patch source: %s\n" % source) if len(changedFiles) == 0: ui.write( "Warning: no modified files found in patch. Did you mean to use the -f option?\n"
def clone(self, remote, heads=[], stream=False): supported = True if not remote.capable('bundles'): supported = False self.ui.debug(_('bundle clone not supported\n')) elif heads: supported = False self.ui.debug(_('cannot perform bundle clone if heads requested\n')) elif stream: supported = False self.ui.debug(_('ignoring bundle clone because stream was ' 'requested\n')) if not supported: return super(bundleclonerepo, self).clone(remote, heads=heads, stream=stream) result = remote._call('bundles') if not result: self.ui.note(_('no bundles available; using normal clone\n')) return super(bundleclonerepo, self).clone(remote, heads=heads, stream=stream) pyver = sys.version_info pyver = (pyver[0], pyver[1], pyver[2]) # Testing backdoor. if ui.config('bundleclone', 'fakepyver'): pyver = ui.configlist('bundleclone', 'fakepyver') pyver = tuple(int(v) for v in pyver) entries = [] snifiltered = False for line in result.splitlines(): fields = line.split() url = fields[0] attrs = {} for rawattr in fields[1:]: key, value = rawattr.split('=', 1) attrs[urllib.unquote(key)] = urllib.unquote(value) # Filter out SNI entries if we don't support SNI. if attrs.get('requiresni') == 'true' and pyver < (2, 7, 9): # Take this opportunity to inform people they are using an # old, insecure Python. if not snifiltered: self.ui.warn(_('(ignoring URL on server that requires ' 'SNI)\n')) self.ui.warn(_('(your Python is older than 2.7.9 and ' 'does not support modern and secure ' 'SSL/TLS; please consider upgrading ' 'your Python to a secure version)\n')) snifiltered = True continue entries.append((url, attrs)) if not entries: # Don't fall back to normal clone because we don't want mass # fallback in the wild to barage servers expecting bundle # offload. raise util.Abort(_('no appropriate bundles available'), hint=_('you may wish to complain to the ' 'server operator')) # The configuration is allowed to define lists of preferred # attributes and values. If this is present, sort results according # to that preference. Otherwise, use manifest order and select the # first entry. prefers = self.ui.configlist('bundleclone', 'prefers', default=[]) if prefers: prefers = [p.split('=', 1) for p in prefers] def compareentry(a, b): aattrs = a[1] battrs = b[1] # Itereate over local preferences. for pkey, pvalue in prefers: avalue = aattrs.get(pkey) bvalue = battrs.get(pkey) # Special case for b is missing attribute and a matches # exactly. if avalue is not None and bvalue is None and avalue == pvalue: return -1 # Special case for a missing attribute and b matches # exactly. if bvalue is not None and avalue is None and bvalue == pvalue: return 1 # We can't compare unless the attribute is defined on # both entries. if avalue is None or bvalue is None: continue # Same values should fall back to next attribute. if avalue == bvalue: continue # Exact matches come first. if avalue == pvalue: return -1 if bvalue == pvalue: return 1 # Fall back to next attribute. continue # Entries could not be sorted based on attributes. This # says they are equal, which will fall back to index order, # which is what we want. return 0 entries = sorted(entries, cmp=compareentry) url, attrs = entries[0] if not url: self.ui.note(_('invalid bundle manifest; using normal clone\n')) return super(bundleclonerepo, self).clone(remote, heads=heads, stream=stream) self.ui.status(_('downloading bundle %s\n' % url)) try: fh = hgurl.open(self.ui, url) # Stream clone data is not changegroup data. Handle it # specially. if 'stream' in attrs: reqs = set(attrs['stream'].split(',')) applystreamclone(self, reqs, fh) else: if exchange: cg = exchange.readbundle(self.ui, fh, 'stream') else: cg = changegroup.readbundle(fh, 'stream') if hasattr(changegroup, 'addchangegroup'): changegroup.addchangegroup(self, cg, 'bundleclone', url) else: self.addchangegroup(cg, 'bundleclone', url) self.ui.status(_('finishing applying bundle; pulling\n')) # Maintain compatibility with Mercurial 2.x. if exchange: return exchange.pull(self, remote, heads=heads) else: return self.pull(remote, heads=heads) except (urllib2.HTTPError, urllib2.URLError) as e: if isinstance(e, urllib2.HTTPError): msg = _('HTTP error fetching bundle: %s') % str(e) else: msg = _('error fetching bundle: %s') % e.reason # Don't fall back to regular clone unless explicitly told to. if not self.ui.configbool('bundleclone', 'fallbackonerror', False): raise util.Abort(msg, hint=_('consider contacting the ' 'server operator if this error persists')) self.ui.warn(msg + '\n') self.ui.warn(_('falling back to normal clone\n')) return super(bundleclonerepo, self).clone(remote, heads=heads, stream=stream)