diff mercurial/subrepo.py @ 43076:2372284d9457

formatting: blacken the codebase This is using my patch to black (https://github.com/psf/black/pull/826) so we don't un-wrap collection literals. Done with: hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S # skip-blame mass-reformatting only # no-check-commit reformats foo_bar functions Differential Revision: https://phab.mercurial-scm.org/D6971
author Augie Fackler <augie@google.com>
date Sun, 06 Oct 2019 09:45:02 -0400
parents f6540aba8e3e
children 687b865b95ad
line wrap: on
line diff
--- a/mercurial/subrepo.py	Sat Oct 05 10:29:34 2019 -0400
+++ b/mercurial/subrepo.py	Sun Oct 06 09:45:02 2019 -0400
@@ -47,6 +47,7 @@
 _abssource = subrepoutil._abssource
 propertycache = util.propertycache
 
+
 def _expandedabspath(path):
     '''
     get a path or url and if it is a path expand it and return an absolute path
@@ -57,17 +58,21 @@
         path = util.normpath(os.path.abspath(u.path))
     return path
 
+
 def _getstorehashcachename(remotepath):
     '''get a unique filename for the store hash cache of a remote repository'''
     return node.hex(hashlib.sha1(_expandedabspath(remotepath)).digest())[0:12]
 
+
 class SubrepoAbort(error.Abort):
     """Exception class used to avoid handling a subrepo error more than once"""
+
     def __init__(self, *args, **kw):
         self.subrepo = kw.pop(r'subrepo', None)
         self.cause = kw.pop(r'cause', None)
         error.Abort.__init__(self, *args, **kw)
 
+
 def annotatesubrepoerror(func):
     def decoratedmethod(self, *args, **kargs):
         try:
@@ -77,30 +82,39 @@
             raise ex
         except error.Abort as ex:
             subrepo = subrelpath(self)
-            errormsg = (stringutil.forcebytestr(ex) + ' '
-                        + _('(in subrepository "%s")') % subrepo)
+            errormsg = (
+                stringutil.forcebytestr(ex)
+                + ' '
+                + _('(in subrepository "%s")') % subrepo
+            )
             # avoid handling this exception by raising a SubrepoAbort exception
-            raise SubrepoAbort(errormsg, hint=ex.hint, subrepo=subrepo,
-                               cause=sys.exc_info())
+            raise SubrepoAbort(
+                errormsg, hint=ex.hint, subrepo=subrepo, cause=sys.exc_info()
+            )
         return res
+
     return decoratedmethod
 
+
 def _updateprompt(ui, sub, dirty, local, remote):
     if dirty:
-        msg = (_(' subrepository sources for %s differ\n'
-                 'you can use (l)ocal source (%s) or (r)emote source (%s).\n'
-                 'what do you want to do?'
-                 '$$ &Local $$ &Remote')
-               % (subrelpath(sub), local, remote))
+        msg = _(
+            ' subrepository sources for %s differ\n'
+            'you can use (l)ocal source (%s) or (r)emote source (%s).\n'
+            'what do you want to do?'
+            '$$ &Local $$ &Remote'
+        ) % (subrelpath(sub), local, remote)
     else:
-        msg = (_(' subrepository sources for %s differ (in checked out '
-                 'version)\n'
-                 'you can use (l)ocal source (%s) or (r)emote source (%s).\n'
-                 'what do you want to do?'
-                 '$$ &Local $$ &Remote')
-               % (subrelpath(sub), local, remote))
+        msg = _(
+            ' subrepository sources for %s differ (in checked out '
+            'version)\n'
+            'you can use (l)ocal source (%s) or (r)emote source (%s).\n'
+            'what do you want to do?'
+            '$$ &Local $$ &Remote'
+        ) % (subrelpath(sub), local, remote)
     return ui.promptchoice(msg, 0)
 
+
 def _sanitize(ui, vfs, ignore):
     for dirname, dirs, names in vfs.walk():
         for i, d in enumerate(dirs):
@@ -111,41 +125,55 @@
             continue
         for f in names:
             if f.lower() == 'hgrc':
-                ui.warn(_("warning: removing potentially hostile 'hgrc' "
-                          "in '%s'\n") % vfs.join(dirname))
+                ui.warn(
+                    _(
+                        "warning: removing potentially hostile 'hgrc' "
+                        "in '%s'\n"
+                    )
+                    % vfs.join(dirname)
+                )
                 vfs.unlink(vfs.reljoin(dirname, f))
 
+
 def _auditsubrepopath(repo, path):
     # sanity check for potentially unsafe paths such as '~' and '$FOO'
     if path.startswith('~') or '$' in path or util.expandpath(path) != path:
-        raise error.Abort(_('subrepo path contains illegal component: %s')
-                          % path)
+        raise error.Abort(
+            _('subrepo path contains illegal component: %s') % path
+        )
     # auditor doesn't check if the path itself is a symlink
     pathutil.pathauditor(repo.root)(path)
     if repo.wvfs.islink(path):
         raise error.Abort(_("subrepo '%s' traverses symbolic link") % path)
 
+
 SUBREPO_ALLOWED_DEFAULTS = {
     'hg': True,
     'git': False,
     'svn': False,
 }
 
+
 def _checktype(ui, kind):
     # subrepos.allowed is a master kill switch. If disabled, subrepos are
     # disabled period.
     if not ui.configbool('subrepos', 'allowed', True):
-        raise error.Abort(_('subrepos not enabled'),
-                          hint=_("see 'hg help config.subrepos' for details"))
+        raise error.Abort(
+            _('subrepos not enabled'),
+            hint=_("see 'hg help config.subrepos' for details"),
+        )
 
     default = SUBREPO_ALLOWED_DEFAULTS.get(kind, False)
     if not ui.configbool('subrepos', '%s:allowed' % kind, default):
-        raise error.Abort(_('%s subrepos not allowed') % kind,
-                          hint=_("see 'hg help config.subrepos' for details"))
+        raise error.Abort(
+            _('%s subrepos not allowed') % kind,
+            hint=_("see 'hg help config.subrepos' for details"),
+        )
 
     if kind not in types:
         raise error.Abort(_('unknown subrepo type %s') % kind)
 
+
 def subrepo(ctx, path, allowwdir=False, allowcreate=True):
     """return instance of the right subrepo class for subrepo in path"""
     # subrepo inherently violates our import layering rules
@@ -154,6 +182,7 @@
     # scripts that don't use our demand-loading
     global hg
     from . import hg as h
+
     hg = h
 
     repo = ctx.repo()
@@ -164,6 +193,7 @@
         state = (state[0], ctx.subrev(path), state[2])
     return types[state[2]](ctx, path, state[:2], allowcreate)
 
+
 def nullsubrepo(ctx, path, pctx):
     """return an empty subrepo in pctx for the extant subrepo in ctx"""
     # subrepo inherently violates our import layering rules
@@ -172,6 +202,7 @@
     # scripts that don't use our demand-loading
     global hg
     from . import hg as h
+
     hg = h
 
     repo = ctx.repo()
@@ -183,10 +214,11 @@
         subrev = "0" * 40
     return types[state[2]](pctx, path, (state[0], subrev), True)
 
+
 # subrepo classes need to implement the following abstract class:
 
+
 class abstractsubrepo(object):
-
     def __init__(self, ctx, path):
         """Initialize abstractsubrepo part
 
@@ -233,14 +265,14 @@
         This returns None, otherwise.
         """
         if self.dirty(ignoreupdate=ignoreupdate, missing=missing):
-            return _('uncommitted changes in subrepository "%s"'
-                     ) % subrelpath(self)
+            return _('uncommitted changes in subrepository "%s"') % subrelpath(
+                self
+            )
 
     def bailifchanged(self, ignoreupdate=False, hint=None):
         """raise Abort if subrepository is ``dirty()``
         """
-        dirtyreason = self.dirtyreason(ignoreupdate=ignoreupdate,
-                                       missing=True)
+        dirtyreason = self.dirtyreason(ignoreupdate=ignoreupdate, missing=True)
         if dirtyreason:
             raise error.Abort(dirtyreason, hint=hint)
 
@@ -338,15 +370,17 @@
             files = self.files()
         total = len(files)
         relpath = subrelpath(self)
-        progress = self.ui.makeprogress(_('archiving (%s)') % relpath,
-                                        unit=_('files'), total=total)
+        progress = self.ui.makeprogress(
+            _('archiving (%s)') % relpath, unit=_('files'), total=total
+        )
         progress.update(0)
         for name in files:
             flags = self.fileflags(name)
             mode = 'x' in flags and 0o755 or 0o644
             symlink = 'l' in flags
-            archiver.addfile(prefix + name, mode, symlink,
-                             self.filedata(name, decode))
+            archiver.addfile(
+                prefix + name, mode, symlink, self.filedata(name, decode)
+            )
             progress.increment()
         progress.complete()
         return total
@@ -360,19 +394,31 @@
     def forget(self, match, prefix, uipathfn, dryrun, interactive):
         return ([], [])
 
-    def removefiles(self, matcher, prefix, uipathfn, after, force, subrepos,
-                    dryrun, warnings):
+    def removefiles(
+        self,
+        matcher,
+        prefix,
+        uipathfn,
+        after,
+        force,
+        subrepos,
+        dryrun,
+        warnings,
+    ):
         """remove the matched files from the subrepository and the filesystem,
         possibly by force and/or after the file has been removed from the
         filesystem.  Return 0 on success, 1 on any warning.
         """
-        warnings.append(_("warning: removefiles not implemented (%s)")
-                        % self._path)
+        warnings.append(
+            _("warning: removefiles not implemented (%s)") % self._path
+        )
         return 1
 
     def revert(self, substate, *pats, **opts):
-        self.ui.warn(_('%s: reverting %s subrepos is unsupported\n')
-                     % (substate[0], substate[2]))
+        self.ui.warn(
+            _('%s: reverting %s subrepos is unsupported\n')
+            % (substate[0], substate[2])
+        )
         return []
 
     def shortid(self, revid):
@@ -401,6 +447,7 @@
         """
         return self.wvfs.reljoin(reporelpath(self._ctx.repo()), self._path)
 
+
 class hgsubrepo(abstractsubrepo):
     def __init__(self, ctx, path, state, allowcreate):
         super(hgsubrepo, self).__init__(ctx, path)
@@ -411,13 +458,15 @@
         # repository constructor does expand variables in path, which is
         # unsafe since subrepo path might come from untrusted source.
         if os.path.realpath(util.expandpath(root)) != root:
-            raise error.Abort(_('subrepo path contains illegal component: %s')
-                              % path)
+            raise error.Abort(
+                _('subrepo path contains illegal component: %s') % path
+            )
         self._repo = hg.repository(r.baseui, root, create=create)
         if self._repo.root != root:
-            raise error.ProgrammingError('failed to reject unsafe subrepo '
-                                         'path: %s (expanded to %s)'
-                                         % (root, self._repo.root))
+            raise error.ProgrammingError(
+                'failed to reject unsafe subrepo '
+                'path: %s (expanded to %s)' % (root, self._repo.root)
+            )
 
         # Propagate the parent's --hidden option
         if r is r.unfiltered():
@@ -519,8 +568,9 @@
 
     @annotatesubrepoerror
     def add(self, ui, match, prefix, uipathfn, explicitonly, **opts):
-        return cmdutil.add(ui, self._repo, match, prefix, uipathfn,
-                           explicitonly, **opts)
+        return cmdutil.add(
+            ui, self._repo, match, prefix, uipathfn, explicitonly, **opts
+        )
 
     @annotatesubrepoerror
     def addremove(self, m, prefix, uipathfn, opts):
@@ -535,8 +585,9 @@
     def cat(self, match, fm, fntemplate, prefix, **opts):
         rev = self._state[1]
         ctx = self._repo[rev]
-        return cmdutil.cat(self.ui, self._repo, ctx, match, fm, fntemplate,
-                           prefix, **opts)
+        return cmdutil.cat(
+            self.ui, self._repo, ctx, match, fm, fntemplate, prefix, **opts
+        )
 
     @annotatesubrepoerror
     def status(self, rev2, **opts):
@@ -546,8 +597,10 @@
             ctx2 = self._repo[rev2]
             return self._repo.status(ctx1, ctx2, **opts)
         except error.RepoLookupError as inst:
-            self.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
-                         % (inst, subrelpath(self)))
+            self.ui.warn(
+                _('warning: error "%s" in subrepository "%s"\n')
+                % (inst, subrelpath(self))
+            )
             return scmutil.status([], [], [], [], [], [], [])
 
     @annotatesubrepoerror
@@ -558,12 +611,22 @@
             # in hex format
             if node2 is not None:
                 node2 = node.bin(node2)
-            logcmdutil.diffordiffstat(ui, self._repo, diffopts, node1, node2,
-                                      match, prefix=prefix, listsubrepos=True,
-                                      **opts)
+            logcmdutil.diffordiffstat(
+                ui,
+                self._repo,
+                diffopts,
+                node1,
+                node2,
+                match,
+                prefix=prefix,
+                listsubrepos=True,
+                **opts
+            )
         except error.RepoLookupError as inst:
-            self.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
-                          % (inst, subrelpath(self)))
+            self.ui.warn(
+                _('warning: error "%s" in subrepository "%s"\n')
+                % (inst, subrelpath(self))
+            )
 
     @annotatesubrepoerror
     def archive(self, archiver, prefix, match=None, decode=True):
@@ -573,27 +636,27 @@
             files = [f for f in files if match(f)]
         rev = self._state[1]
         ctx = self._repo[rev]
-        scmutil.prefetchfiles(self._repo, [ctx.rev()],
-                              scmutil.matchfiles(self._repo, files))
+        scmutil.prefetchfiles(
+            self._repo, [ctx.rev()], scmutil.matchfiles(self._repo, files)
+        )
         total = abstractsubrepo.archive(self, archiver, prefix, match)
         for subpath in ctx.substate:
             s = subrepo(ctx, subpath, True)
             submatch = matchmod.subdirmatcher(subpath, match)
             subprefix = prefix + subpath + '/'
-            total += s.archive(archiver, subprefix, submatch,
-                               decode)
+            total += s.archive(archiver, subprefix, submatch, decode)
         return total
 
     @annotatesubrepoerror
     def dirty(self, ignoreupdate=False, missing=False):
         r = self._state[1]
-        if r == '' and not ignoreupdate: # no state recorded
+        if r == '' and not ignoreupdate:  # no state recorded
             return True
         w = self._repo[None]
         if r != w.p1().hex() and not ignoreupdate:
             # different version checked out
             return True
-        return w.dirty(missing=missing) # working directory changed
+        return w.dirty(missing=missing)  # working directory changed
 
     def basestate(self):
         return self._repo['.'].hex()
@@ -610,7 +673,7 @@
         self.ui.debug("committing subrepo %s\n" % subrelpath(self))
         n = self._repo.commit(text, user, date)
         if not n:
-            return self._repo['.'].hex() # different version checked out
+            return self._repo['.'].hex()  # different version checked out
         return node.hex(n)
 
     @annotatesubrepoerror
@@ -649,11 +712,17 @@
             # A simpler option is for the user to configure clone pooling, and
             # work with that.
             if parentrepo.shared() and hg.islocal(srcurl):
-                self.ui.status(_('sharing subrepo %s from %s\n')
-                               % (subrelpath(self), srcurl))
-                shared = hg.share(self._repo._subparent.baseui,
-                                  getpeer(), self._repo.root,
-                                  update=False, bookmarks=False)
+                self.ui.status(
+                    _('sharing subrepo %s from %s\n')
+                    % (subrelpath(self), srcurl)
+                )
+                shared = hg.share(
+                    self._repo._subparent.baseui,
+                    getpeer(),
+                    self._repo.root,
+                    update=False,
+                    bookmarks=False,
+                )
                 self._repo = shared.local()
             else:
                 # TODO: find a common place for this and this code in the
@@ -670,17 +739,26 @@
                 else:
                     shareopts = {}
 
-                self.ui.status(_('cloning subrepo %s from %s\n')
-                               % (subrelpath(self), util.hidepassword(srcurl)))
-                other, cloned = hg.clone(self._repo._subparent.baseui, {},
-                                         getpeer(), self._repo.root,
-                                         update=False, shareopts=shareopts)
+                self.ui.status(
+                    _('cloning subrepo %s from %s\n')
+                    % (subrelpath(self), util.hidepassword(srcurl))
+                )
+                other, cloned = hg.clone(
+                    self._repo._subparent.baseui,
+                    {},
+                    getpeer(),
+                    self._repo.root,
+                    update=False,
+                    shareopts=shareopts,
+                )
                 self._repo = cloned.local()
             self._initrepo(parentrepo, source, create=True)
             self._cachestorehash(srcurl)
         else:
-            self.ui.status(_('pulling subrepo %s from %s\n')
-                           % (subrelpath(self), util.hidepassword(srcurl)))
+            self.ui.status(
+                _('pulling subrepo %s from %s\n')
+                % (subrelpath(self), util.hidepassword(srcurl))
+            )
             cleansub = self.storeclean(srcurl)
             exchange.pull(self._repo, getpeer())
             if cleansub:
@@ -700,7 +778,8 @@
             if ctx.hidden():
                 urepo.ui.warn(
                     _('revision %s in subrepository "%s" is hidden\n')
-                    % (revision[0:12], self._path))
+                    % (revision[0:12], self._path)
+                )
                 repo = urepo
         hg.updaterepo(repo, revision, overwrite)
 
@@ -713,12 +792,14 @@
 
         def mergefunc():
             if anc == cur and dst.branch() == cur.branch():
-                self.ui.debug('updating subrepository "%s"\n'
-                              % subrelpath(self))
+                self.ui.debug(
+                    'updating subrepository "%s"\n' % subrelpath(self)
+                )
                 hg.update(self._repo, state[1])
             elif anc == dst:
-                self.ui.debug('skipping subrepository "%s"\n'
-                              % subrelpath(self))
+                self.ui.debug(
+                    'skipping subrepository "%s"\n' % subrelpath(self)
+                )
             else:
                 self.ui.debug('merging subrepository "%s"\n' % subrelpath(self))
                 hg.merge(self._repo, state[1], remind=False)
@@ -741,7 +822,7 @@
 
         # push subrepos depth-first for coherent ordering
         c = self._repo['.']
-        subs = c.substate # only repos that are committed
+        subs = c.substate  # only repos that are committed
         for s in sorted(subs):
             if c.sub(s).push(opts) == 0:
                 return False
@@ -751,10 +832,13 @@
             if self.storeclean(dsturl):
                 self.ui.status(
                     _('no changes made to subrepo %s since last push to %s\n')
-                    % (subrelpath(self), util.hidepassword(dsturl)))
+                    % (subrelpath(self), util.hidepassword(dsturl))
+                )
                 return None
-        self.ui.status(_('pushing subrepo %s to %s\n') %
-            (subrelpath(self), util.hidepassword(dsturl)))
+        self.ui.status(
+            _('pushing subrepo %s to %s\n')
+            % (subrelpath(self), util.hidepassword(dsturl))
+        )
         other = hg.peer(self._repo, {'ssh': ssh}, dsturl)
         res = exchange.push(self._repo, other, force, newbranch=newbranch)
 
@@ -825,8 +909,10 @@
                 pm = matchmod.prefixdirmatcher(subpath, sm, badfn=badfn)
                 matchers.append(pm)
             except error.LookupError:
-                self.ui.status(_("skipping missing subrepository: %s\n")
-                               % self.wvfs.reljoin(reporelpath(self), subpath))
+                self.ui.status(
+                    _("skipping missing subrepository: %s\n")
+                    % self.wvfs.reljoin(reporelpath(self), subpath)
+                )
         if len(matchers) == 1:
             return matchers[0]
         return matchmod.unionmatcher(matchers)
@@ -837,14 +923,40 @@
 
     @annotatesubrepoerror
     def forget(self, match, prefix, uipathfn, dryrun, interactive):
-        return cmdutil.forget(self.ui, self._repo, match, prefix, uipathfn,
-                              True, dryrun=dryrun, interactive=interactive)
+        return cmdutil.forget(
+            self.ui,
+            self._repo,
+            match,
+            prefix,
+            uipathfn,
+            True,
+            dryrun=dryrun,
+            interactive=interactive,
+        )
 
     @annotatesubrepoerror
-    def removefiles(self, matcher, prefix, uipathfn, after, force, subrepos,
-                    dryrun, warnings):
-        return cmdutil.remove(self.ui, self._repo, matcher, prefix, uipathfn,
-                              after, force, subrepos, dryrun)
+    def removefiles(
+        self,
+        matcher,
+        prefix,
+        uipathfn,
+        after,
+        force,
+        subrepos,
+        dryrun,
+        warnings,
+    ):
+        return cmdutil.remove(
+            self.ui,
+            self._repo,
+            matcher,
+            prefix,
+            uipathfn,
+            after,
+            force,
+            subrepos,
+            dryrun,
+        )
 
     @annotatesubrepoerror
     def revert(self, substate, *pats, **opts):
@@ -888,6 +1000,7 @@
         # scripts that don't use our demand-loading
         global hg
         from . import hg as h
+
         hg = h
 
         # Nothing prevents a user from sharing in a repo, and then making that a
@@ -906,14 +1019,18 @@
                 # Since hidden revisions aren't pushed/pulled, it seems worth an
                 # explicit warning.
                 ui = self._repo.ui
-                ui.warn(_("subrepo '%s' is hidden in revision %s\n") %
-                        (self._relpath, node.short(self._ctx.node())))
+                ui.warn(
+                    _("subrepo '%s' is hidden in revision %s\n")
+                    % (self._relpath, node.short(self._ctx.node()))
+                )
             return 0
         except error.RepoLookupError:
             # A missing subrepo revision may be a case of needing to pull it, so
             # don't treat this as an error.
-            self._repo.ui.warn(_("subrepo '%s' not found in revision %s\n") %
-                               (self._relpath, node.short(self._ctx.node())))
+            self._repo.ui.warn(
+                _("subrepo '%s' not found in revision %s\n")
+                % (self._relpath, node.short(self._ctx.node()))
+            )
             return 0
 
     @propertycache
@@ -929,14 +1046,16 @@
         # Keep consistent dir separators by avoiding vfs.join(self._path)
         return reporelpath(self._repo)
 
+
 class svnsubrepo(abstractsubrepo):
     def __init__(self, ctx, path, state, allowcreate):
         super(svnsubrepo, self).__init__(ctx, path)
         self._state = state
         self._exe = procutil.findexe('svn')
         if not self._exe:
-            raise error.Abort(_("'svn' executable not found for subrepo '%s'")
-                             % self._path)
+            raise error.Abort(
+                _("'svn' executable not found for subrepo '%s'") % self._path
+            )
 
     def _svncommand(self, commands, filename='', failok=False):
         cmd = [self._exe]
@@ -953,8 +1072,9 @@
                 cmd.append('--non-interactive')
         cmd.extend(commands)
         if filename is not None:
-            path = self.wvfs.reljoin(self._ctx.repo().origroot,
-                                     self._path, filename)
+            path = self.wvfs.reljoin(
+                self._ctx.repo().origroot, self._path, filename
+            )
             cmd.append(path)
         env = dict(encoding.environ)
         # Avoid localized output, preserve current locale for everything else.
@@ -963,16 +1083,22 @@
             env['LANG'] = lc_all
             del env['LC_ALL']
         env['LC_MESSAGES'] = 'C'
-        p = subprocess.Popen(pycompat.rapply(procutil.tonativestr, cmd),
-                             bufsize=-1, close_fds=procutil.closefds,
-                             stdout=subprocess.PIPE, stderr=subprocess.PIPE,
-                             env=procutil.tonativeenv(env), **extrakw)
+        p = subprocess.Popen(
+            pycompat.rapply(procutil.tonativestr, cmd),
+            bufsize=-1,
+            close_fds=procutil.closefds,
+            stdout=subprocess.PIPE,
+            stderr=subprocess.PIPE,
+            env=procutil.tonativeenv(env),
+            **extrakw
+        )
         stdout, stderr = map(util.fromnativeeol, p.communicate())
         stderr = stderr.strip()
         if not failok:
             if p.returncode:
-                raise error.Abort(stderr or 'exited with code %d'
-                                  % p.returncode)
+                raise error.Abort(
+                    stderr or 'exited with code %d' % p.returncode
+                )
             if stderr:
                 self.ui.warn(stderr + '\n')
         return stdout, stderr
@@ -1000,8 +1126,10 @@
             rev = pycompat.bytestr(entries[0].getAttribute(r'revision')) or '0'
             commits = entries[0].getElementsByTagName(r'commit')
             if commits:
-                lastrev = pycompat.bytestr(
-                    commits[0].getAttribute(r'revision')) or '0'
+                lastrev = (
+                    pycompat.bytestr(commits[0].getAttribute(r'revision'))
+                    or '0'
+                )
         return (lastrev, rev)
 
     def _wcrev(self):
@@ -1027,8 +1155,12 @@
                 externals.append(path)
             elif item == r'missing':
                 missing.append(path)
-            if (item not in (r'', r'normal', r'unversioned', r'external')
-                or props not in (r'', r'none', r'normal')):
+            if item not in (
+                r'',
+                r'normal',
+                r'unversioned',
+                r'external',
+            ) or props not in (r'', r'none', r'normal'):
                 changes.append(path)
         for path in changes:
             for ext in externals:
@@ -1092,8 +1224,10 @@
     @annotatesubrepoerror
     def remove(self):
         if self.dirty():
-            self.ui.warn(_('not removing repo %s because '
-                           'it has changes.\n') % self._path)
+            self.ui.warn(
+                _('not removing repo %s because ' 'it has changes.\n')
+                % self._path
+            )
             return
         self.ui.note(_('removing subrepo %s\n') % self._path)
 
@@ -1121,8 +1255,9 @@
         status, err = self._svncommand(args, failok=True)
         _sanitize(self.ui, self.wvfs, '.svn')
         if not re.search('Checked out revision [0-9]+.', status):
-            if ('is already a working copy for a different URL' in err
-                and (self._wcchanged()[:2] == (False, False))):
+            if 'is already a working copy for a different URL' in err and (
+                self._wcchanged()[:2] == (False, False)
+            ):
                 # obstructed but clean working copy, so just blow it away.
                 self.remove()
                 self.get(state, overwrite=False)
@@ -1153,9 +1288,11 @@
             kind = pycompat.bytestr(e.getAttribute(r'kind'))
             if kind != 'file':
                 continue
-            name = r''.join(c.data for c
-                            in e.getElementsByTagName(r'name')[0].childNodes
-                            if c.nodeType == c.TEXT_NODE)
+            name = r''.join(
+                c.data
+                for c in e.getElementsByTagName(r'name')[0].childNodes
+                if c.nodeType == c.TEXT_NODE
+            )
             paths.append(name.encode('utf8'))
         return paths
 
@@ -1179,23 +1316,33 @@
             genericerror = _("error executing git for subrepo '%s': %s")
             notfoundhint = _("check git is installed and in your PATH")
             if e.errno != errno.ENOENT:
-                raise error.Abort(genericerror % (
-                    self._path, encoding.strtolocal(e.strerror)))
+                raise error.Abort(
+                    genericerror % (self._path, encoding.strtolocal(e.strerror))
+                )
             elif pycompat.iswindows:
                 try:
                     self._gitexecutable = 'git.cmd'
                     out, err = self._gitnodir(['--version'])
                 except OSError as e2:
                     if e2.errno == errno.ENOENT:
-                        raise error.Abort(_("couldn't find 'git' or 'git.cmd'"
-                            " for subrepo '%s'") % self._path,
-                            hint=notfoundhint)
+                        raise error.Abort(
+                            _(
+                                "couldn't find 'git' or 'git.cmd'"
+                                " for subrepo '%s'"
+                            )
+                            % self._path,
+                            hint=notfoundhint,
+                        )
                     else:
-                        raise error.Abort(genericerror % (self._path,
-                            encoding.strtolocal(e2.strerror)))
+                        raise error.Abort(
+                            genericerror
+                            % (self._path, encoding.strtolocal(e2.strerror))
+                        )
             else:
-                raise error.Abort(_("couldn't find git for subrepo '%s'")
-                    % self._path, hint=notfoundhint)
+                raise error.Abort(
+                    _("couldn't find git for subrepo '%s'") % self._path,
+                    hint=notfoundhint,
+                )
         versionstatus = self._checkversion(out)
         if versionstatus == 'unknown':
             self.ui.warn(_('cannot retrieve git version\n'))
@@ -1256,8 +1403,9 @@
         return self._gitdir(commands, env=env, stream=stream)[0]
 
     def _gitdir(self, commands, env=None, stream=False):
-        return self._gitnodir(commands, env=env, stream=stream,
-                              cwd=self._abspath)
+        return self._gitnodir(
+            commands, env=env, stream=stream, cwd=self._abspath
+        )
 
     def _gitnodir(self, commands, env=None, stream=False, cwd=None):
         """Calls the git command
@@ -1282,13 +1430,17 @@
             # insert the argument in the front,
             # the end of git diff arguments is used for paths
             commands.insert(1, '--color')
-        p = subprocess.Popen(pycompat.rapply(procutil.tonativestr,
-                                             [self._gitexecutable] + commands),
-                             bufsize=-1,
-                             cwd=pycompat.rapply(procutil.tonativestr, cwd),
-                             env=procutil.tonativeenv(env),
-                             close_fds=procutil.closefds,
-                             stdout=subprocess.PIPE, stderr=errpipe)
+        p = subprocess.Popen(
+            pycompat.rapply(
+                procutil.tonativestr, [self._gitexecutable] + commands
+            ),
+            bufsize=-1,
+            cwd=pycompat.rapply(procutil.tonativestr, cwd),
+            env=procutil.tonativeenv(env),
+            close_fds=procutil.closefds,
+            stdout=subprocess.PIPE,
+            stderr=errpipe,
+        )
         if stream:
             return p.stdout, None
 
@@ -1302,8 +1454,10 @@
             if command in ('cat-file', 'symbolic-ref'):
                 return retdata, p.returncode
             # for all others, abort
-            raise error.Abort(_('git %s error %d in %s') %
-                             (command, p.returncode, self._relpath))
+            raise error.Abort(
+                _('git %s error %d in %s')
+                % (command, p.returncode, self._relpath)
+            )
 
         return retdata, p.returncode
 
@@ -1349,15 +1503,17 @@
         branch2rev = {}
         rev2branch = {}
 
-        out = self._gitcommand(['for-each-ref', '--format',
-                                '%(objectname) %(refname)'])
+        out = self._gitcommand(
+            ['for-each-ref', '--format', '%(objectname) %(refname)']
+        )
         for line in out.split('\n'):
             revision, ref = line.split(' ')
-            if (not ref.startswith('refs/heads/') and
-                not ref.startswith('refs/remotes/')):
+            if not ref.startswith('refs/heads/') and not ref.startswith(
+                'refs/remotes/'
+            ):
                 continue
             if ref.startswith('refs/remotes/') and ref.endswith('/HEAD'):
-                continue # ignore remote/HEAD redirects
+                continue  # ignore remote/HEAD redirects
             branch2rev[ref] = revision
             rev2branch.setdefault(revision, []).append(ref)
         return branch2rev, rev2branch
@@ -1373,8 +1529,9 @@
             remote = self._gitcommand(['config', 'branch.%s.remote' % bname])
             if remote:
                 ref = self._gitcommand(['config', 'branch.%s.merge' % bname])
-                tracking['refs/remotes/%s/%s' %
-                         (remote, ref.split('/', 2)[2])] = b
+                tracking[
+                    'refs/remotes/%s/%s' % (remote, ref.split('/', 2)[2])
+                ] = b
         return tracking
 
     def _abssource(self, source):
@@ -1392,18 +1549,23 @@
             util.checksafessh(source)
 
             source = self._abssource(source)
-            self.ui.status(_('cloning subrepo %s from %s\n') %
-                            (self._relpath, source))
+            self.ui.status(
+                _('cloning subrepo %s from %s\n') % (self._relpath, source)
+            )
             self._gitnodir(['clone', source, self._abspath])
         if self._githavelocally(revision):
             return
-        self.ui.status(_('pulling subrepo %s from %s\n') %
-                        (self._relpath, self._gitremote('origin')))
+        self.ui.status(
+            _('pulling subrepo %s from %s\n')
+            % (self._relpath, self._gitremote('origin'))
+        )
         # try only origin: the originally cloned repo
         self._gitcommand(['fetch'])
         if not self._githavelocally(revision):
-            raise error.Abort(_('revision %s does not exist in subrepository '
-                                '"%s"\n') % (revision, self._relpath))
+            raise error.Abort(
+                _('revision %s does not exist in subrepository ' '"%s"\n')
+                % (revision, self._relpath)
+            )
 
     @annotatesubrepoerror
     def dirty(self, ignoreupdate=False, missing=False):
@@ -1458,10 +1620,13 @@
 
         def rawcheckout():
             # no branch to checkout, check it out with no branch
-            self.ui.warn(_('checking out detached HEAD in '
-                           'subrepository "%s"\n') % self._relpath)
-            self.ui.warn(_('check out a git branch if you intend '
-                            'to make changes\n'))
+            self.ui.warn(
+                _('checking out detached HEAD in ' 'subrepository "%s"\n')
+                % self._relpath
+            )
+            self.ui.warn(
+                _('check out a git branch if you intend ' 'to make changes\n')
+            )
             checkout(['-q', revision])
 
         if revision not in rev2branch:
@@ -1519,8 +1684,9 @@
         if date:
             # git's date parser silently ignores when seconds < 1e9
             # convert to ISO8601
-            env['GIT_AUTHOR_DATE'] = dateutil.datestr(date,
-                                                  '%Y-%m-%dT%H:%M:%S %1%2')
+            env['GIT_AUTHOR_DATE'] = dateutil.datestr(
+                date, '%Y-%m-%dT%H:%M:%S %1%2'
+            )
         self._gitcommand(cmd, env=env)
         # make sure commit works otherwise HEAD might not exist under certain
         # circumstances
@@ -1536,7 +1702,7 @@
 
         def mergefunc():
             if base == revision:
-                self.get(state) # fast forward merge
+                self.get(state)  # fast forward merge
             elif base != self._state[1]:
                 self._gitcommand(['merge', '--no-commit', revision])
             _sanitize(self.ui, self.wvfs, '.git')
@@ -1544,8 +1710,9 @@
         if self.dirty():
             if self._gitstate() != revision:
                 dirty = self._gitstate() == self._state[1] or code != 0
-                if _updateprompt(self.ui, self, dirty,
-                                 self._state[1][:7], revision[:7]):
+                if _updateprompt(
+                    self.ui, self, dirty, self._state[1][:7], revision[:7]
+                ):
                     mergefunc()
         else:
             mergefunc()
@@ -1577,17 +1744,28 @@
         if current:
             # determine if the current branch is even useful
             if not self._gitisancestor(self._state[1], current):
-                self.ui.warn(_('unrelated git branch checked out '
-                               'in subrepository "%s"\n') % self._relpath)
+                self.ui.warn(
+                    _(
+                        'unrelated git branch checked out '
+                        'in subrepository "%s"\n'
+                    )
+                    % self._relpath
+                )
                 return False
-            self.ui.status(_('pushing branch %s of subrepository "%s"\n') %
-                           (current.split('/', 2)[2], self._relpath))
+            self.ui.status(
+                _('pushing branch %s of subrepository "%s"\n')
+                % (current.split('/', 2)[2], self._relpath)
+            )
             ret = self._gitdir(cmd + ['origin', current])
             return ret[1] == 0
         else:
-            self.ui.warn(_('no branch checked out in subrepository "%s"\n'
-                           'cannot push revision %s\n') %
-                          (self._relpath, self._state[1]))
+            self.ui.warn(
+                _(
+                    'no branch checked out in subrepository "%s"\n'
+                    'cannot push revision %s\n'
+                )
+                % (self._relpath, self._state[1])
+            )
             return False
 
     @annotatesubrepoerror
@@ -1613,7 +1791,7 @@
             exact = match.exact(f)
             command = ["add"]
             if exact:
-                command.append("-f") #should be added, even if ignored
+                command.append("-f")  # should be added, even if ignored
             if ui.verbose or not exact:
                 ui.status(_('adding %s\n') % uipathfn(f))
 
@@ -1634,8 +1812,10 @@
         if self._gitmissing():
             return
         if self.dirty():
-            self.ui.warn(_('not removing repo %s because '
-                           'it has changes.\n') % self._relpath)
+            self.ui.warn(
+                _('not removing repo %s because ' 'it has changes.\n')
+                % self._relpath
+            )
             return
         # we can't fully delete the repository as it may contain
         # local-only history
@@ -1662,8 +1842,9 @@
         tarstream = self._gitcommand(['archive', revision], stream=True)
         tar = tarfile.open(fileobj=tarstream, mode=r'r|')
         relpath = subrelpath(self)
-        progress = self.ui.makeprogress(_('archiving (%s)') % relpath,
-                                        unit=_('files'))
+        progress = self.ui.makeprogress(
+            _('archiving (%s)') % relpath, unit=_('files')
+        )
         progress.update(0)
         for info in tar:
             if info.isdir():
@@ -1681,12 +1862,11 @@
         progress.complete()
         return total
 
-
     @annotatesubrepoerror
     def cat(self, match, fm, fntemplate, prefix, **opts):
         rev = self._state[1]
         if match.anypats():
-            return 1 #No support for include/exclude yet
+            return 1  # No support for include/exclude yet
 
         if not match.files():
             return 1
@@ -1694,13 +1874,13 @@
         # TODO: add support for non-plain formatter (see cmdutil.cat())
         for f in match.files():
             output = self._gitcommand(["show", "%s:%s" % (rev, f)])
-            fp = cmdutil.makefileobj(self._ctx, fntemplate,
-                                     pathname=self.wvfs.reljoin(prefix, f))
+            fp = cmdutil.makefileobj(
+                self._ctx, fntemplate, pathname=self.wvfs.reljoin(prefix, f)
+            )
             fp.write(output)
             fp.close()
         return 0
 
-
     @annotatesubrepoerror
     def status(self, rev2, **opts):
         rev1 = self._state[1]
@@ -1718,7 +1898,7 @@
             tab = line.find('\t')
             if tab == -1:
                 continue
-            status, f = line[tab - 1:tab], line[tab + 1:]
+            status, f = line[tab - 1 : tab], line[tab + 1 :]
             if status == 'M':
                 modified.append(f)
             elif status == 'A':
@@ -1743,7 +1923,7 @@
             if not line:
                 continue
             st = line[0:2]
-            #moves and copies show 2 files on one line
+            # moves and copies show 2 files on one line
             if line.find('\0') >= 0:
                 filename1, filename2 = line[3:].split('\0')
             else:
@@ -1765,8 +1945,9 @@
                 if not f in changedfiles:
                     clean.append(f)
 
-        return scmutil.status(modified, added, removed, deleted,
-                              unknown, ignored, clean)
+        return scmutil.status(
+            modified, added, removed, deleted, unknown, ignored, clean
+        )
 
     @annotatesubrepoerror
     def diff(self, ui, diffopts, node2, match, prefix, **opts):
@@ -1779,18 +1960,22 @@
             cmd.append('-U%d' % diffopts.context)
 
         if diffopts.noprefix:
-            cmd.extend(['--src-prefix=%s/' % prefix,
-                        '--dst-prefix=%s/' % prefix])
+            cmd.extend(
+                ['--src-prefix=%s/' % prefix, '--dst-prefix=%s/' % prefix]
+            )
         else:
-            cmd.extend(['--src-prefix=a/%s/' % prefix,
-                        '--dst-prefix=b/%s/' % prefix])
+            cmd.extend(
+                ['--src-prefix=a/%s/' % prefix, '--dst-prefix=b/%s/' % prefix]
+            )
 
         if diffopts.ignorews:
             cmd.append('--ignore-all-space')
         if diffopts.ignorewsamount:
             cmd.append('--ignore-space-change')
-        if (self._gitversion(self._gitcommand(['--version'])) >= (1, 8, 4)
-            and diffopts.ignoreblanklines):
+        if (
+            self._gitversion(self._gitcommand(['--version'])) >= (1, 8, 4)
+            and diffopts.ignoreblanklines
+        ):
             cmd.append('--ignore-blank-lines')
 
         cmd.append(node1)
@@ -1820,10 +2005,13 @@
                 # backuppath() expects a path relative to the parent repo (the
                 # repo that ui.origbackuppath is relative to)
                 parentname = os.path.join(self._path, name)
-                bakname = scmutil.backuppath(self.ui, self._subparent,
-                                             parentname)
-                self.ui.note(_('saving current version of %s as %s\n') %
-                        (name, os.path.relpath(bakname)))
+                bakname = scmutil.backuppath(
+                    self.ui, self._subparent, parentname
+                )
+                self.ui.note(
+                    _('saving current version of %s as %s\n')
+                    % (name, os.path.relpath(bakname))
+                )
                 util.rename(self.wvfs.join(name), bakname)
 
         if not opts.get(r'dry_run'):
@@ -1833,8 +2021,9 @@
     def shortid(self, revid):
         return revid[:7]
 
+
 types = {
     'hg': hgsubrepo,
     'svn': svnsubrepo,
     'git': gitsubrepo,
-    }
+}