hgext/mq.py
changeset 43077 687b865b95ad
parent 43076 2372284d9457
child 43085 eef9a2d67051
equal deleted inserted replaced
43076:2372284d9457 43077:687b865b95ad
   102     dateutil,
   102     dateutil,
   103     stringutil,
   103     stringutil,
   104 )
   104 )
   105 
   105 
   106 release = lockmod.release
   106 release = lockmod.release
   107 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
   107 seriesopts = [(b's', b'summary', None, _(b'print first line of patch header'))]
   108 
   108 
   109 cmdtable = {}
   109 cmdtable = {}
   110 command = registrar.command(cmdtable)
   110 command = registrar.command(cmdtable)
   111 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
   111 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
   112 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
   112 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
   113 # be specifying the version(s) of Mercurial they are tested with, or
   113 # be specifying the version(s) of Mercurial they are tested with, or
   114 # leave the attribute unspecified.
   114 # leave the attribute unspecified.
   115 testedwith = 'ships-with-hg-core'
   115 testedwith = b'ships-with-hg-core'
   116 
   116 
   117 configtable = {}
   117 configtable = {}
   118 configitem = registrar.configitem(configtable)
   118 configitem = registrar.configitem(configtable)
   119 
   119 
   120 configitem(
   120 configitem(
   121     'mq', 'git', default='auto',
   121     b'mq', b'git', default=b'auto',
   122 )
   122 )
   123 configitem(
   123 configitem(
   124     'mq', 'keepchanges', default=False,
   124     b'mq', b'keepchanges', default=False,
   125 )
   125 )
   126 configitem(
   126 configitem(
   127     'mq', 'plain', default=False,
   127     b'mq', b'plain', default=False,
   128 )
   128 )
   129 configitem(
   129 configitem(
   130     'mq', 'secret', default=False,
   130     b'mq', b'secret', default=False,
   131 )
   131 )
   132 
   132 
   133 # force load strip extension formerly included in mq and import some utility
   133 # force load strip extension formerly included in mq and import some utility
   134 try:
   134 try:
   135     stripext = extensions.find('strip')
   135     stripext = extensions.find(b'strip')
   136 except KeyError:
   136 except KeyError:
   137     # note: load is lazy so we could avoid the try-except,
   137     # note: load is lazy so we could avoid the try-except,
   138     # but I (marmoute) prefer this explicit code.
   138     # but I (marmoute) prefer this explicit code.
   139     class dummyui(object):
   139     class dummyui(object):
   140         def debug(self, msg):
   140         def debug(self, msg):
   141             pass
   141             pass
   142 
   142 
   143         def log(self, event, msgfmt, *msgargs, **opts):
   143         def log(self, event, msgfmt, *msgargs, **opts):
   144             pass
   144             pass
   145 
   145 
   146     stripext = extensions.load(dummyui(), 'strip', '')
   146     stripext = extensions.load(dummyui(), b'strip', b'')
   147 
   147 
   148 strip = stripext.strip
   148 strip = stripext.strip
   149 
   149 
   150 
   150 
   151 def checksubstate(repo, baserev=None):
   151 def checksubstate(repo, baserev=None):
   172 class statusentry(object):
   172 class statusentry(object):
   173     def __init__(self, node, name):
   173     def __init__(self, node, name):
   174         self.node, self.name = node, name
   174         self.node, self.name = node, name
   175 
   175 
   176     def __bytes__(self):
   176     def __bytes__(self):
   177         return hex(self.node) + ':' + self.name
   177         return hex(self.node) + b':' + self.name
   178 
   178 
   179     __str__ = encoding.strmethod(__bytes__)
   179     __str__ = encoding.strmethod(__bytes__)
   180     __repr__ = encoding.strmethod(__bytes__)
   180     __repr__ = encoding.strmethod(__bytes__)
   181 
   181 
   182 
   182 
   183 # The order of the headers in 'hg export' HG patches:
   183 # The order of the headers in 'hg export' HG patches:
   184 HGHEADERS = [
   184 HGHEADERS = [
   185     #   '# HG changeset patch',
   185     #   '# HG changeset patch',
   186     '# User ',
   186     b'# User ',
   187     '# Date ',
   187     b'# Date ',
   188     '#      ',
   188     b'#      ',
   189     '# Branch ',
   189     b'# Branch ',
   190     '# Node ID ',
   190     b'# Node ID ',
   191     '# Parent  ',  # can occur twice for merges - but that is not relevant for mq
   191     b'# Parent  ',  # can occur twice for merges - but that is not relevant for mq
   192 ]
   192 ]
   193 # The order of headers in plain 'mail style' patches:
   193 # The order of headers in plain 'mail style' patches:
   194 PLAINHEADERS = {
   194 PLAINHEADERS = {
   195     'from': 0,
   195     b'from': 0,
   196     'date': 1,
   196     b'date': 1,
   197     'subject': 2,
   197     b'subject': 2,
   198 }
   198 }
   199 
   199 
   200 
   200 
   201 def inserthgheader(lines, header, value):
   201 def inserthgheader(lines, header, value):
   202     """Assuming lines contains a HG patch header, add a header line with value.
   202     """Assuming lines contains a HG patch header, add a header line with value.
   219     ['# HG changeset patch', '# Date z', '', '# Date y']
   219     ['# HG changeset patch', '# Date z', '', '# Date y']
   220     >>> inserthgheader([b'# HG changeset patch', b'# Parent  y'],
   220     >>> inserthgheader([b'# HG changeset patch', b'# Parent  y'],
   221     ...                b'# Date ', b'z')
   221     ...                b'# Date ', b'z')
   222     ['# HG changeset patch', '# Date z', '# Parent  y']
   222     ['# HG changeset patch', '# Date z', '# Parent  y']
   223     """
   223     """
   224     start = lines.index('# HG changeset patch') + 1
   224     start = lines.index(b'# HG changeset patch') + 1
   225     newindex = HGHEADERS.index(header)
   225     newindex = HGHEADERS.index(header)
   226     bestpos = len(lines)
   226     bestpos = len(lines)
   227     for i in range(start, len(lines)):
   227     for i in range(start, len(lines)):
   228         line = lines[i]
   228         line = lines[i]
   229         if not line.startswith('# '):
   229         if not line.startswith(b'# '):
   230             bestpos = min(bestpos, i)
   230             bestpos = min(bestpos, i)
   231             break
   231             break
   232         for lineindex, h in enumerate(HGHEADERS):
   232         for lineindex, h in enumerate(HGHEADERS):
   233             if line.startswith(h):
   233             if line.startswith(h):
   234                 if lineindex == newindex:
   234                 if lineindex == newindex:
   259     ['From: y', 'foo: bar', 'DATE: z', '', 'x']
   259     ['From: y', 'foo: bar', 'DATE: z', '', 'x']
   260     """
   260     """
   261     newprio = PLAINHEADERS[header.lower()]
   261     newprio = PLAINHEADERS[header.lower()]
   262     bestpos = len(lines)
   262     bestpos = len(lines)
   263     for i, line in enumerate(lines):
   263     for i, line in enumerate(lines):
   264         if ':' in line:
   264         if b':' in line:
   265             lheader = line.split(':', 1)[0].strip().lower()
   265             lheader = line.split(b':', 1)[0].strip().lower()
   266             lprio = PLAINHEADERS.get(lheader, newprio + 1)
   266             lprio = PLAINHEADERS.get(lheader, newprio + 1)
   267             if lprio == newprio:
   267             if lprio == newprio:
   268                 lines[i] = '%s: %s' % (header, value)
   268                 lines[i] = b'%s: %s' % (header, value)
   269                 return lines
   269                 return lines
   270             if lprio > newprio and i < bestpos:
   270             if lprio > newprio and i < bestpos:
   271                 bestpos = i
   271                 bestpos = i
   272         else:
   272         else:
   273             if line:
   273             if line:
   274                 lines.insert(i, '')
   274                 lines.insert(i, b'')
   275             if i < bestpos:
   275             if i < bestpos:
   276                 bestpos = i
   276                 bestpos = i
   277             break
   277             break
   278     lines.insert(bestpos, '%s: %s' % (header, value))
   278     lines.insert(bestpos, b'%s: %s' % (header, value))
   279     return lines
   279     return lines
   280 
   280 
   281 
   281 
   282 class patchheader(object):
   282 class patchheader(object):
   283     def __init__(self, pf, plainmode=False):
   283     def __init__(self, pf, plainmode=False):
   284         def eatdiff(lines):
   284         def eatdiff(lines):
   285             while lines:
   285             while lines:
   286                 l = lines[-1]
   286                 l = lines[-1]
   287                 if (
   287                 if (
   288                     l.startswith("diff -")
   288                     l.startswith(b"diff -")
   289                     or l.startswith("Index:")
   289                     or l.startswith(b"Index:")
   290                     or l.startswith("===========")
   290                     or l.startswith(b"===========")
   291                 ):
   291                 ):
   292                     del lines[-1]
   292                     del lines[-1]
   293                 else:
   293                 else:
   294                     break
   294                     break
   295 
   295 
   309         subject = None
   309         subject = None
   310         branch = None
   310         branch = None
   311         nodeid = None
   311         nodeid = None
   312         diffstart = 0
   312         diffstart = 0
   313 
   313 
   314         for line in open(pf, 'rb'):
   314         for line in open(pf, b'rb'):
   315             line = line.rstrip()
   315             line = line.rstrip()
   316             if line.startswith('diff --git') or (
   316             if line.startswith(b'diff --git') or (
   317                 diffstart and line.startswith('+++ ')
   317                 diffstart and line.startswith(b'+++ ')
   318             ):
   318             ):
   319                 diffstart = 2
   319                 diffstart = 2
   320                 break
   320                 break
   321             diffstart = 0  # reset
   321             diffstart = 0  # reset
   322             if line.startswith("--- "):
   322             if line.startswith(b"--- "):
   323                 diffstart = 1
   323                 diffstart = 1
   324                 continue
   324                 continue
   325             elif format == "hgpatch":
   325             elif format == b"hgpatch":
   326                 # parse values when importing the result of an hg export
   326                 # parse values when importing the result of an hg export
   327                 if line.startswith("# User "):
   327                 if line.startswith(b"# User "):
   328                     user = line[7:]
   328                     user = line[7:]
   329                 elif line.startswith("# Date "):
   329                 elif line.startswith(b"# Date "):
   330                     date = line[7:]
   330                     date = line[7:]
   331                 elif line.startswith("# Parent "):
   331                 elif line.startswith(b"# Parent "):
   332                     parent = line[9:].lstrip()  # handle double trailing space
   332                     parent = line[9:].lstrip()  # handle double trailing space
   333                 elif line.startswith("# Branch "):
   333                 elif line.startswith(b"# Branch "):
   334                     branch = line[9:]
   334                     branch = line[9:]
   335                 elif line.startswith("# Node ID "):
   335                 elif line.startswith(b"# Node ID "):
   336                     nodeid = line[10:]
   336                     nodeid = line[10:]
   337                 elif not line.startswith("# ") and line:
   337                 elif not line.startswith(b"# ") and line:
   338                     message.append(line)
   338                     message.append(line)
   339                     format = None
   339                     format = None
   340             elif line == '# HG changeset patch':
   340             elif line == b'# HG changeset patch':
   341                 message = []
   341                 message = []
   342                 format = "hgpatch"
   342                 format = b"hgpatch"
   343             elif format != "tagdone" and (
   343             elif format != b"tagdone" and (
   344                 line.startswith("Subject: ") or line.startswith("subject: ")
   344                 line.startswith(b"Subject: ") or line.startswith(b"subject: ")
   345             ):
   345             ):
   346                 subject = line[9:]
   346                 subject = line[9:]
   347                 format = "tag"
   347                 format = b"tag"
   348             elif format != "tagdone" and (
   348             elif format != b"tagdone" and (
   349                 line.startswith("From: ") or line.startswith("from: ")
   349                 line.startswith(b"From: ") or line.startswith(b"from: ")
   350             ):
   350             ):
   351                 user = line[6:]
   351                 user = line[6:]
   352                 format = "tag"
   352                 format = b"tag"
   353             elif format != "tagdone" and (
   353             elif format != b"tagdone" and (
   354                 line.startswith("Date: ") or line.startswith("date: ")
   354                 line.startswith(b"Date: ") or line.startswith(b"date: ")
   355             ):
   355             ):
   356                 date = line[6:]
   356                 date = line[6:]
   357                 format = "tag"
   357                 format = b"tag"
   358             elif format == "tag" and line == "":
   358             elif format == b"tag" and line == b"":
   359                 # when looking for tags (subject: from: etc) they
   359                 # when looking for tags (subject: from: etc) they
   360                 # end once you find a blank line in the source
   360                 # end once you find a blank line in the source
   361                 format = "tagdone"
   361                 format = b"tagdone"
   362             elif message or line:
   362             elif message or line:
   363                 message.append(line)
   363                 message.append(line)
   364             comments.append(line)
   364             comments.append(line)
   365 
   365 
   366         eatdiff(message)
   366         eatdiff(message)
   370         self.diffstartline = len(comments)
   370         self.diffstartline = len(comments)
   371         eatempty(message)
   371         eatempty(message)
   372         eatempty(comments)
   372         eatempty(comments)
   373 
   373 
   374         # make sure message isn't empty
   374         # make sure message isn't empty
   375         if format and format.startswith("tag") and subject:
   375         if format and format.startswith(b"tag") and subject:
   376             message.insert(0, subject)
   376             message.insert(0, subject)
   377 
   377 
   378         self.message = message
   378         self.message = message
   379         self.comments = comments
   379         self.comments = comments
   380         self.user = user
   380         self.user = user
   384         self.nodeid = nodeid
   384         self.nodeid = nodeid
   385         self.branch = branch
   385         self.branch = branch
   386         self.haspatch = diffstart > 1
   386         self.haspatch = diffstart > 1
   387         self.plainmode = (
   387         self.plainmode = (
   388             plainmode
   388             plainmode
   389             or '# HG changeset patch' not in self.comments
   389             or b'# HG changeset patch' not in self.comments
   390             and any(
   390             and any(
   391                 c.startswith('Date: ') or c.startswith('From: ')
   391                 c.startswith(b'Date: ') or c.startswith(b'From: ')
   392                 for c in self.comments
   392                 for c in self.comments
   393             )
   393             )
   394         )
   394         )
   395 
   395 
   396     def setuser(self, user):
   396     def setuser(self, user):
   397         try:
   397         try:
   398             inserthgheader(self.comments, '# User ', user)
   398             inserthgheader(self.comments, b'# User ', user)
   399         except ValueError:
   399         except ValueError:
   400             if self.plainmode:
   400             if self.plainmode:
   401                 insertplainheader(self.comments, 'From', user)
   401                 insertplainheader(self.comments, b'From', user)
   402             else:
   402             else:
   403                 tmp = ['# HG changeset patch', '# User ' + user]
   403                 tmp = [b'# HG changeset patch', b'# User ' + user]
   404                 self.comments = tmp + self.comments
   404                 self.comments = tmp + self.comments
   405         self.user = user
   405         self.user = user
   406 
   406 
   407     def setdate(self, date):
   407     def setdate(self, date):
   408         try:
   408         try:
   409             inserthgheader(self.comments, '# Date ', date)
   409             inserthgheader(self.comments, b'# Date ', date)
   410         except ValueError:
   410         except ValueError:
   411             if self.plainmode:
   411             if self.plainmode:
   412                 insertplainheader(self.comments, 'Date', date)
   412                 insertplainheader(self.comments, b'Date', date)
   413             else:
   413             else:
   414                 tmp = ['# HG changeset patch', '# Date ' + date]
   414                 tmp = [b'# HG changeset patch', b'# Date ' + date]
   415                 self.comments = tmp + self.comments
   415                 self.comments = tmp + self.comments
   416         self.date = date
   416         self.date = date
   417 
   417 
   418     def setparent(self, parent):
   418     def setparent(self, parent):
   419         try:
   419         try:
   420             inserthgheader(self.comments, '# Parent  ', parent)
   420             inserthgheader(self.comments, b'# Parent  ', parent)
   421         except ValueError:
   421         except ValueError:
   422             if not self.plainmode:
   422             if not self.plainmode:
   423                 tmp = ['# HG changeset patch', '# Parent  ' + parent]
   423                 tmp = [b'# HG changeset patch', b'# Parent  ' + parent]
   424                 self.comments = tmp + self.comments
   424                 self.comments = tmp + self.comments
   425         self.parent = parent
   425         self.parent = parent
   426 
   426 
   427     def setmessage(self, message):
   427     def setmessage(self, message):
   428         if self.comments:
   428         if self.comments:
   429             self._delmsg()
   429             self._delmsg()
   430         self.message = [message]
   430         self.message = [message]
   431         if message:
   431         if message:
   432             if self.plainmode and self.comments and self.comments[-1]:
   432             if self.plainmode and self.comments and self.comments[-1]:
   433                 self.comments.append('')
   433                 self.comments.append(b'')
   434             self.comments.append(message)
   434             self.comments.append(message)
   435 
   435 
   436     def __bytes__(self):
   436     def __bytes__(self):
   437         s = '\n'.join(self.comments).rstrip()
   437         s = b'\n'.join(self.comments).rstrip()
   438         if not s:
   438         if not s:
   439             return ''
   439             return b''
   440         return s + '\n\n'
   440         return s + b'\n\n'
   441 
   441 
   442     __str__ = encoding.strmethod(__bytes__)
   442     __str__ = encoding.strmethod(__bytes__)
   443 
   443 
   444     def _delmsg(self):
   444     def _delmsg(self):
   445         '''Remove existing message, keeping the rest of the comments fields.
   445         '''Remove existing message, keeping the rest of the comments fields.
   446         If comments contains 'subject: ', message will prepend
   446         If comments contains 'subject: ', message will prepend
   447         the field and a blank line.'''
   447         the field and a blank line.'''
   448         if self.message:
   448         if self.message:
   449             subj = 'subject: ' + self.message[0].lower()
   449             subj = b'subject: ' + self.message[0].lower()
   450             for i in pycompat.xrange(len(self.comments)):
   450             for i in pycompat.xrange(len(self.comments)):
   451                 if subj == self.comments[i].lower():
   451                 if subj == self.comments[i].lower():
   452                     del self.comments[i]
   452                     del self.comments[i]
   453                     self.message = self.message[2:]
   453                     self.message = self.message[2:]
   454                     break
   454                     break
   465     It should be used instead of repo.commit inside the mq source for operation
   465     It should be used instead of repo.commit inside the mq source for operation
   466     creating new changeset.
   466     creating new changeset.
   467     """
   467     """
   468     repo = repo.unfiltered()
   468     repo = repo.unfiltered()
   469     if phase is None:
   469     if phase is None:
   470         if repo.ui.configbool('mq', 'secret'):
   470         if repo.ui.configbool(b'mq', b'secret'):
   471             phase = phases.secret
   471             phase = phases.secret
   472     overrides = {('ui', 'allowemptycommit'): True}
   472     overrides = {(b'ui', b'allowemptycommit'): True}
   473     if phase is not None:
   473     if phase is not None:
   474         overrides[('phases', 'new-commit')] = phase
   474         overrides[(b'phases', b'new-commit')] = phase
   475     with repo.ui.configoverride(overrides, 'mq'):
   475     with repo.ui.configoverride(overrides, b'mq'):
   476         repo.ui.setconfig('ui', 'allowemptycommit', True)
   476         repo.ui.setconfig(b'ui', b'allowemptycommit', True)
   477         return repo.commit(*args, **kwargs)
   477         return repo.commit(*args, **kwargs)
   478 
   478 
   479 
   479 
   480 class AbortNoCleanup(error.Abort):
   480 class AbortNoCleanup(error.Abort):
   481     pass
   481     pass
   483 
   483 
   484 class queue(object):
   484 class queue(object):
   485     def __init__(self, ui, baseui, path, patchdir=None):
   485     def __init__(self, ui, baseui, path, patchdir=None):
   486         self.basepath = path
   486         self.basepath = path
   487         try:
   487         try:
   488             with open(os.path.join(path, 'patches.queue'), r'rb') as fh:
   488             with open(os.path.join(path, b'patches.queue'), r'rb') as fh:
   489                 cur = fh.read().rstrip()
   489                 cur = fh.read().rstrip()
   490 
   490 
   491             if not cur:
   491             if not cur:
   492                 curpath = os.path.join(path, 'patches')
   492                 curpath = os.path.join(path, b'patches')
   493             else:
   493             else:
   494                 curpath = os.path.join(path, 'patches-' + cur)
   494                 curpath = os.path.join(path, b'patches-' + cur)
   495         except IOError:
   495         except IOError:
   496             curpath = os.path.join(path, 'patches')
   496             curpath = os.path.join(path, b'patches')
   497         self.path = patchdir or curpath
   497         self.path = patchdir or curpath
   498         self.opener = vfsmod.vfs(self.path)
   498         self.opener = vfsmod.vfs(self.path)
   499         self.ui = ui
   499         self.ui = ui
   500         self.baseui = baseui
   500         self.baseui = baseui
   501         self.applieddirty = False
   501         self.applieddirty = False
   502         self.seriesdirty = False
   502         self.seriesdirty = False
   503         self.added = []
   503         self.added = []
   504         self.seriespath = "series"
   504         self.seriespath = b"series"
   505         self.statuspath = "status"
   505         self.statuspath = b"status"
   506         self.guardspath = "guards"
   506         self.guardspath = b"guards"
   507         self.activeguards = None
   507         self.activeguards = None
   508         self.guardsdirty = False
   508         self.guardsdirty = False
   509         # Handle mq.git as a bool with extended values
   509         # Handle mq.git as a bool with extended values
   510         gitmode = ui.config('mq', 'git').lower()
   510         gitmode = ui.config(b'mq', b'git').lower()
   511         boolmode = stringutil.parsebool(gitmode)
   511         boolmode = stringutil.parsebool(gitmode)
   512         if boolmode is not None:
   512         if boolmode is not None:
   513             if boolmode:
   513             if boolmode:
   514                 gitmode = 'yes'
   514                 gitmode = b'yes'
   515             else:
   515             else:
   516                 gitmode = 'no'
   516                 gitmode = b'no'
   517         self.gitmode = gitmode
   517         self.gitmode = gitmode
   518         # deprecated config: mq.plain
   518         # deprecated config: mq.plain
   519         self.plainmode = ui.configbool('mq', 'plain')
   519         self.plainmode = ui.configbool(b'mq', b'plain')
   520         self.checkapplied = True
   520         self.checkapplied = True
   521 
   521 
   522     @util.propertycache
   522     @util.propertycache
   523     def applied(self):
   523     def applied(self):
   524         def parselines(lines):
   524         def parselines(lines):
   525             for l in lines:
   525             for l in lines:
   526                 entry = l.split(':', 1)
   526                 entry = l.split(b':', 1)
   527                 if len(entry) > 1:
   527                 if len(entry) > 1:
   528                     n, name = entry
   528                     n, name = entry
   529                     yield statusentry(bin(n), name)
   529                     yield statusentry(bin(n), name)
   530                 elif l.strip():
   530                 elif l.strip():
   531                     self.ui.warn(
   531                     self.ui.warn(
   532                         _('malformated mq status line: %s\n')
   532                         _(b'malformated mq status line: %s\n')
   533                         % stringutil.pprint(entry)
   533                         % stringutil.pprint(entry)
   534                     )
   534                     )
   535                 # else we ignore empty lines
   535                 # else we ignore empty lines
   536 
   536 
   537         try:
   537         try:
   560     def seriesguards(self):
   560     def seriesguards(self):
   561         self.parseseries()
   561         self.parseseries()
   562         return self.seriesguards
   562         return self.seriesguards
   563 
   563 
   564     def invalidate(self):
   564     def invalidate(self):
   565         for a in 'applied fullseries series seriesguards'.split():
   565         for a in b'applied fullseries series seriesguards'.split():
   566             if a in self.__dict__:
   566             if a in self.__dict__:
   567                 delattr(self, a)
   567                 delattr(self, a)
   568         self.applieddirty = False
   568         self.applieddirty = False
   569         self.seriesdirty = False
   569         self.seriesdirty = False
   570         self.guardsdirty = False
   570         self.guardsdirty = False
   578             opts,
   578             opts,
   579             git=True,
   579             git=True,
   580             whitespace=not plain,
   580             whitespace=not plain,
   581             formatchanging=not plain,
   581             formatchanging=not plain,
   582         )
   582         )
   583         if self.gitmode == 'auto':
   583         if self.gitmode == b'auto':
   584             diffopts.upgrade = True
   584             diffopts.upgrade = True
   585         elif self.gitmode == 'keep':
   585         elif self.gitmode == b'keep':
   586             pass
   586             pass
   587         elif self.gitmode in ('yes', 'no'):
   587         elif self.gitmode in (b'yes', b'no'):
   588             diffopts.git = self.gitmode == 'yes'
   588             diffopts.git = self.gitmode == b'yes'
   589         else:
   589         else:
   590             raise error.Abort(
   590             raise error.Abort(
   591                 _('mq.git option can be auto/keep/yes/no' ' got %s')
   591                 _(b'mq.git option can be auto/keep/yes/no' b' got %s')
   592                 % self.gitmode
   592                 % self.gitmode
   593             )
   593             )
   594         if patchfn:
   594         if patchfn:
   595             diffopts = self.patchopts(diffopts, patchfn)
   595             diffopts = self.patchopts(diffopts, patchfn)
   596         return diffopts
   596         return diffopts
   598     def patchopts(self, diffopts, *patches):
   598     def patchopts(self, diffopts, *patches):
   599         """Return a copy of input diff options with git set to true if
   599         """Return a copy of input diff options with git set to true if
   600         referenced patch is a git patch and should be preserved as such.
   600         referenced patch is a git patch and should be preserved as such.
   601         """
   601         """
   602         diffopts = diffopts.copy()
   602         diffopts = diffopts.copy()
   603         if not diffopts.git and self.gitmode == 'keep':
   603         if not diffopts.git and self.gitmode == b'keep':
   604             for patchfn in patches:
   604             for patchfn in patches:
   605                 patchf = self.opener(patchfn, 'r')
   605                 patchf = self.opener(patchfn, b'r')
   606                 # if the patch was a git patch, refresh it as a git patch
   606                 # if the patch was a git patch, refresh it as a git patch
   607                 diffopts.git = any(
   607                 diffopts.git = any(
   608                     line.startswith('diff --git') for line in patchf
   608                     line.startswith(b'diff --git') for line in patchf
   609                 )
   609                 )
   610                 patchf.close()
   610                 patchf.close()
   611         return diffopts
   611         return diffopts
   612 
   612 
   613     def join(self, *p):
   613     def join(self, *p):
   614         return os.path.join(self.path, *p)
   614         return os.path.join(self.path, *p)
   615 
   615 
   616     def findseries(self, patch):
   616     def findseries(self, patch):
   617         def matchpatch(l):
   617         def matchpatch(l):
   618             l = l.split('#', 1)[0]
   618             l = l.split(b'#', 1)[0]
   619             return l.strip() == patch
   619             return l.strip() == patch
   620 
   620 
   621         for index, l in enumerate(self.fullseries):
   621         for index, l in enumerate(self.fullseries):
   622             if matchpatch(l):
   622             if matchpatch(l):
   623                 return index
   623                 return index
   627 
   627 
   628     def parseseries(self):
   628     def parseseries(self):
   629         self.series = []
   629         self.series = []
   630         self.seriesguards = []
   630         self.seriesguards = []
   631         for l in self.fullseries:
   631         for l in self.fullseries:
   632             h = l.find('#')
   632             h = l.find(b'#')
   633             if h == -1:
   633             if h == -1:
   634                 patch = l
   634                 patch = l
   635                 comment = ''
   635                 comment = b''
   636             elif h == 0:
   636             elif h == 0:
   637                 continue
   637                 continue
   638             else:
   638             else:
   639                 patch = l[:h]
   639                 patch = l[:h]
   640                 comment = l[h:]
   640                 comment = l[h:]
   641             patch = patch.strip()
   641             patch = patch.strip()
   642             if patch:
   642             if patch:
   643                 if patch in self.series:
   643                 if patch in self.series:
   644                     raise error.Abort(
   644                     raise error.Abort(
   645                         _('%s appears more than once in %s')
   645                         _(b'%s appears more than once in %s')
   646                         % (patch, self.join(self.seriespath))
   646                         % (patch, self.join(self.seriespath))
   647                     )
   647                     )
   648                 self.series.append(patch)
   648                 self.series.append(patch)
   649                 self.seriesguards.append(self.guard_re.findall(comment))
   649                 self.seriesguards.append(self.guard_re.findall(comment))
   650 
   650 
   651     def checkguard(self, guard):
   651     def checkguard(self, guard):
   652         if not guard:
   652         if not guard:
   653             return _('guard cannot be an empty string')
   653             return _(b'guard cannot be an empty string')
   654         bad_chars = '# \t\r\n\f'
   654         bad_chars = b'# \t\r\n\f'
   655         first = guard[0]
   655         first = guard[0]
   656         if first in '-+':
   656         if first in b'-+':
   657             return _('guard %r starts with invalid character: %r') % (
   657             return _(b'guard %r starts with invalid character: %r') % (
   658                 guard,
   658                 guard,
   659                 first,
   659                 first,
   660             )
   660             )
   661         for c in bad_chars:
   661         for c in bad_chars:
   662             if c in guard:
   662             if c in guard:
   663                 return _('invalid character in guard %r: %r') % (guard, c)
   663                 return _(b'invalid character in guard %r: %r') % (guard, c)
   664 
   664 
   665     def setactive(self, guards):
   665     def setactive(self, guards):
   666         for guard in guards:
   666         for guard in guards:
   667             bad = self.checkguard(guard)
   667             bad = self.checkguard(guard)
   668             if bad:
   668             if bad:
   669                 raise error.Abort(bad)
   669                 raise error.Abort(bad)
   670         guards = sorted(set(guards))
   670         guards = sorted(set(guards))
   671         self.ui.debug('active guards: %s\n' % ' '.join(guards))
   671         self.ui.debug(b'active guards: %s\n' % b' '.join(guards))
   672         self.activeguards = guards
   672         self.activeguards = guards
   673         self.guardsdirty = True
   673         self.guardsdirty = True
   674 
   674 
   675     def active(self):
   675     def active(self):
   676         if self.activeguards is None:
   676         if self.activeguards is None:
   683                 guards = []
   683                 guards = []
   684             for i, guard in enumerate(guards):
   684             for i, guard in enumerate(guards):
   685                 bad = self.checkguard(guard)
   685                 bad = self.checkguard(guard)
   686                 if bad:
   686                 if bad:
   687                     self.ui.warn(
   687                     self.ui.warn(
   688                         '%s:%d: %s\n' % (self.join(self.guardspath), i + 1, bad)
   688                         b'%s:%d: %s\n'
       
   689                         % (self.join(self.guardspath), i + 1, bad)
   689                     )
   690                     )
   690                 else:
   691                 else:
   691                     self.activeguards.append(guard)
   692                     self.activeguards.append(guard)
   692         return self.activeguards
   693         return self.activeguards
   693 
   694 
   694     def setguards(self, idx, guards):
   695     def setguards(self, idx, guards):
   695         for g in guards:
   696         for g in guards:
   696             if len(g) < 2:
   697             if len(g) < 2:
   697                 raise error.Abort(_('guard %r too short') % g)
   698                 raise error.Abort(_(b'guard %r too short') % g)
   698             if g[0] not in '-+':
   699             if g[0] not in b'-+':
   699                 raise error.Abort(_('guard %r starts with invalid char') % g)
   700                 raise error.Abort(_(b'guard %r starts with invalid char') % g)
   700             bad = self.checkguard(g[1:])
   701             bad = self.checkguard(g[1:])
   701             if bad:
   702             if bad:
   702                 raise error.Abort(bad)
   703                 raise error.Abort(bad)
   703         drop = self.guard_re.sub('', self.fullseries[idx])
   704         drop = self.guard_re.sub(b'', self.fullseries[idx])
   704         self.fullseries[idx] = drop + ''.join([' #' + g for g in guards])
   705         self.fullseries[idx] = drop + b''.join([b' #' + g for g in guards])
   705         self.parseseries()
   706         self.parseseries()
   706         self.seriesdirty = True
   707         self.seriesdirty = True
   707 
   708 
   708     def pushable(self, idx):
   709     def pushable(self, idx):
   709         if isinstance(idx, bytes):
   710         if isinstance(idx, bytes):
   711         patchguards = self.seriesguards[idx]
   712         patchguards = self.seriesguards[idx]
   712         if not patchguards:
   713         if not patchguards:
   713             return True, None
   714             return True, None
   714         guards = self.active()
   715         guards = self.active()
   715         exactneg = [
   716         exactneg = [
   716             g for g in patchguards if g.startswith('-') and g[1:] in guards
   717             g for g in patchguards if g.startswith(b'-') and g[1:] in guards
   717         ]
   718         ]
   718         if exactneg:
   719         if exactneg:
   719             return False, stringutil.pprint(exactneg[0])
   720             return False, stringutil.pprint(exactneg[0])
   720         pos = [g for g in patchguards if g.startswith('+')]
   721         pos = [g for g in patchguards if g.startswith(b'+')]
   721         exactpos = [g for g in pos if g[1:] in guards]
   722         exactpos = [g for g in pos if g[1:] in guards]
   722         if pos:
   723         if pos:
   723             if exactpos:
   724             if exactpos:
   724                 return True, stringutil.pprint(exactpos[0])
   725                 return True, stringutil.pprint(exactpos[0])
   725             return False, ' '.join([stringutil.pprint(p) for p in pos])
   726             return False, b' '.join([stringutil.pprint(p) for p in pos])
   726         return True, ''
   727         return True, b''
   727 
   728 
   728     def explainpushable(self, idx, all_patches=False):
   729     def explainpushable(self, idx, all_patches=False):
   729         if all_patches:
   730         if all_patches:
   730             write = self.ui.write
   731             write = self.ui.write
   731         else:
   732         else:
   736                 idx = self.series.index(idx)
   737                 idx = self.series.index(idx)
   737             pushable, why = self.pushable(idx)
   738             pushable, why = self.pushable(idx)
   738             if all_patches and pushable:
   739             if all_patches and pushable:
   739                 if why is None:
   740                 if why is None:
   740                     write(
   741                     write(
   741                         _('allowing %s - no guards in effect\n')
   742                         _(b'allowing %s - no guards in effect\n')
   742                         % self.series[idx]
   743                         % self.series[idx]
   743                     )
   744                     )
   744                 else:
   745                 else:
   745                     if not why:
   746                     if not why:
   746                         write(
   747                         write(
   747                             _('allowing %s - no matching negative guards\n')
   748                             _(b'allowing %s - no matching negative guards\n')
   748                             % self.series[idx]
   749                             % self.series[idx]
   749                         )
   750                         )
   750                     else:
   751                     else:
   751                         write(
   752                         write(
   752                             _('allowing %s - guarded by %s\n')
   753                             _(b'allowing %s - guarded by %s\n')
   753                             % (self.series[idx], why)
   754                             % (self.series[idx], why)
   754                         )
   755                         )
   755             if not pushable:
   756             if not pushable:
   756                 if why:
   757                 if why:
   757                     write(
   758                     write(
   758                         _('skipping %s - guarded by %s\n')
   759                         _(b'skipping %s - guarded by %s\n')
   759                         % (self.series[idx], why)
   760                         % (self.series[idx], why)
   760                     )
   761                     )
   761                 else:
   762                 else:
   762                     write(
   763                     write(
   763                         _('skipping %s - no matching guards\n')
   764                         _(b'skipping %s - no matching guards\n')
   764                         % self.series[idx]
   765                         % self.series[idx]
   765                     )
   766                     )
   766 
   767 
   767     def savedirty(self):
   768     def savedirty(self):
   768         def writelist(items, path):
   769         def writelist(items, path):
   769             fp = self.opener(path, 'wb')
   770             fp = self.opener(path, b'wb')
   770             for i in items:
   771             for i in items:
   771                 fp.write("%s\n" % i)
   772                 fp.write(b"%s\n" % i)
   772             fp.close()
   773             fp.close()
   773 
   774 
   774         if self.applieddirty:
   775         if self.applieddirty:
   775             writelist(map(bytes, self.applied), self.statuspath)
   776             writelist(map(bytes, self.applied), self.statuspath)
   776             self.applieddirty = False
   777             self.applieddirty = False
   785             if qrepo:
   786             if qrepo:
   786                 qrepo[None].add(f for f in self.added if f not in qrepo[None])
   787                 qrepo[None].add(f for f in self.added if f not in qrepo[None])
   787             self.added = []
   788             self.added = []
   788 
   789 
   789     def removeundo(self, repo):
   790     def removeundo(self, repo):
   790         undo = repo.sjoin('undo')
   791         undo = repo.sjoin(b'undo')
   791         if not os.path.exists(undo):
   792         if not os.path.exists(undo):
   792             return
   793             return
   793         try:
   794         try:
   794             os.unlink(undo)
   795             os.unlink(undo)
   795         except OSError as inst:
   796         except OSError as inst:
   796             self.ui.warn(
   797             self.ui.warn(
   797                 _('error removing undo: %s\n') % stringutil.forcebytestr(inst)
   798                 _(b'error removing undo: %s\n') % stringutil.forcebytestr(inst)
   798             )
   799             )
   799 
   800 
   800     def backup(self, repo, files, copy=False):
   801     def backup(self, repo, files, copy=False):
   801         # backup local changes in --force case
   802         # backup local changes in --force case
   802         for f in sorted(files):
   803         for f in sorted(files):
   803             absf = repo.wjoin(f)
   804             absf = repo.wjoin(f)
   804             if os.path.lexists(absf):
   805             if os.path.lexists(absf):
   805                 absorig = scmutil.backuppath(self.ui, repo, f)
   806                 absorig = scmutil.backuppath(self.ui, repo, f)
   806                 self.ui.note(
   807                 self.ui.note(
   807                     _('saving current version of %s as %s\n')
   808                     _(b'saving current version of %s as %s\n')
   808                     % (f, os.path.relpath(absorig))
   809                     % (f, os.path.relpath(absorig))
   809                 )
   810                 )
   810 
   811 
   811                 if copy:
   812                 if copy:
   812                     util.copyfile(absf, absorig)
   813                     util.copyfile(absf, absorig)
   824         changes=None,
   825         changes=None,
   825         opts=None,
   826         opts=None,
   826     ):
   827     ):
   827         if opts is None:
   828         if opts is None:
   828             opts = {}
   829             opts = {}
   829         stat = opts.get('stat')
   830         stat = opts.get(b'stat')
   830         m = scmutil.match(repo[node1], files, opts)
   831         m = scmutil.match(repo[node1], files, opts)
   831         logcmdutil.diffordiffstat(
   832         logcmdutil.diffordiffstat(
   832             self.ui, repo, diffopts, node1, node2, m, changes, stat, fp
   833             self.ui, repo, diffopts, node1, node2, m, changes, stat, fp
   833         )
   834         )
   834 
   835 
   840 
   841 
   841         if err == 0:
   842         if err == 0:
   842             return (err, n)
   843             return (err, n)
   843 
   844 
   844         if n is None:
   845         if n is None:
   845             raise error.Abort(_("apply failed for patch %s") % patch)
   846             raise error.Abort(_(b"apply failed for patch %s") % patch)
   846 
   847 
   847         self.ui.warn(_("patch didn't work out, merging %s\n") % patch)
   848         self.ui.warn(_(b"patch didn't work out, merging %s\n") % patch)
   848 
   849 
   849         # apply failed, strip away that rev and merge.
   850         # apply failed, strip away that rev and merge.
   850         hg.clean(repo, head)
   851         hg.clean(repo, head)
   851         strip(self.ui, repo, [n], update=False, backup=False)
   852         strip(self.ui, repo, [n], update=False, backup=False)
   852 
   853 
   853         ctx = repo[rev]
   854         ctx = repo[rev]
   854         ret = hg.merge(repo, rev)
   855         ret = hg.merge(repo, rev)
   855         if ret:
   856         if ret:
   856             raise error.Abort(_("update returned %d") % ret)
   857             raise error.Abort(_(b"update returned %d") % ret)
   857         n = newcommit(repo, None, ctx.description(), ctx.user(), force=True)
   858         n = newcommit(repo, None, ctx.description(), ctx.user(), force=True)
   858         if n is None:
   859         if n is None:
   859             raise error.Abort(_("repo commit failed"))
   860             raise error.Abort(_(b"repo commit failed"))
   860         try:
   861         try:
   861             ph = patchheader(mergeq.join(patch), self.plainmode)
   862             ph = patchheader(mergeq.join(patch), self.plainmode)
   862         except Exception:
   863         except Exception:
   863             raise error.Abort(_("unable to read %s") % patch)
   864             raise error.Abort(_(b"unable to read %s") % patch)
   864 
   865 
   865         diffopts = self.patchopts(diffopts, patch)
   866         diffopts = self.patchopts(diffopts, patch)
   866         patchf = self.opener(patch, "w")
   867         patchf = self.opener(patch, b"w")
   867         comments = bytes(ph)
   868         comments = bytes(ph)
   868         if comments:
   869         if comments:
   869             patchf.write(comments)
   870             patchf.write(comments)
   870         self.printdiff(repo, diffopts, head, n, fp=patchf)
   871         self.printdiff(repo, diffopts, head, n, fp=patchf)
   871         patchf.close()
   872         patchf.close()
   899             # can confuse the qrefresh, qdiff, and strip code because it
   900             # can confuse the qrefresh, qdiff, and strip code because it
   900             # needs to know which parent is actually in the patch queue.
   901             # needs to know which parent is actually in the patch queue.
   901             # so, we insert a merge marker with only one parent.  This way
   902             # so, we insert a merge marker with only one parent.  This way
   902             # the first patch in the queue is never a merge patch
   903             # the first patch in the queue is never a merge patch
   903             #
   904             #
   904             pname = ".hg.patches.merge.marker"
   905             pname = b".hg.patches.merge.marker"
   905             n = newcommit(repo, None, '[mq]: merge marker', force=True)
   906             n = newcommit(repo, None, b'[mq]: merge marker', force=True)
   906             self.removeundo(repo)
   907             self.removeundo(repo)
   907             self.applied.append(statusentry(n, pname))
   908             self.applied.append(statusentry(n, pname))
   908             self.applieddirty = True
   909             self.applieddirty = True
   909 
   910 
   910         head = self.qparents(repo)
   911         head = self.qparents(repo)
   911 
   912 
   912         for patch in series:
   913         for patch in series:
   913             patch = mergeq.lookup(patch, strict=True)
   914             patch = mergeq.lookup(patch, strict=True)
   914             if not patch:
   915             if not patch:
   915                 self.ui.warn(_("patch %s does not exist\n") % patch)
   916                 self.ui.warn(_(b"patch %s does not exist\n") % patch)
   916                 return (1, None)
   917                 return (1, None)
   917             pushable, reason = self.pushable(patch)
   918             pushable, reason = self.pushable(patch)
   918             if not pushable:
   919             if not pushable:
   919                 self.explainpushable(patch, all_patches=True)
   920                 self.explainpushable(patch, all_patches=True)
   920                 continue
   921                 continue
   921             info = mergeq.isapplied(patch)
   922             info = mergeq.isapplied(patch)
   922             if not info:
   923             if not info:
   923                 self.ui.warn(_("patch %s is not applied\n") % patch)
   924                 self.ui.warn(_(b"patch %s is not applied\n") % patch)
   924                 return (1, None)
   925                 return (1, None)
   925             rev = info[1]
   926             rev = info[1]
   926             err, head = self.mergeone(repo, mergeq, head, patch, rev, diffopts)
   927             err, head = self.mergeone(repo, mergeq, head, patch, rev, diffopts)
   927             if head:
   928             if head:
   928                 self.applied.append(statusentry(head, patch))
   929                 self.applied.append(statusentry(head, patch))
   940             fuzz = patchmod.patch(
   941             fuzz = patchmod.patch(
   941                 self.ui, repo, patchfile, strip=1, files=files, eolmode=None
   942                 self.ui, repo, patchfile, strip=1, files=files, eolmode=None
   942             )
   943             )
   943             return (True, list(files), fuzz)
   944             return (True, list(files), fuzz)
   944         except Exception as inst:
   945         except Exception as inst:
   945             self.ui.note(stringutil.forcebytestr(inst) + '\n')
   946             self.ui.note(stringutil.forcebytestr(inst) + b'\n')
   946             if not self.ui.verbose:
   947             if not self.ui.verbose:
   947                 self.ui.warn(_("patch failed, unable to continue (try -v)\n"))
   948                 self.ui.warn(_(b"patch failed, unable to continue (try -v)\n"))
   948             self.ui.traceback()
   949             self.ui.traceback()
   949             return (False, list(files), False)
   950             return (False, list(files), False)
   950 
   951 
   951     def apply(
   952     def apply(
   952         self,
   953         self,
   963     ):
   964     ):
   964         wlock = lock = tr = None
   965         wlock = lock = tr = None
   965         try:
   966         try:
   966             wlock = repo.wlock()
   967             wlock = repo.wlock()
   967             lock = repo.lock()
   968             lock = repo.lock()
   968             tr = repo.transaction("qpush")
   969             tr = repo.transaction(b"qpush")
   969             try:
   970             try:
   970                 ret = self._apply(
   971                 ret = self._apply(
   971                     repo,
   972                     repo,
   972                     series,
   973                     series,
   973                     list,
   974                     list,
  1023         for patchname in series:
  1024         for patchname in series:
  1024             pushable, reason = self.pushable(patchname)
  1025             pushable, reason = self.pushable(patchname)
  1025             if not pushable:
  1026             if not pushable:
  1026                 self.explainpushable(patchname, all_patches=True)
  1027                 self.explainpushable(patchname, all_patches=True)
  1027                 continue
  1028                 continue
  1028             self.ui.status(_("applying %s\n") % patchname)
  1029             self.ui.status(_(b"applying %s\n") % patchname)
  1029             pf = os.path.join(patchdir, patchname)
  1030             pf = os.path.join(patchdir, patchname)
  1030 
  1031 
  1031             try:
  1032             try:
  1032                 ph = patchheader(self.join(patchname), self.plainmode)
  1033                 ph = patchheader(self.join(patchname), self.plainmode)
  1033             except IOError:
  1034             except IOError:
  1034                 self.ui.warn(_("unable to read %s\n") % patchname)
  1035                 self.ui.warn(_(b"unable to read %s\n") % patchname)
  1035                 err = 1
  1036                 err = 1
  1036                 break
  1037                 break
  1037 
  1038 
  1038             message = ph.message
  1039             message = ph.message
  1039             if not message:
  1040             if not message:
  1040                 # The commit message should not be translated
  1041                 # The commit message should not be translated
  1041                 message = "imported patch %s\n" % patchname
  1042                 message = b"imported patch %s\n" % patchname
  1042             else:
  1043             else:
  1043                 if list:
  1044                 if list:
  1044                     # The commit message should not be translated
  1045                     # The commit message should not be translated
  1045                     message.append("\nimported patch %s" % patchname)
  1046                     message.append(b"\nimported patch %s" % patchname)
  1046                 message = '\n'.join(message)
  1047                 message = b'\n'.join(message)
  1047 
  1048 
  1048             if ph.haspatch:
  1049             if ph.haspatch:
  1049                 if tobackup:
  1050                 if tobackup:
  1050                     touched = patchmod.changedfiles(self.ui, repo, pf)
  1051                     touched = patchmod.changedfiles(self.ui, repo, pf)
  1051                     touched = set(touched) & tobackup
  1052                     touched = set(touched) & tobackup
  1052                     if touched and keepchanges:
  1053                     if touched and keepchanges:
  1053                         raise AbortNoCleanup(
  1054                         raise AbortNoCleanup(
  1054                             _("conflicting local changes found"),
  1055                             _(b"conflicting local changes found"),
  1055                             hint=_("did you forget to qrefresh?"),
  1056                             hint=_(b"did you forget to qrefresh?"),
  1056                         )
  1057                         )
  1057                     self.backup(repo, touched, copy=True)
  1058                     self.backup(repo, touched, copy=True)
  1058                     tobackup = tobackup - touched
  1059                     tobackup = tobackup - touched
  1059                 (patcherr, files, fuzz) = self.patch(repo, pf)
  1060                 (patcherr, files, fuzz) = self.patch(repo, pf)
  1060                 if all_files is not None:
  1061                 if all_files is not None:
  1061                     all_files.update(files)
  1062                     all_files.update(files)
  1062                 patcherr = not patcherr
  1063                 patcherr = not patcherr
  1063             else:
  1064             else:
  1064                 self.ui.warn(_("patch %s is empty\n") % patchname)
  1065                 self.ui.warn(_(b"patch %s is empty\n") % patchname)
  1065                 patcherr, files, fuzz = 0, [], 0
  1066                 patcherr, files, fuzz = 0, [], 0
  1066 
  1067 
  1067             if merge and files:
  1068             if merge and files:
  1068                 # Mark as removed/merged and update dirstate parent info
  1069                 # Mark as removed/merged and update dirstate parent info
  1069                 removed = []
  1070                 removed = []
  1079                     for f in merged:
  1080                     for f in merged:
  1080                         repo.dirstate.merge(f)
  1081                         repo.dirstate.merge(f)
  1081                     p1 = repo.dirstate.p1()
  1082                     p1 = repo.dirstate.p1()
  1082                     repo.setparents(p1, merge)
  1083                     repo.setparents(p1, merge)
  1083 
  1084 
  1084             if all_files and '.hgsubstate' in all_files:
  1085             if all_files and b'.hgsubstate' in all_files:
  1085                 wctx = repo[None]
  1086                 wctx = repo[None]
  1086                 pctx = repo['.']
  1087                 pctx = repo[b'.']
  1087                 overwrite = False
  1088                 overwrite = False
  1088                 mergedsubstate = subrepoutil.submerge(
  1089                 mergedsubstate = subrepoutil.submerge(
  1089                     repo, pctx, wctx, wctx, overwrite
  1090                     repo, pctx, wctx, wctx, overwrite
  1090                 )
  1091                 )
  1091                 files += mergedsubstate.keys()
  1092                 files += mergedsubstate.keys()
  1094             oldtip = repo.changelog.tip()
  1095             oldtip = repo.changelog.tip()
  1095             n = newcommit(
  1096             n = newcommit(
  1096                 repo, None, message, ph.user, ph.date, match=match, force=True
  1097                 repo, None, message, ph.user, ph.date, match=match, force=True
  1097             )
  1098             )
  1098             if repo.changelog.tip() == oldtip:
  1099             if repo.changelog.tip() == oldtip:
  1099                 raise error.Abort(_("qpush exactly duplicates child changeset"))
  1100                 raise error.Abort(
       
  1101                     _(b"qpush exactly duplicates child changeset")
       
  1102                 )
  1100             if n is None:
  1103             if n is None:
  1101                 raise error.Abort(_("repository commit failed"))
  1104                 raise error.Abort(_(b"repository commit failed"))
  1102 
  1105 
  1103             if update_status:
  1106             if update_status:
  1104                 self.applied.append(statusentry(n, patchname))
  1107                 self.applied.append(statusentry(n, patchname))
  1105 
  1108 
  1106             if patcherr:
  1109             if patcherr:
  1107                 self.ui.warn(
  1110                 self.ui.warn(
  1108                     _("patch failed, rejects left in working " "directory\n")
  1111                     _(b"patch failed, rejects left in working " b"directory\n")
  1109                 )
  1112                 )
  1110                 err = 2
  1113                 err = 2
  1111                 break
  1114                 break
  1112 
  1115 
  1113             if fuzz and strict:
  1116             if fuzz and strict:
  1114                 self.ui.warn(_("fuzz found when applying patch, stopping\n"))
  1117                 self.ui.warn(_(b"fuzz found when applying patch, stopping\n"))
  1115                 err = 3
  1118                 err = 3
  1116                 break
  1119                 break
  1117         return (err, n)
  1120         return (err, n)
  1118 
  1121 
  1119     def _cleanup(self, patches, numrevs, keep=False):
  1122     def _cleanup(self, patches, numrevs, keep=False):
  1153 
  1156 
  1154         if unknown:
  1157         if unknown:
  1155             if numrevs:
  1158             if numrevs:
  1156                 rev = dict((entry.name, entry.node) for entry in qfinished)
  1159                 rev = dict((entry.name, entry.node) for entry in qfinished)
  1157                 for p in unknown:
  1160                 for p in unknown:
  1158                     msg = _('revision %s refers to unknown patches: %s\n')
  1161                     msg = _(b'revision %s refers to unknown patches: %s\n')
  1159                     self.ui.warn(msg % (short(rev[p]), p))
  1162                     self.ui.warn(msg % (short(rev[p]), p))
  1160             else:
  1163             else:
  1161                 msg = _('unknown patches: %s\n')
  1164                 msg = _(b'unknown patches: %s\n')
  1162                 raise error.Abort(''.join(msg % p for p in unknown))
  1165                 raise error.Abort(b''.join(msg % p for p in unknown))
  1163 
  1166 
  1164         self.parseseries()
  1167         self.parseseries()
  1165         self.seriesdirty = True
  1168         self.seriesdirty = True
  1166         return [entry.node for entry in qfinished]
  1169         return [entry.node for entry in qfinished]
  1167 
  1170 
  1169         firstrev = repo[self.applied[0].node].rev()
  1172         firstrev = repo[self.applied[0].node].rev()
  1170         patches = []
  1173         patches = []
  1171         for i, rev in enumerate(revs):
  1174         for i, rev in enumerate(revs):
  1172 
  1175 
  1173             if rev < firstrev:
  1176             if rev < firstrev:
  1174                 raise error.Abort(_('revision %d is not managed') % rev)
  1177                 raise error.Abort(_(b'revision %d is not managed') % rev)
  1175 
  1178 
  1176             ctx = repo[rev]
  1179             ctx = repo[rev]
  1177             base = self.applied[i].node
  1180             base = self.applied[i].node
  1178             if ctx.node() != base:
  1181             if ctx.node() != base:
  1179                 msg = _('cannot delete revision %d above applied patches')
  1182                 msg = _(b'cannot delete revision %d above applied patches')
  1180                 raise error.Abort(msg % rev)
  1183                 raise error.Abort(msg % rev)
  1181 
  1184 
  1182             patch = self.applied[i].name
  1185             patch = self.applied[i].name
  1183             for fmt in ('[mq]: %s', 'imported patch %s'):
  1186             for fmt in (b'[mq]: %s', b'imported patch %s'):
  1184                 if ctx.description() == fmt % patch:
  1187                 if ctx.description() == fmt % patch:
  1185                     msg = _('patch %s finalized without changeset message\n')
  1188                     msg = _(b'patch %s finalized without changeset message\n')
  1186                     repo.ui.status(msg % patch)
  1189                     repo.ui.status(msg % patch)
  1187                     break
  1190                     break
  1188 
  1191 
  1189             patches.append(patch)
  1192             patches.append(patch)
  1190         return patches
  1193         return patches
  1193         # Manually trigger phase computation to ensure phasedefaults is
  1196         # Manually trigger phase computation to ensure phasedefaults is
  1194         # executed before we remove the patches.
  1197         # executed before we remove the patches.
  1195         repo._phasecache
  1198         repo._phasecache
  1196         patches = self._revpatches(repo, sorted(revs))
  1199         patches = self._revpatches(repo, sorted(revs))
  1197         qfinished = self._cleanup(patches, len(patches))
  1200         qfinished = self._cleanup(patches, len(patches))
  1198         if qfinished and repo.ui.configbool('mq', 'secret'):
  1201         if qfinished and repo.ui.configbool(b'mq', b'secret'):
  1199             # only use this logic when the secret option is added
  1202             # only use this logic when the secret option is added
  1200             oldqbase = repo[qfinished[0]]
  1203             oldqbase = repo[qfinished[0]]
  1201             tphase = phases.newcommitphase(repo.ui)
  1204             tphase = phases.newcommitphase(repo.ui)
  1202             if oldqbase.phase() > tphase and oldqbase.p1().phase() <= tphase:
  1205             if oldqbase.phase() > tphase and oldqbase.p1().phase() <= tphase:
  1203                 with repo.transaction('qfinish') as tr:
  1206                 with repo.transaction(b'qfinish') as tr:
  1204                     phases.advanceboundary(repo, tr, tphase, qfinished)
  1207                     phases.advanceboundary(repo, tr, tphase, qfinished)
  1205 
  1208 
  1206     def delete(self, repo, patches, opts):
  1209     def delete(self, repo, patches, opts):
  1207         if not patches and not opts.get('rev'):
  1210         if not patches and not opts.get(b'rev'):
  1208             raise error.Abort(
  1211             raise error.Abort(
  1209                 _('qdelete requires at least one revision or ' 'patch name')
  1212                 _(b'qdelete requires at least one revision or ' b'patch name')
  1210             )
  1213             )
  1211 
  1214 
  1212         realpatches = []
  1215         realpatches = []
  1213         for patch in patches:
  1216         for patch in patches:
  1214             patch = self.lookup(patch, strict=True)
  1217             patch = self.lookup(patch, strict=True)
  1215             info = self.isapplied(patch)
  1218             info = self.isapplied(patch)
  1216             if info:
  1219             if info:
  1217                 raise error.Abort(_("cannot delete applied patch %s") % patch)
  1220                 raise error.Abort(_(b"cannot delete applied patch %s") % patch)
  1218             if patch not in self.series:
  1221             if patch not in self.series:
  1219                 raise error.Abort(_("patch %s not in series file") % patch)
  1222                 raise error.Abort(_(b"patch %s not in series file") % patch)
  1220             if patch not in realpatches:
  1223             if patch not in realpatches:
  1221                 realpatches.append(patch)
  1224                 realpatches.append(patch)
  1222 
  1225 
  1223         numrevs = 0
  1226         numrevs = 0
  1224         if opts.get('rev'):
  1227         if opts.get(b'rev'):
  1225             if not self.applied:
  1228             if not self.applied:
  1226                 raise error.Abort(_('no patches applied'))
  1229                 raise error.Abort(_(b'no patches applied'))
  1227             revs = scmutil.revrange(repo, opts.get('rev'))
  1230             revs = scmutil.revrange(repo, opts.get(b'rev'))
  1228             revs.sort()
  1231             revs.sort()
  1229             revpatches = self._revpatches(repo, revs)
  1232             revpatches = self._revpatches(repo, revs)
  1230             realpatches += revpatches
  1233             realpatches += revpatches
  1231             numrevs = len(revpatches)
  1234             numrevs = len(revpatches)
  1232 
  1235 
  1233         self._cleanup(realpatches, numrevs, opts.get('keep'))
  1236         self._cleanup(realpatches, numrevs, opts.get(b'keep'))
  1234 
  1237 
  1235     def checktoppatch(self, repo):
  1238     def checktoppatch(self, repo):
  1236         '''check that working directory is at qtip'''
  1239         '''check that working directory is at qtip'''
  1237         if self.applied:
  1240         if self.applied:
  1238             top = self.applied[-1].node
  1241             top = self.applied[-1].node
  1239             patch = self.applied[-1].name
  1242             patch = self.applied[-1].name
  1240             if repo.dirstate.p1() != top:
  1243             if repo.dirstate.p1() != top:
  1241                 raise error.Abort(_("working directory revision is not qtip"))
  1244                 raise error.Abort(_(b"working directory revision is not qtip"))
  1242             return top, patch
  1245             return top, patch
  1243         return None, None
  1246         return None, None
  1244 
  1247 
  1245     def putsubstate2changes(self, substatestate, changes):
  1248     def putsubstate2changes(self, substatestate, changes):
  1246         for files in changes[:3]:
  1249         for files in changes[:3]:
  1247             if '.hgsubstate' in files:
  1250             if b'.hgsubstate' in files:
  1248                 return  # already listed up
  1251                 return  # already listed up
  1249         # not yet listed up
  1252         # not yet listed up
  1250         if substatestate in 'a?':
  1253         if substatestate in b'a?':
  1251             changes[1].append('.hgsubstate')
  1254             changes[1].append(b'.hgsubstate')
  1252         elif substatestate in 'r':
  1255         elif substatestate in b'r':
  1253             changes[2].append('.hgsubstate')
  1256             changes[2].append(b'.hgsubstate')
  1254         else:  # modified
  1257         else:  # modified
  1255             changes[0].append('.hgsubstate')
  1258             changes[0].append(b'.hgsubstate')
  1256 
  1259 
  1257     def checklocalchanges(self, repo, force=False, refresh=True):
  1260     def checklocalchanges(self, repo, force=False, refresh=True):
  1258         excsuffix = ''
  1261         excsuffix = b''
  1259         if refresh:
  1262         if refresh:
  1260             excsuffix = ', qrefresh first'
  1263             excsuffix = b', qrefresh first'
  1261             # plain versions for i18n tool to detect them
  1264             # plain versions for i18n tool to detect them
  1262             _("local changes found, qrefresh first")
  1265             _(b"local changes found, qrefresh first")
  1263             _("local changed subrepos found, qrefresh first")
  1266             _(b"local changed subrepos found, qrefresh first")
  1264 
  1267 
  1265         s = repo.status()
  1268         s = repo.status()
  1266         if not force:
  1269         if not force:
  1267             cmdutil.checkunfinished(repo)
  1270             cmdutil.checkunfinished(repo)
  1268             if s.modified or s.added or s.removed or s.deleted:
  1271             if s.modified or s.added or s.removed or s.deleted:
  1269                 _("local changes found")  # i18n tool detection
  1272                 _(b"local changes found")  # i18n tool detection
  1270                 raise error.Abort(_("local changes found" + excsuffix))
  1273                 raise error.Abort(_(b"local changes found" + excsuffix))
  1271             if checksubstate(repo):
  1274             if checksubstate(repo):
  1272                 _("local changed subrepos found")  # i18n tool detection
  1275                 _(b"local changed subrepos found")  # i18n tool detection
  1273                 raise error.Abort(_("local changed subrepos found" + excsuffix))
  1276                 raise error.Abort(
       
  1277                     _(b"local changed subrepos found" + excsuffix)
       
  1278                 )
  1274         else:
  1279         else:
  1275             cmdutil.checkunfinished(repo, skipmerge=True)
  1280             cmdutil.checkunfinished(repo, skipmerge=True)
  1276         return s
  1281         return s
  1277 
  1282 
  1278     _reserved = ('series', 'status', 'guards', '.', '..')
  1283     _reserved = (b'series', b'status', b'guards', b'.', b'..')
  1279 
  1284 
  1280     def checkreservedname(self, name):
  1285     def checkreservedname(self, name):
  1281         if name in self._reserved:
  1286         if name in self._reserved:
  1282             raise error.Abort(
  1287             raise error.Abort(
  1283                 _('"%s" cannot be used as the name of a patch') % name
  1288                 _(b'"%s" cannot be used as the name of a patch') % name
  1284             )
  1289             )
  1285         if name != name.strip():
  1290         if name != name.strip():
  1286             # whitespace is stripped by parseseries()
  1291             # whitespace is stripped by parseseries()
  1287             raise error.Abort(
  1292             raise error.Abort(
  1288                 _('patch name cannot begin or end with ' 'whitespace')
  1293                 _(b'patch name cannot begin or end with ' b'whitespace')
  1289             )
  1294             )
  1290         for prefix in ('.hg', '.mq'):
  1295         for prefix in (b'.hg', b'.mq'):
  1291             if name.startswith(prefix):
  1296             if name.startswith(prefix):
  1292                 raise error.Abort(
  1297                 raise error.Abort(
  1293                     _('patch name cannot begin with "%s"') % prefix
  1298                     _(b'patch name cannot begin with "%s"') % prefix
  1294                 )
  1299                 )
  1295         for c in ('#', ':', '\r', '\n'):
  1300         for c in (b'#', b':', b'\r', b'\n'):
  1296             if c in name:
  1301             if c in name:
  1297                 raise error.Abort(
  1302                 raise error.Abort(
  1298                     _('%r cannot be used in the name of a patch')
  1303                     _(b'%r cannot be used in the name of a patch')
  1299                     % pycompat.bytestr(c)
  1304                     % pycompat.bytestr(c)
  1300                 )
  1305                 )
  1301 
  1306 
  1302     def checkpatchname(self, name, force=False):
  1307     def checkpatchname(self, name, force=False):
  1303         self.checkreservedname(name)
  1308         self.checkreservedname(name)
  1304         if not force and os.path.exists(self.join(name)):
  1309         if not force and os.path.exists(self.join(name)):
  1305             if os.path.isdir(self.join(name)):
  1310             if os.path.isdir(self.join(name)):
  1306                 raise error.Abort(
  1311                 raise error.Abort(
  1307                     _('"%s" already exists as a directory') % name
  1312                     _(b'"%s" already exists as a directory') % name
  1308                 )
  1313                 )
  1309             else:
  1314             else:
  1310                 raise error.Abort(_('patch "%s" already exists') % name)
  1315                 raise error.Abort(_(b'patch "%s" already exists') % name)
  1311 
  1316 
  1312     def makepatchname(self, title, fallbackname):
  1317     def makepatchname(self, title, fallbackname):
  1313         """Return a suitable filename for title, adding a suffix to make
  1318         """Return a suitable filename for title, adding a suffix to make
  1314         it unique in the existing list"""
  1319         it unique in the existing list"""
  1315         namebase = re.sub(br'[\s\W_]+', b'_', title.lower()).strip(b'_')
  1320         namebase = re.sub(br'[\s\W_]+', b'_', title.lower()).strip(b'_')
  1329                     self.checkpatchname(name)
  1334                     self.checkpatchname(name)
  1330                     break
  1335                     break
  1331                 except error.Abort:
  1336                 except error.Abort:
  1332                     pass
  1337                     pass
  1333             i += 1
  1338             i += 1
  1334             name = '%s__%d' % (namebase, i)
  1339             name = b'%s__%d' % (namebase, i)
  1335         return name
  1340         return name
  1336 
  1341 
  1337     def checkkeepchanges(self, keepchanges, force):
  1342     def checkkeepchanges(self, keepchanges, force):
  1338         if force and keepchanges:
  1343         if force and keepchanges:
  1339             raise error.Abort(_('cannot use both --force and --keep-changes'))
  1344             raise error.Abort(_(b'cannot use both --force and --keep-changes'))
  1340 
  1345 
  1341     def new(self, repo, patchfn, *pats, **opts):
  1346     def new(self, repo, patchfn, *pats, **opts):
  1342         """options:
  1347         """options:
  1343            msg: a string or a no-argument function returning a string
  1348            msg: a string or a no-argument function returning a string
  1344         """
  1349         """
  1345         opts = pycompat.byteskwargs(opts)
  1350         opts = pycompat.byteskwargs(opts)
  1346         msg = opts.get('msg')
  1351         msg = opts.get(b'msg')
  1347         edit = opts.get('edit')
  1352         edit = opts.get(b'edit')
  1348         editform = opts.get('editform', 'mq.qnew')
  1353         editform = opts.get(b'editform', b'mq.qnew')
  1349         user = opts.get('user')
  1354         user = opts.get(b'user')
  1350         date = opts.get('date')
  1355         date = opts.get(b'date')
  1351         if date:
  1356         if date:
  1352             date = dateutil.parsedate(date)
  1357             date = dateutil.parsedate(date)
  1353         diffopts = self.diffopts({'git': opts.get('git')}, plain=True)
  1358         diffopts = self.diffopts({b'git': opts.get(b'git')}, plain=True)
  1354         if opts.get('checkname', True):
  1359         if opts.get(b'checkname', True):
  1355             self.checkpatchname(patchfn)
  1360             self.checkpatchname(patchfn)
  1356         inclsubs = checksubstate(repo)
  1361         inclsubs = checksubstate(repo)
  1357         if inclsubs:
  1362         if inclsubs:
  1358             substatestate = repo.dirstate['.hgsubstate']
  1363             substatestate = repo.dirstate[b'.hgsubstate']
  1359         if opts.get('include') or opts.get('exclude') or pats:
  1364         if opts.get(b'include') or opts.get(b'exclude') or pats:
  1360             # detect missing files in pats
  1365             # detect missing files in pats
  1361             def badfn(f, msg):
  1366             def badfn(f, msg):
  1362                 if f != '.hgsubstate':  # .hgsubstate is auto-created
  1367                 if f != b'.hgsubstate':  # .hgsubstate is auto-created
  1363                     raise error.Abort('%s: %s' % (f, msg))
  1368                     raise error.Abort(b'%s: %s' % (f, msg))
  1364 
  1369 
  1365             match = scmutil.match(repo[None], pats, opts, badfn=badfn)
  1370             match = scmutil.match(repo[None], pats, opts, badfn=badfn)
  1366             changes = repo.status(match=match)
  1371             changes = repo.status(match=match)
  1367         else:
  1372         else:
  1368             changes = self.checklocalchanges(repo, force=True)
  1373             changes = self.checklocalchanges(repo, force=True)
  1369         commitfiles = list(inclsubs)
  1374         commitfiles = list(inclsubs)
  1370         for files in changes[:3]:
  1375         for files in changes[:3]:
  1371             commitfiles.extend(files)
  1376             commitfiles.extend(files)
  1372         match = scmutil.matchfiles(repo, commitfiles)
  1377         match = scmutil.matchfiles(repo, commitfiles)
  1373         if len(repo[None].parents()) > 1:
  1378         if len(repo[None].parents()) > 1:
  1374             raise error.Abort(_('cannot manage merge changesets'))
  1379             raise error.Abort(_(b'cannot manage merge changesets'))
  1375         self.checktoppatch(repo)
  1380         self.checktoppatch(repo)
  1376         insert = self.fullseriesend()
  1381         insert = self.fullseriesend()
  1377         with repo.wlock():
  1382         with repo.wlock():
  1378             try:
  1383             try:
  1379                 # if patch file write fails, abort early
  1384                 # if patch file write fails, abort early
  1380                 p = self.opener(patchfn, "w")
  1385                 p = self.opener(patchfn, b"w")
  1381             except IOError as e:
  1386             except IOError as e:
  1382                 raise error.Abort(
  1387                 raise error.Abort(
  1383                     _('cannot write patch "%s": %s')
  1388                     _(b'cannot write patch "%s": %s')
  1384                     % (patchfn, encoding.strtolocal(e.strerror))
  1389                     % (patchfn, encoding.strtolocal(e.strerror))
  1385                 )
  1390                 )
  1386             try:
  1391             try:
  1387                 defaultmsg = "[mq]: %s" % patchfn
  1392                 defaultmsg = b"[mq]: %s" % patchfn
  1388                 editor = cmdutil.getcommiteditor(editform=editform)
  1393                 editor = cmdutil.getcommiteditor(editform=editform)
  1389                 if edit:
  1394                 if edit:
  1390 
  1395 
  1391                     def finishdesc(desc):
  1396                     def finishdesc(desc):
  1392                         if desc.rstrip():
  1397                         if desc.rstrip():
  1393                             return desc
  1398                             return desc
  1394                         else:
  1399                         else:
  1395                             return defaultmsg
  1400                             return defaultmsg
  1396 
  1401 
  1397                     # i18n: this message is shown in editor with "HG: " prefix
  1402                     # i18n: this message is shown in editor with "HG: " prefix
  1398                     extramsg = _('Leave message empty to use default message.')
  1403                     extramsg = _(b'Leave message empty to use default message.')
  1399                     editor = cmdutil.getcommiteditor(
  1404                     editor = cmdutil.getcommiteditor(
  1400                         finishdesc=finishdesc,
  1405                         finishdesc=finishdesc,
  1401                         extramsg=extramsg,
  1406                         extramsg=extramsg,
  1402                         editform=editform,
  1407                         editform=editform,
  1403                     )
  1408                     )
  1414                     match=match,
  1419                     match=match,
  1415                     force=True,
  1420                     force=True,
  1416                     editor=editor,
  1421                     editor=editor,
  1417                 )
  1422                 )
  1418                 if n is None:
  1423                 if n is None:
  1419                     raise error.Abort(_("repo commit failed"))
  1424                     raise error.Abort(_(b"repo commit failed"))
  1420                 try:
  1425                 try:
  1421                     self.fullseries[insert:insert] = [patchfn]
  1426                     self.fullseries[insert:insert] = [patchfn]
  1422                     self.applied.append(statusentry(n, patchfn))
  1427                     self.applied.append(statusentry(n, patchfn))
  1423                     self.parseseries()
  1428                     self.parseseries()
  1424                     self.seriesdirty = True
  1429                     self.seriesdirty = True
  1426                     nctx = repo[n]
  1431                     nctx = repo[n]
  1427                     ph = patchheader(self.join(patchfn), self.plainmode)
  1432                     ph = patchheader(self.join(patchfn), self.plainmode)
  1428                     if user:
  1433                     if user:
  1429                         ph.setuser(user)
  1434                         ph.setuser(user)
  1430                     if date:
  1435                     if date:
  1431                         ph.setdate('%d %d' % date)
  1436                         ph.setdate(b'%d %d' % date)
  1432                     ph.setparent(hex(nctx.p1().node()))
  1437                     ph.setparent(hex(nctx.p1().node()))
  1433                     msg = nctx.description().strip()
  1438                     msg = nctx.description().strip()
  1434                     if msg == defaultmsg.strip():
  1439                     if msg == defaultmsg.strip():
  1435                         msg = ''
  1440                         msg = b''
  1436                     ph.setmessage(msg)
  1441                     ph.setmessage(msg)
  1437                     p.write(bytes(ph))
  1442                     p.write(bytes(ph))
  1438                     if commitfiles:
  1443                     if commitfiles:
  1439                         parent = self.qparents(repo, n)
  1444                         parent = self.qparents(repo, n)
  1440                         if inclsubs:
  1445                         if inclsubs:
  1458             except Exception:
  1463             except Exception:
  1459                 patchpath = self.join(patchfn)
  1464                 patchpath = self.join(patchfn)
  1460                 try:
  1465                 try:
  1461                     os.unlink(patchpath)
  1466                     os.unlink(patchpath)
  1462                 except OSError:
  1467                 except OSError:
  1463                     self.ui.warn(_('error unlinking %s\n') % patchpath)
  1468                     self.ui.warn(_(b'error unlinking %s\n') % patchpath)
  1464                 raise
  1469                 raise
  1465             self.removeundo(repo)
  1470             self.removeundo(repo)
  1466 
  1471 
  1467     def isapplied(self, patch):
  1472     def isapplied(self, patch):
  1468         """returns (index, rev, patch)"""
  1473         """returns (index, rev, patch)"""
  1481         def partialname(s):
  1486         def partialname(s):
  1482             if s in self.series:
  1487             if s in self.series:
  1483                 return s
  1488                 return s
  1484             matches = [x for x in self.series if s in x]
  1489             matches = [x for x in self.series if s in x]
  1485             if len(matches) > 1:
  1490             if len(matches) > 1:
  1486                 self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
  1491                 self.ui.warn(_(b'patch name "%s" is ambiguous:\n') % s)
  1487                 for m in matches:
  1492                 for m in matches:
  1488                     self.ui.warn('  %s\n' % m)
  1493                     self.ui.warn(b'  %s\n' % m)
  1489                 return None
  1494                 return None
  1490             if matches:
  1495             if matches:
  1491                 return matches[0]
  1496                 return matches[0]
  1492             if self.series and self.applied:
  1497             if self.series and self.applied:
  1493                 if s == 'qtip':
  1498                 if s == b'qtip':
  1494                     return self.series[self.seriesend(True) - 1]
  1499                     return self.series[self.seriesend(True) - 1]
  1495                 if s == 'qbase':
  1500                 if s == b'qbase':
  1496                     return self.series[0]
  1501                     return self.series[0]
  1497             return None
  1502             return None
  1498 
  1503 
  1499         if patch in self.series:
  1504         if patch in self.series:
  1500             return patch
  1505             return patch
  1510 
  1515 
  1511             if not strict:
  1516             if not strict:
  1512                 res = partialname(patch)
  1517                 res = partialname(patch)
  1513                 if res:
  1518                 if res:
  1514                     return res
  1519                     return res
  1515                 minus = patch.rfind('-')
  1520                 minus = patch.rfind(b'-')
  1516                 if minus >= 0:
  1521                 if minus >= 0:
  1517                     res = partialname(patch[:minus])
  1522                     res = partialname(patch[:minus])
  1518                     if res:
  1523                     if res:
  1519                         i = self.series.index(res)
  1524                         i = self.series.index(res)
  1520                         try:
  1525                         try:
  1522                         except (ValueError, OverflowError):
  1527                         except (ValueError, OverflowError):
  1523                             pass
  1528                             pass
  1524                         else:
  1529                         else:
  1525                             if i - off >= 0:
  1530                             if i - off >= 0:
  1526                                 return self.series[i - off]
  1531                                 return self.series[i - off]
  1527                 plus = patch.rfind('+')
  1532                 plus = patch.rfind(b'+')
  1528                 if plus >= 0:
  1533                 if plus >= 0:
  1529                     res = partialname(patch[:plus])
  1534                     res = partialname(patch[:plus])
  1530                     if res:
  1535                     if res:
  1531                         i = self.series.index(res)
  1536                         i = self.series.index(res)
  1532                         try:
  1537                         try:
  1534                         except (ValueError, OverflowError):
  1539                         except (ValueError, OverflowError):
  1535                             pass
  1540                             pass
  1536                         else:
  1541                         else:
  1537                             if i + off < len(self.series):
  1542                             if i + off < len(self.series):
  1538                                 return self.series[i + off]
  1543                                 return self.series[i + off]
  1539         raise error.Abort(_("patch %s not in series") % patch)
  1544         raise error.Abort(_(b"patch %s not in series") % patch)
  1540 
  1545 
  1541     def push(
  1546     def push(
  1542         self,
  1547         self,
  1543         repo,
  1548         repo,
  1544         patch=None,
  1549         patch=None,
  1558             for hs in repo.branchmap().iterheads():
  1563             for hs in repo.branchmap().iterheads():
  1559                 heads.extend(hs)
  1564                 heads.extend(hs)
  1560             if not heads:
  1565             if not heads:
  1561                 heads = [nullid]
  1566                 heads = [nullid]
  1562             if repo.dirstate.p1() not in heads and not exact:
  1567             if repo.dirstate.p1() not in heads and not exact:
  1563                 self.ui.status(_("(working directory not at a head)\n"))
  1568                 self.ui.status(_(b"(working directory not at a head)\n"))
  1564 
  1569 
  1565             if not self.series:
  1570             if not self.series:
  1566                 self.ui.warn(_('no patches in series\n'))
  1571                 self.ui.warn(_(b'no patches in series\n'))
  1567                 return 0
  1572                 return 0
  1568 
  1573 
  1569             # Suppose our series file is: A B C and the current 'top'
  1574             # Suppose our series file is: A B C and the current 'top'
  1570             # patch is B. qpush C should be performed (moving forward)
  1575             # patch is B. qpush C should be performed (moving forward)
  1571             # qpush B is a NOP (no change) qpush A is an error (can't
  1576             # qpush B is a NOP (no change) qpush A is an error (can't
  1572             # go backwards with qpush)
  1577             # go backwards with qpush)
  1573             if patch:
  1578             if patch:
  1574                 patch = self.lookup(patch)
  1579                 patch = self.lookup(patch)
  1575                 info = self.isapplied(patch)
  1580                 info = self.isapplied(patch)
  1576                 if info and info[0] >= len(self.applied) - 1:
  1581                 if info and info[0] >= len(self.applied) - 1:
  1577                     self.ui.warn(_('qpush: %s is already at the top\n') % patch)
  1582                     self.ui.warn(
       
  1583                         _(b'qpush: %s is already at the top\n') % patch
       
  1584                     )
  1578                     return 0
  1585                     return 0
  1579 
  1586 
  1580                 pushable, reason = self.pushable(patch)
  1587                 pushable, reason = self.pushable(patch)
  1581                 if pushable:
  1588                 if pushable:
  1582                     if self.series.index(patch) < self.seriesend():
  1589                     if self.series.index(patch) < self.seriesend():
  1583                         raise error.Abort(
  1590                         raise error.Abort(
  1584                             _("cannot push to a previous patch: %s") % patch
  1591                             _(b"cannot push to a previous patch: %s") % patch
  1585                         )
  1592                         )
  1586                 else:
  1593                 else:
  1587                     if reason:
  1594                     if reason:
  1588                         reason = _('guarded by %s') % reason
  1595                         reason = _(b'guarded by %s') % reason
  1589                     else:
  1596                     else:
  1590                         reason = _('no matching guards')
  1597                         reason = _(b'no matching guards')
  1591                     self.ui.warn(_("cannot push '%s' - %s\n") % (patch, reason))
  1598                     self.ui.warn(
       
  1599                         _(b"cannot push '%s' - %s\n") % (patch, reason)
       
  1600                     )
  1592                     return 1
  1601                     return 1
  1593             elif all:
  1602             elif all:
  1594                 patch = self.series[-1]
  1603                 patch = self.series[-1]
  1595                 if self.isapplied(patch):
  1604                 if self.isapplied(patch):
  1596                     self.ui.warn(_('all patches are currently applied\n'))
  1605                     self.ui.warn(_(b'all patches are currently applied\n'))
  1597                     return 0
  1606                     return 0
  1598 
  1607 
  1599             # Following the above example, starting at 'top' of B:
  1608             # Following the above example, starting at 'top' of B:
  1600             # qpush should be performed (pushes C), but a subsequent
  1609             # qpush should be performed (pushes C), but a subsequent
  1601             # qpush without an argument is an error (nothing to
  1610             # qpush without an argument is an error (nothing to
  1602             # apply). This allows a loop of "...while hg qpush..." to
  1611             # apply). This allows a loop of "...while hg qpush..." to
  1603             # work as it detects an error when done
  1612             # work as it detects an error when done
  1604             start = self.seriesend()
  1613             start = self.seriesend()
  1605             if start == len(self.series):
  1614             if start == len(self.series):
  1606                 self.ui.warn(_('patch series already fully applied\n'))
  1615                 self.ui.warn(_(b'patch series already fully applied\n'))
  1607                 return 1
  1616                 return 1
  1608             if not force and not keepchanges:
  1617             if not force and not keepchanges:
  1609                 self.checklocalchanges(repo, refresh=self.applied)
  1618                 self.checklocalchanges(repo, refresh=self.applied)
  1610 
  1619 
  1611             if exact:
  1620             if exact:
  1612                 if keepchanges:
  1621                 if keepchanges:
  1613                     raise error.Abort(
  1622                     raise error.Abort(
  1614                         _("cannot use --exact and --keep-changes together")
  1623                         _(b"cannot use --exact and --keep-changes together")
  1615                     )
  1624                     )
  1616                 if move:
  1625                 if move:
  1617                     raise error.Abort(
  1626                     raise error.Abort(
  1618                         _('cannot use --exact and --move ' 'together')
  1627                         _(b'cannot use --exact and --move ' b'together')
  1619                     )
  1628                     )
  1620                 if self.applied:
  1629                 if self.applied:
  1621                     raise error.Abort(
  1630                     raise error.Abort(
  1622                         _('cannot push --exact with applied ' 'patches')
  1631                         _(b'cannot push --exact with applied ' b'patches')
  1623                     )
  1632                     )
  1624                 root = self.series[start]
  1633                 root = self.series[start]
  1625                 target = patchheader(self.join(root), self.plainmode).parent
  1634                 target = patchheader(self.join(root), self.plainmode).parent
  1626                 if not target:
  1635                 if not target:
  1627                     raise error.Abort(
  1636                     raise error.Abort(
  1628                         _("%s does not have a parent recorded") % root
  1637                         _(b"%s does not have a parent recorded") % root
  1629                     )
  1638                     )
  1630                 if not repo[target] == repo['.']:
  1639                 if not repo[target] == repo[b'.']:
  1631                     hg.update(repo, target)
  1640                     hg.update(repo, target)
  1632 
  1641 
  1633             if move:
  1642             if move:
  1634                 if not patch:
  1643                 if not patch:
  1635                     raise error.Abort(_("please specify the patch to move"))
  1644                     raise error.Abort(_(b"please specify the patch to move"))
  1636                 for fullstart, rpn in enumerate(self.fullseries):
  1645                 for fullstart, rpn in enumerate(self.fullseries):
  1637                     # strip markers for patch guards
  1646                     # strip markers for patch guards
  1638                     if self.guard_re.split(rpn, 1)[0] == self.series[start]:
  1647                     if self.guard_re.split(rpn, 1)[0] == self.series[start]:
  1639                         break
  1648                         break
  1640                 for i, rpn in enumerate(self.fullseries[fullstart:]):
  1649                 for i, rpn in enumerate(self.fullseries[fullstart:]):
  1686                         keepchanges=keepchanges,
  1695                         keepchanges=keepchanges,
  1687                     )
  1696                     )
  1688             except AbortNoCleanup:
  1697             except AbortNoCleanup:
  1689                 raise
  1698                 raise
  1690             except:  # re-raises
  1699             except:  # re-raises
  1691                 self.ui.warn(_('cleaning up working directory...\n'))
  1700                 self.ui.warn(_(b'cleaning up working directory...\n'))
  1692                 cmdutil.revert(
  1701                 cmdutil.revert(
  1693                     self.ui,
  1702                     self.ui,
  1694                     repo,
  1703                     repo,
  1695                     repo['.'],
  1704                     repo[b'.'],
  1696                     repo.dirstate.parents(),
  1705                     repo.dirstate.parents(),
  1697                     no_backup=True,
  1706                     no_backup=True,
  1698                 )
  1707                 )
  1699                 # only remove unknown files that we know we touched or
  1708                 # only remove unknown files that we know we touched or
  1700                 # created while patching
  1709                 # created while patching
  1701                 for f in all_files:
  1710                 for f in all_files:
  1702                     if f not in repo.dirstate:
  1711                     if f not in repo.dirstate:
  1703                         repo.wvfs.unlinkpath(f, ignoremissing=True)
  1712                         repo.wvfs.unlinkpath(f, ignoremissing=True)
  1704                 self.ui.warn(_('done\n'))
  1713                 self.ui.warn(_(b'done\n'))
  1705                 raise
  1714                 raise
  1706 
  1715 
  1707             if not self.applied:
  1716             if not self.applied:
  1708                 return ret[0]
  1717                 return ret[0]
  1709             top = self.applied[-1].name
  1718             top = self.applied[-1].name
  1710             if ret[0] and ret[0] > 1:
  1719             if ret[0] and ret[0] > 1:
  1711                 msg = _("errors during apply, please fix and qrefresh %s\n")
  1720                 msg = _(b"errors during apply, please fix and qrefresh %s\n")
  1712                 self.ui.write(msg % top)
  1721                 self.ui.write(msg % top)
  1713             else:
  1722             else:
  1714                 self.ui.write(_("now at: %s\n") % top)
  1723                 self.ui.write(_(b"now at: %s\n") % top)
  1715             return ret[0]
  1724             return ret[0]
  1716 
  1725 
  1717     def pop(
  1726     def pop(
  1718         self,
  1727         self,
  1719         repo,
  1728         repo,
  1731                 info = self.isapplied(patch)
  1740                 info = self.isapplied(patch)
  1732                 if not info:
  1741                 if not info:
  1733                     patch = self.lookup(patch)
  1742                     patch = self.lookup(patch)
  1734                 info = self.isapplied(patch)
  1743                 info = self.isapplied(patch)
  1735                 if not info:
  1744                 if not info:
  1736                     raise error.Abort(_("patch %s is not applied") % patch)
  1745                     raise error.Abort(_(b"patch %s is not applied") % patch)
  1737 
  1746 
  1738             if not self.applied:
  1747             if not self.applied:
  1739                 # Allow qpop -a to work repeatedly,
  1748                 # Allow qpop -a to work repeatedly,
  1740                 # but not qpop without an argument
  1749                 # but not qpop without an argument
  1741                 self.ui.warn(_("no patches applied\n"))
  1750                 self.ui.warn(_(b"no patches applied\n"))
  1742                 return not all
  1751                 return not all
  1743 
  1752 
  1744             if all:
  1753             if all:
  1745                 start = 0
  1754                 start = 0
  1746             elif patch:
  1755             elif patch:
  1747                 start = info[0] + 1
  1756                 start = info[0] + 1
  1748             else:
  1757             else:
  1749                 start = len(self.applied) - 1
  1758                 start = len(self.applied) - 1
  1750 
  1759 
  1751             if start >= len(self.applied):
  1760             if start >= len(self.applied):
  1752                 self.ui.warn(_("qpop: %s is already at the top\n") % patch)
  1761                 self.ui.warn(_(b"qpop: %s is already at the top\n") % patch)
  1753                 return
  1762                 return
  1754 
  1763 
  1755             if not update:
  1764             if not update:
  1756                 parents = repo.dirstate.parents()
  1765                 parents = repo.dirstate.parents()
  1757                 rr = [x.node for x in self.applied]
  1766                 rr = [x.node for x in self.applied]
  1758                 for p in parents:
  1767                 for p in parents:
  1759                     if p in rr:
  1768                     if p in rr:
  1760                         self.ui.warn(_("qpop: forcing dirstate update\n"))
  1769                         self.ui.warn(_(b"qpop: forcing dirstate update\n"))
  1761                         update = True
  1770                         update = True
  1762             else:
  1771             else:
  1763                 parents = [p.node() for p in repo[None].parents()]
  1772                 parents = [p.node() for p in repo[None].parents()]
  1764                 update = any(
  1773                 update = any(
  1765                     entry.node in parents for entry in self.applied[start:]
  1774                     entry.node in parents for entry in self.applied[start:]
  1782 
  1791 
  1783             try:
  1792             try:
  1784                 heads = repo.changelog.heads(rev)
  1793                 heads = repo.changelog.heads(rev)
  1785             except error.LookupError:
  1794             except error.LookupError:
  1786                 node = short(rev)
  1795                 node = short(rev)
  1787                 raise error.Abort(_('trying to pop unknown node %s') % node)
  1796                 raise error.Abort(_(b'trying to pop unknown node %s') % node)
  1788 
  1797 
  1789             if heads != [self.applied[-1].node]:
  1798             if heads != [self.applied[-1].node]:
  1790                 raise error.Abort(
  1799                 raise error.Abort(
  1791                     _(
  1800                     _(
  1792                         "popping would remove a revision not "
  1801                         b"popping would remove a revision not "
  1793                         "managed by this patch queue"
  1802                         b"managed by this patch queue"
  1794                     )
  1803                     )
  1795                 )
  1804                 )
  1796             if not repo[self.applied[-1].node].mutable():
  1805             if not repo[self.applied[-1].node].mutable():
  1797                 raise error.Abort(
  1806                 raise error.Abort(
  1798                     _("popping would remove a public revision"),
  1807                     _(b"popping would remove a public revision"),
  1799                     hint=_("see 'hg help phases' for details"),
  1808                     hint=_(b"see 'hg help phases' for details"),
  1800                 )
  1809                 )
  1801 
  1810 
  1802             # we know there are no local changes, so we can make a simplified
  1811             # we know there are no local changes, so we can make a simplified
  1803             # form of hg.update.
  1812             # form of hg.update.
  1804             if update:
  1813             if update:
  1805                 qp = self.qparents(repo, rev)
  1814                 qp = self.qparents(repo, rev)
  1806                 ctx = repo[qp]
  1815                 ctx = repo[qp]
  1807                 m, a, r, d = repo.status(qp, '.')[:4]
  1816                 m, a, r, d = repo.status(qp, b'.')[:4]
  1808                 if d:
  1817                 if d:
  1809                     raise error.Abort(_("deletions found between repo revs"))
  1818                     raise error.Abort(_(b"deletions found between repo revs"))
  1810 
  1819 
  1811                 tobackup = set(a + m + r) & tobackup
  1820                 tobackup = set(a + m + r) & tobackup
  1812                 if keepchanges and tobackup:
  1821                 if keepchanges and tobackup:
  1813                     raise error.Abort(_("local changes found, qrefresh first"))
  1822                     raise error.Abort(_(b"local changes found, qrefresh first"))
  1814                 self.backup(repo, tobackup)
  1823                 self.backup(repo, tobackup)
  1815                 with repo.dirstate.parentchange():
  1824                 with repo.dirstate.parentchange():
  1816                     for f in a:
  1825                     for f in a:
  1817                         repo.wvfs.unlinkpath(f, ignoremissing=True)
  1826                         repo.wvfs.unlinkpath(f, ignoremissing=True)
  1818                         repo.dirstate.drop(f)
  1827                         repo.dirstate.drop(f)
  1820                         fctx = ctx[f]
  1829                         fctx = ctx[f]
  1821                         repo.wwrite(f, fctx.data(), fctx.flags())
  1830                         repo.wwrite(f, fctx.data(), fctx.flags())
  1822                         repo.dirstate.normal(f)
  1831                         repo.dirstate.normal(f)
  1823                     repo.setparents(qp, nullid)
  1832                     repo.setparents(qp, nullid)
  1824             for patch in reversed(self.applied[start:end]):
  1833             for patch in reversed(self.applied[start:end]):
  1825                 self.ui.status(_("popping %s\n") % patch.name)
  1834                 self.ui.status(_(b"popping %s\n") % patch.name)
  1826             del self.applied[start:end]
  1835             del self.applied[start:end]
  1827             strip(self.ui, repo, [rev], update=False, backup=False)
  1836             strip(self.ui, repo, [rev], update=False, backup=False)
  1828             for s, state in repo['.'].substate.items():
  1837             for s, state in repo[b'.'].substate.items():
  1829                 repo['.'].sub(s).get(state)
  1838                 repo[b'.'].sub(s).get(state)
  1830             if self.applied:
  1839             if self.applied:
  1831                 self.ui.write(_("now at: %s\n") % self.applied[-1].name)
  1840                 self.ui.write(_(b"now at: %s\n") % self.applied[-1].name)
  1832             else:
  1841             else:
  1833                 self.ui.write(_("patch queue now empty\n"))
  1842                 self.ui.write(_(b"patch queue now empty\n"))
  1834 
  1843 
  1835     def diff(self, repo, pats, opts):
  1844     def diff(self, repo, pats, opts):
  1836         top, patch = self.checktoppatch(repo)
  1845         top, patch = self.checktoppatch(repo)
  1837         if not top:
  1846         if not top:
  1838             self.ui.write(_("no patches applied\n"))
  1847             self.ui.write(_(b"no patches applied\n"))
  1839             return
  1848             return
  1840         qp = self.qparents(repo, top)
  1849         qp = self.qparents(repo, top)
  1841         if opts.get('reverse'):
  1850         if opts.get(b'reverse'):
  1842             node1, node2 = None, qp
  1851             node1, node2 = None, qp
  1843         else:
  1852         else:
  1844             node1, node2 = qp, None
  1853             node1, node2 = qp, None
  1845         diffopts = self.diffopts(opts, patch)
  1854         diffopts = self.diffopts(opts, patch)
  1846         self.printdiff(repo, diffopts, node1, node2, files=pats, opts=opts)
  1855         self.printdiff(repo, diffopts, node1, node2, files=pats, opts=opts)
  1847 
  1856 
  1848     def refresh(self, repo, pats=None, **opts):
  1857     def refresh(self, repo, pats=None, **opts):
  1849         opts = pycompat.byteskwargs(opts)
  1858         opts = pycompat.byteskwargs(opts)
  1850         if not self.applied:
  1859         if not self.applied:
  1851             self.ui.write(_("no patches applied\n"))
  1860             self.ui.write(_(b"no patches applied\n"))
  1852             return 1
  1861             return 1
  1853         msg = opts.get('msg', '').rstrip()
  1862         msg = opts.get(b'msg', b'').rstrip()
  1854         edit = opts.get('edit')
  1863         edit = opts.get(b'edit')
  1855         editform = opts.get('editform', 'mq.qrefresh')
  1864         editform = opts.get(b'editform', b'mq.qrefresh')
  1856         newuser = opts.get('user')
  1865         newuser = opts.get(b'user')
  1857         newdate = opts.get('date')
  1866         newdate = opts.get(b'date')
  1858         if newdate:
  1867         if newdate:
  1859             newdate = '%d %d' % dateutil.parsedate(newdate)
  1868             newdate = b'%d %d' % dateutil.parsedate(newdate)
  1860         wlock = repo.wlock()
  1869         wlock = repo.wlock()
  1861 
  1870 
  1862         try:
  1871         try:
  1863             self.checktoppatch(repo)
  1872             self.checktoppatch(repo)
  1864             (top, patchfn) = (self.applied[-1].node, self.applied[-1].name)
  1873             (top, patchfn) = (self.applied[-1].node, self.applied[-1].name)
  1865             if repo.changelog.heads(top) != [top]:
  1874             if repo.changelog.heads(top) != [top]:
  1866                 raise error.Abort(_("cannot qrefresh a revision with children"))
  1875                 raise error.Abort(
       
  1876                     _(b"cannot qrefresh a revision with children")
       
  1877                 )
  1867             if not repo[top].mutable():
  1878             if not repo[top].mutable():
  1868                 raise error.Abort(
  1879                 raise error.Abort(
  1869                     _("cannot qrefresh public revision"),
  1880                     _(b"cannot qrefresh public revision"),
  1870                     hint=_("see 'hg help phases' for details"),
  1881                     hint=_(b"see 'hg help phases' for details"),
  1871                 )
  1882                 )
  1872 
  1883 
  1873             cparents = repo.changelog.parents(top)
  1884             cparents = repo.changelog.parents(top)
  1874             patchparent = self.qparents(repo, top)
  1885             patchparent = self.qparents(repo, top)
  1875 
  1886 
  1876             inclsubs = checksubstate(repo, patchparent)
  1887             inclsubs = checksubstate(repo, patchparent)
  1877             if inclsubs:
  1888             if inclsubs:
  1878                 substatestate = repo.dirstate['.hgsubstate']
  1889                 substatestate = repo.dirstate[b'.hgsubstate']
  1879 
  1890 
  1880             ph = patchheader(self.join(patchfn), self.plainmode)
  1891             ph = patchheader(self.join(patchfn), self.plainmode)
  1881             diffopts = self.diffopts(
  1892             diffopts = self.diffopts(
  1882                 {'git': opts.get('git')}, patchfn, plain=True
  1893                 {b'git': opts.get(b'git')}, patchfn, plain=True
  1883             )
  1894             )
  1884             if newuser:
  1895             if newuser:
  1885                 ph.setuser(newuser)
  1896                 ph.setuser(newuser)
  1886             if newdate:
  1897             if newdate:
  1887                 ph.setdate(newdate)
  1898                 ph.setdate(newdate)
  1888             ph.setparent(hex(patchparent))
  1899             ph.setparent(hex(patchparent))
  1889 
  1900 
  1890             # only commit new patch when write is complete
  1901             # only commit new patch when write is complete
  1891             patchf = self.opener(patchfn, 'w', atomictemp=True)
  1902             patchf = self.opener(patchfn, b'w', atomictemp=True)
  1892 
  1903 
  1893             # update the dirstate in place, strip off the qtip commit
  1904             # update the dirstate in place, strip off the qtip commit
  1894             # and then commit.
  1905             # and then commit.
  1895             #
  1906             #
  1896             # this should really read:
  1907             # this should really read:
  1901             ctx = repo[top]
  1912             ctx = repo[top]
  1902             aaa = aa[:]
  1913             aaa = aa[:]
  1903             match1 = scmutil.match(repo[None], pats, opts)
  1914             match1 = scmutil.match(repo[None], pats, opts)
  1904             # in short mode, we only diff the files included in the
  1915             # in short mode, we only diff the files included in the
  1905             # patch already plus specified files
  1916             # patch already plus specified files
  1906             if opts.get('short'):
  1917             if opts.get(b'short'):
  1907                 # if amending a patch, we start with existing
  1918                 # if amending a patch, we start with existing
  1908                 # files plus specified files - unfiltered
  1919                 # files plus specified files - unfiltered
  1909                 match = scmutil.matchfiles(repo, mm + aa + dd + match1.files())
  1920                 match = scmutil.matchfiles(repo, mm + aa + dd + match1.files())
  1910                 # filter with include/exclude options
  1921                 # filter with include/exclude options
  1911                 match1 = scmutil.match(repo[None], opts=opts)
  1922                 match1 = scmutil.match(repo[None], opts=opts)
  1961 
  1972 
  1962             bmlist = repo[top].bookmarks()
  1973             bmlist = repo[top].bookmarks()
  1963 
  1974 
  1964             dsguard = None
  1975             dsguard = None
  1965             try:
  1976             try:
  1966                 dsguard = dirstateguard.dirstateguard(repo, 'mq.refresh')
  1977                 dsguard = dirstateguard.dirstateguard(repo, b'mq.refresh')
  1967                 if diffopts.git or diffopts.upgrade:
  1978                 if diffopts.git or diffopts.upgrade:
  1968                     copies = {}
  1979                     copies = {}
  1969                     for dst in a:
  1980                     for dst in a:
  1970                         src = repo.dirstate.copied(dst)
  1981                         src = repo.dirstate.copied(dst)
  1971                         # during qfold, the source file for copies may
  1982                         # during qfold, the source file for copies may
  2024                 release(dsguard)
  2035                 release(dsguard)
  2025 
  2036 
  2026             try:
  2037             try:
  2027                 # might be nice to attempt to roll back strip after this
  2038                 # might be nice to attempt to roll back strip after this
  2028 
  2039 
  2029                 defaultmsg = "[mq]: %s" % patchfn
  2040                 defaultmsg = b"[mq]: %s" % patchfn
  2030                 editor = cmdutil.getcommiteditor(editform=editform)
  2041                 editor = cmdutil.getcommiteditor(editform=editform)
  2031                 if edit:
  2042                 if edit:
  2032 
  2043 
  2033                     def finishdesc(desc):
  2044                     def finishdesc(desc):
  2034                         if desc.rstrip():
  2045                         if desc.rstrip():
  2035                             ph.setmessage(desc)
  2046                             ph.setmessage(desc)
  2036                             return desc
  2047                             return desc
  2037                         return defaultmsg
  2048                         return defaultmsg
  2038 
  2049 
  2039                     # i18n: this message is shown in editor with "HG: " prefix
  2050                     # i18n: this message is shown in editor with "HG: " prefix
  2040                     extramsg = _('Leave message empty to use default message.')
  2051                     extramsg = _(b'Leave message empty to use default message.')
  2041                     editor = cmdutil.getcommiteditor(
  2052                     editor = cmdutil.getcommiteditor(
  2042                         finishdesc=finishdesc,
  2053                         finishdesc=finishdesc,
  2043                         extramsg=extramsg,
  2054                         extramsg=extramsg,
  2044                         editform=editform,
  2055                         editform=editform,
  2045                     )
  2056                     )
  2046                     message = msg or "\n".join(ph.message)
  2057                     message = msg or b"\n".join(ph.message)
  2047                 elif not msg:
  2058                 elif not msg:
  2048                     if not ph.message:
  2059                     if not ph.message:
  2049                         message = defaultmsg
  2060                         message = defaultmsg
  2050                     else:
  2061                     else:
  2051                         message = "\n".join(ph.message)
  2062                         message = b"\n".join(ph.message)
  2052                 else:
  2063                 else:
  2053                     message = msg
  2064                     message = msg
  2054                     ph.setmessage(msg)
  2065                     ph.setmessage(msg)
  2055 
  2066 
  2056                 # Ensure we create a new changeset in the same phase than
  2067                 # Ensure we create a new changeset in the same phase than
  2057                 # the old one.
  2068                 # the old one.
  2058                 lock = tr = None
  2069                 lock = tr = None
  2059                 try:
  2070                 try:
  2060                     lock = repo.lock()
  2071                     lock = repo.lock()
  2061                     tr = repo.transaction('mq')
  2072                     tr = repo.transaction(b'mq')
  2062                     n = newcommit(
  2073                     n = newcommit(
  2063                         repo,
  2074                         repo,
  2064                         oldphase,
  2075                         oldphase,
  2065                         message,
  2076                         message,
  2066                         user,
  2077                         user,
  2094                 ctx = repo[cparents[0]]
  2105                 ctx = repo[cparents[0]]
  2095                 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
  2106                 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
  2096                 self.savedirty()
  2107                 self.savedirty()
  2097                 self.ui.warn(
  2108                 self.ui.warn(
  2098                     _(
  2109                     _(
  2099                         'qrefresh interrupted while patch was popped! '
  2110                         b'qrefresh interrupted while patch was popped! '
  2100                         '(revert --all, qpush to recover)\n'
  2111                         b'(revert --all, qpush to recover)\n'
  2101                     )
  2112                     )
  2102                 )
  2113                 )
  2103                 raise
  2114                 raise
  2104         finally:
  2115         finally:
  2105             wlock.release()
  2116             wlock.release()
  2106             self.removeundo(repo)
  2117             self.removeundo(repo)
  2107 
  2118 
  2108     def init(self, repo, create=False):
  2119     def init(self, repo, create=False):
  2109         if not create and os.path.isdir(self.path):
  2120         if not create and os.path.isdir(self.path):
  2110             raise error.Abort(_("patch queue directory already exists"))
  2121             raise error.Abort(_(b"patch queue directory already exists"))
  2111         try:
  2122         try:
  2112             os.mkdir(self.path)
  2123             os.mkdir(self.path)
  2113         except OSError as inst:
  2124         except OSError as inst:
  2114             if inst.errno != errno.EEXIST or not create:
  2125             if inst.errno != errno.EEXIST or not create:
  2115                 raise
  2126                 raise
  2116         if create:
  2127         if create:
  2117             return self.qrepo(create=True)
  2128             return self.qrepo(create=True)
  2118 
  2129 
  2119     def unapplied(self, repo, patch=None):
  2130     def unapplied(self, repo, patch=None):
  2120         if patch and patch not in self.series:
  2131         if patch and patch not in self.series:
  2121             raise error.Abort(_("patch %s is not in series file") % patch)
  2132             raise error.Abort(_(b"patch %s is not in series file") % patch)
  2122         if not patch:
  2133         if not patch:
  2123             start = self.seriesend()
  2134             start = self.seriesend()
  2124         else:
  2135         else:
  2125             start = self.series.index(patch) + 1
  2136             start = self.series.index(patch) + 1
  2126         unapplied = []
  2137         unapplied = []
  2146             if summary:
  2157             if summary:
  2147                 ph = patchheader(self.join(patchname), self.plainmode)
  2158                 ph = patchheader(self.join(patchname), self.plainmode)
  2148                 if ph.message:
  2159                 if ph.message:
  2149                     msg = ph.message[0]
  2160                     msg = ph.message[0]
  2150                 else:
  2161                 else:
  2151                     msg = ''
  2162                     msg = b''
  2152 
  2163 
  2153                 if self.ui.formatted():
  2164                 if self.ui.formatted():
  2154                     width = self.ui.termwidth() - len(pfx) - len(patchname) - 2
  2165                     width = self.ui.termwidth() - len(pfx) - len(patchname) - 2
  2155                     if width > 0:
  2166                     if width > 0:
  2156                         msg = stringutil.ellipsis(msg, width)
  2167                         msg = stringutil.ellipsis(msg, width)
  2157                     else:
  2168                     else:
  2158                         msg = ''
  2169                         msg = b''
  2159                 self.ui.write(patchname, label='qseries.' + state)
  2170                 self.ui.write(patchname, label=b'qseries.' + state)
  2160                 self.ui.write(': ')
  2171                 self.ui.write(b': ')
  2161                 self.ui.write(msg, label='qseries.message.' + state)
  2172                 self.ui.write(msg, label=b'qseries.message.' + state)
  2162             else:
  2173             else:
  2163                 self.ui.write(patchname, label='qseries.' + state)
  2174                 self.ui.write(patchname, label=b'qseries.' + state)
  2164             self.ui.write('\n')
  2175             self.ui.write(b'\n')
  2165 
  2176 
  2166         applied = {p.name for p in self.applied}
  2177         applied = {p.name for p in self.applied}
  2167         if length is None:
  2178         if length is None:
  2168             length = len(self.series) - start
  2179             length = len(self.series) - start
  2169         if not missing:
  2180         if not missing:
  2170             if self.ui.verbose:
  2181             if self.ui.verbose:
  2171                 idxwidth = len("%d" % (start + length - 1))
  2182                 idxwidth = len(b"%d" % (start + length - 1))
  2172             for i in pycompat.xrange(start, start + length):
  2183             for i in pycompat.xrange(start, start + length):
  2173                 patch = self.series[i]
  2184                 patch = self.series[i]
  2174                 if patch in applied:
  2185                 if patch in applied:
  2175                     char, state = 'A', 'applied'
  2186                     char, state = b'A', b'applied'
  2176                 elif self.pushable(i)[0]:
  2187                 elif self.pushable(i)[0]:
  2177                     char, state = 'U', 'unapplied'
  2188                     char, state = b'U', b'unapplied'
  2178                 else:
  2189                 else:
  2179                     char, state = 'G', 'guarded'
  2190                     char, state = b'G', b'guarded'
  2180                 pfx = ''
  2191                 pfx = b''
  2181                 if self.ui.verbose:
  2192                 if self.ui.verbose:
  2182                     pfx = '%*d %s ' % (idxwidth, i, char)
  2193                     pfx = b'%*d %s ' % (idxwidth, i, char)
  2183                 elif status and status != char:
  2194                 elif status and status != char:
  2184                     continue
  2195                     continue
  2185                 displayname(pfx, patch, state)
  2196                 displayname(pfx, patch, state)
  2186         else:
  2197         else:
  2187             msng_list = []
  2198             msng_list = []
  2195                         not in (
  2206                         not in (
  2196                             self.statuspath,
  2207                             self.statuspath,
  2197                             self.seriespath,
  2208                             self.seriespath,
  2198                             self.guardspath,
  2209                             self.guardspath,
  2199                         )
  2210                         )
  2200                         and not fl.startswith('.')
  2211                         and not fl.startswith(b'.')
  2201                     ):
  2212                     ):
  2202                         msng_list.append(fl)
  2213                         msng_list.append(fl)
  2203             for x in sorted(msng_list):
  2214             for x in sorted(msng_list):
  2204                 pfx = self.ui.verbose and 'D ' or ''
  2215                 pfx = self.ui.verbose and b'D ' or b''
  2205                 displayname(pfx, x, 'missing')
  2216                 displayname(pfx, x, b'missing')
  2206 
  2217 
  2207     def issaveline(self, l):
  2218     def issaveline(self, l):
  2208         if l.name == '.hg.patches.save.line':
  2219         if l.name == b'.hg.patches.save.line':
  2209             return True
  2220             return True
  2210 
  2221 
  2211     def qrepo(self, create=False):
  2222     def qrepo(self, create=False):
  2212         ui = self.baseui.copy()
  2223         ui = self.baseui.copy()
  2213         # copy back attributes set by ui.pager()
  2224         # copy back attributes set by ui.pager()
  2214         if self.ui.pageractive and not ui.pageractive:
  2225         if self.ui.pageractive and not ui.pageractive:
  2215             ui.pageractive = self.ui.pageractive
  2226             ui.pageractive = self.ui.pageractive
  2216             # internal config: ui.formatted
  2227             # internal config: ui.formatted
  2217             ui.setconfig(
  2228             ui.setconfig(
  2218                 'ui', 'formatted', self.ui.config('ui', 'formatted'), 'mqpager'
  2229                 b'ui',
       
  2230                 b'formatted',
       
  2231                 self.ui.config(b'ui', b'formatted'),
       
  2232                 b'mqpager',
  2219             )
  2233             )
  2220             ui.setconfig(
  2234             ui.setconfig(
  2221                 'ui',
  2235                 b'ui',
  2222                 'interactive',
  2236                 b'interactive',
  2223                 self.ui.config('ui', 'interactive'),
  2237                 self.ui.config(b'ui', b'interactive'),
  2224                 'mqpager',
  2238                 b'mqpager',
  2225             )
  2239             )
  2226         if create or os.path.isdir(self.join(".hg")):
  2240         if create or os.path.isdir(self.join(b".hg")):
  2227             return hg.repository(ui, path=self.path, create=create)
  2241             return hg.repository(ui, path=self.path, create=create)
  2228 
  2242 
  2229     def restore(self, repo, rev, delete=None, qupdate=None):
  2243     def restore(self, repo, rev, delete=None, qupdate=None):
  2230         desc = repo[rev].description().strip()
  2244         desc = repo[rev].description().strip()
  2231         lines = desc.splitlines()
  2245         lines = desc.splitlines()
  2233         datastart = None
  2247         datastart = None
  2234         series = []
  2248         series = []
  2235         applied = []
  2249         applied = []
  2236         qpp = None
  2250         qpp = None
  2237         for i, line in enumerate(lines):
  2251         for i, line in enumerate(lines):
  2238             if line == 'Patch Data:':
  2252             if line == b'Patch Data:':
  2239                 datastart = i + 1
  2253                 datastart = i + 1
  2240             elif line.startswith('Dirstate:'):
  2254             elif line.startswith(b'Dirstate:'):
  2241                 l = line.rstrip()
  2255                 l = line.rstrip()
  2242                 l = l[10:].split(' ')
  2256                 l = l[10:].split(b' ')
  2243                 qpp = [bin(x) for x in l]
  2257                 qpp = [bin(x) for x in l]
  2244             elif datastart is not None:
  2258             elif datastart is not None:
  2245                 l = line.rstrip()
  2259                 l = line.rstrip()
  2246                 n, name = l.split(':', 1)
  2260                 n, name = l.split(b':', 1)
  2247                 if n:
  2261                 if n:
  2248                     applied.append(statusentry(bin(n), name))
  2262                     applied.append(statusentry(bin(n), name))
  2249                 else:
  2263                 else:
  2250                     series.append(l)
  2264                     series.append(l)
  2251         if datastart is None:
  2265         if datastart is None:
  2252             self.ui.warn(_("no saved patch data found\n"))
  2266             self.ui.warn(_(b"no saved patch data found\n"))
  2253             return 1
  2267             return 1
  2254         self.ui.warn(_("restoring status: %s\n") % lines[0])
  2268         self.ui.warn(_(b"restoring status: %s\n") % lines[0])
  2255         self.fullseries = series
  2269         self.fullseries = series
  2256         self.applied = applied
  2270         self.applied = applied
  2257         self.parseseries()
  2271         self.parseseries()
  2258         self.seriesdirty = True
  2272         self.seriesdirty = True
  2259         self.applieddirty = True
  2273         self.applieddirty = True
  2260         heads = repo.changelog.heads()
  2274         heads = repo.changelog.heads()
  2261         if delete:
  2275         if delete:
  2262             if rev not in heads:
  2276             if rev not in heads:
  2263                 self.ui.warn(_("save entry has children, leaving it alone\n"))
  2277                 self.ui.warn(_(b"save entry has children, leaving it alone\n"))
  2264             else:
  2278             else:
  2265                 self.ui.warn(_("removing save entry %s\n") % short(rev))
  2279                 self.ui.warn(_(b"removing save entry %s\n") % short(rev))
  2266                 pp = repo.dirstate.parents()
  2280                 pp = repo.dirstate.parents()
  2267                 if rev in pp:
  2281                 if rev in pp:
  2268                     update = True
  2282                     update = True
  2269                 else:
  2283                 else:
  2270                     update = False
  2284                     update = False
  2271                 strip(self.ui, repo, [rev], update=update, backup=False)
  2285                 strip(self.ui, repo, [rev], update=update, backup=False)
  2272         if qpp:
  2286         if qpp:
  2273             self.ui.warn(
  2287             self.ui.warn(
  2274                 _("saved queue repository parents: %s %s\n")
  2288                 _(b"saved queue repository parents: %s %s\n")
  2275                 % (short(qpp[0]), short(qpp[1]))
  2289                 % (short(qpp[0]), short(qpp[1]))
  2276             )
  2290             )
  2277             if qupdate:
  2291             if qupdate:
  2278                 self.ui.status(_("updating queue directory\n"))
  2292                 self.ui.status(_(b"updating queue directory\n"))
  2279                 r = self.qrepo()
  2293                 r = self.qrepo()
  2280                 if not r:
  2294                 if not r:
  2281                     self.ui.warn(_("unable to load queue repository\n"))
  2295                     self.ui.warn(_(b"unable to load queue repository\n"))
  2282                     return 1
  2296                     return 1
  2283                 hg.clean(r, qpp[0])
  2297                 hg.clean(r, qpp[0])
  2284 
  2298 
  2285     def save(self, repo, msg=None):
  2299     def save(self, repo, msg=None):
  2286         if not self.applied:
  2300         if not self.applied:
  2287             self.ui.warn(_("save: no patches applied, exiting\n"))
  2301             self.ui.warn(_(b"save: no patches applied, exiting\n"))
  2288             return 1
  2302             return 1
  2289         if self.issaveline(self.applied[-1]):
  2303         if self.issaveline(self.applied[-1]):
  2290             self.ui.warn(_("status is already saved\n"))
  2304             self.ui.warn(_(b"status is already saved\n"))
  2291             return 1
  2305             return 1
  2292 
  2306 
  2293         if not msg:
  2307         if not msg:
  2294             msg = _("hg patches saved state")
  2308             msg = _(b"hg patches saved state")
  2295         else:
  2309         else:
  2296             msg = "hg patches: " + msg.rstrip('\r\n')
  2310             msg = b"hg patches: " + msg.rstrip(b'\r\n')
  2297         r = self.qrepo()
  2311         r = self.qrepo()
  2298         if r:
  2312         if r:
  2299             pp = r.dirstate.parents()
  2313             pp = r.dirstate.parents()
  2300             msg += "\nDirstate: %s %s" % (hex(pp[0]), hex(pp[1]))
  2314             msg += b"\nDirstate: %s %s" % (hex(pp[0]), hex(pp[1]))
  2301         msg += "\n\nPatch Data:\n"
  2315         msg += b"\n\nPatch Data:\n"
  2302         msg += ''.join('%s\n' % x for x in self.applied)
  2316         msg += b''.join(b'%s\n' % x for x in self.applied)
  2303         msg += ''.join(':%s\n' % x for x in self.fullseries)
  2317         msg += b''.join(b':%s\n' % x for x in self.fullseries)
  2304         n = repo.commit(msg, force=True)
  2318         n = repo.commit(msg, force=True)
  2305         if not n:
  2319         if not n:
  2306             self.ui.warn(_("repo commit failed\n"))
  2320             self.ui.warn(_(b"repo commit failed\n"))
  2307             return 1
  2321             return 1
  2308         self.applied.append(statusentry(n, '.hg.patches.save.line'))
  2322         self.applied.append(statusentry(n, b'.hg.patches.save.line'))
  2309         self.applieddirty = True
  2323         self.applieddirty = True
  2310         self.removeundo(repo)
  2324         self.removeundo(repo)
  2311 
  2325 
  2312     def fullseriesend(self):
  2326     def fullseriesend(self):
  2313         if self.applied:
  2327         if self.applied:
  2347     def appliedname(self, index):
  2361     def appliedname(self, index):
  2348         pname = self.applied[index].name
  2362         pname = self.applied[index].name
  2349         if not self.ui.verbose:
  2363         if not self.ui.verbose:
  2350             p = pname
  2364             p = pname
  2351         else:
  2365         else:
  2352             p = ("%d" % self.series.index(pname)) + " " + pname
  2366             p = (b"%d" % self.series.index(pname)) + b" " + pname
  2353         return p
  2367         return p
  2354 
  2368 
  2355     def qimport(
  2369     def qimport(
  2356         self,
  2370         self,
  2357         repo,
  2371         repo,
  2363         git=False,
  2377         git=False,
  2364     ):
  2378     ):
  2365         def checkseries(patchname):
  2379         def checkseries(patchname):
  2366             if patchname in self.series:
  2380             if patchname in self.series:
  2367                 raise error.Abort(
  2381                 raise error.Abort(
  2368                     _('patch %s is already in the series file') % patchname
  2382                     _(b'patch %s is already in the series file') % patchname
  2369                 )
  2383                 )
  2370 
  2384 
  2371         if rev:
  2385         if rev:
  2372             if files:
  2386             if files:
  2373                 raise error.Abort(
  2387                 raise error.Abort(
  2374                     _('option "-r" not valid when importing ' 'files')
  2388                     _(b'option "-r" not valid when importing ' b'files')
  2375                 )
  2389                 )
  2376             rev = scmutil.revrange(repo, rev)
  2390             rev = scmutil.revrange(repo, rev)
  2377             rev.sort(reverse=True)
  2391             rev.sort(reverse=True)
  2378         elif not files:
  2392         elif not files:
  2379             raise error.Abort(_('no files or revisions specified'))
  2393             raise error.Abort(_(b'no files or revisions specified'))
  2380         if (len(files) > 1 or len(rev) > 1) and patchname:
  2394         if (len(files) > 1 or len(rev) > 1) and patchname:
  2381             raise error.Abort(
  2395             raise error.Abort(
  2382                 _('option "-n" not valid when importing multiple ' 'patches')
  2396                 _(b'option "-n" not valid when importing multiple ' b'patches')
  2383             )
  2397             )
  2384         imported = []
  2398         imported = []
  2385         if rev:
  2399         if rev:
  2386             # If mq patches are applied, we can only import revisions
  2400             # If mq patches are applied, we can only import revisions
  2387             # that form a linear path to qbase.
  2401             # that form a linear path to qbase.
  2388             # Otherwise, they should form a linear path to a head.
  2402             # Otherwise, they should form a linear path to a head.
  2389             heads = repo.changelog.heads(repo.changelog.node(rev.first()))
  2403             heads = repo.changelog.heads(repo.changelog.node(rev.first()))
  2390             if len(heads) > 1:
  2404             if len(heads) > 1:
  2391                 raise error.Abort(
  2405                 raise error.Abort(
  2392                     _('revision %d is the root of more than one ' 'branch')
  2406                     _(b'revision %d is the root of more than one ' b'branch')
  2393                     % rev.last()
  2407                     % rev.last()
  2394                 )
  2408                 )
  2395             if self.applied:
  2409             if self.applied:
  2396                 base = repo.changelog.node(rev.first())
  2410                 base = repo.changelog.node(rev.first())
  2397                 if base in [n.node for n in self.applied]:
  2411                 if base in [n.node for n in self.applied]:
  2398                     raise error.Abort(
  2412                     raise error.Abort(
  2399                         _('revision %d is already managed') % rev.first()
  2413                         _(b'revision %d is already managed') % rev.first()
  2400                     )
  2414                     )
  2401                 if heads != [self.applied[-1].node]:
  2415                 if heads != [self.applied[-1].node]:
  2402                     raise error.Abort(
  2416                     raise error.Abort(
  2403                         _('revision %d is not the parent of ' 'the queue')
  2417                         _(b'revision %d is not the parent of ' b'the queue')
  2404                         % rev.first()
  2418                         % rev.first()
  2405                     )
  2419                     )
  2406                 base = repo.changelog.rev(self.applied[0].node)
  2420                 base = repo.changelog.rev(self.applied[0].node)
  2407                 lastparent = repo.changelog.parentrevs(base)[0]
  2421                 lastparent = repo.changelog.parentrevs(base)[0]
  2408             else:
  2422             else:
  2409                 if heads != [repo.changelog.node(rev.first())]:
  2423                 if heads != [repo.changelog.node(rev.first())]:
  2410                     raise error.Abort(
  2424                     raise error.Abort(
  2411                         _('revision %d has unmanaged children') % rev.first()
  2425                         _(b'revision %d has unmanaged children') % rev.first()
  2412                     )
  2426                     )
  2413                 lastparent = None
  2427                 lastparent = None
  2414 
  2428 
  2415             diffopts = self.diffopts({'git': git})
  2429             diffopts = self.diffopts({b'git': git})
  2416             with repo.transaction('qimport') as tr:
  2430             with repo.transaction(b'qimport') as tr:
  2417                 for r in rev:
  2431                 for r in rev:
  2418                     if not repo[r].mutable():
  2432                     if not repo[r].mutable():
  2419                         raise error.Abort(
  2433                         raise error.Abort(
  2420                             _('revision %d is not mutable') % r,
  2434                             _(b'revision %d is not mutable') % r,
  2421                             hint=_("see 'hg help phases' " 'for details'),
  2435                             hint=_(b"see 'hg help phases' " b'for details'),
  2422                         )
  2436                         )
  2423                     p1, p2 = repo.changelog.parentrevs(r)
  2437                     p1, p2 = repo.changelog.parentrevs(r)
  2424                     n = repo.changelog.node(r)
  2438                     n = repo.changelog.node(r)
  2425                     if p2 != nullrev:
  2439                     if p2 != nullrev:
  2426                         raise error.Abort(
  2440                         raise error.Abort(
  2427                             _('cannot import merge revision %d') % r
  2441                             _(b'cannot import merge revision %d') % r
  2428                         )
  2442                         )
  2429                     if lastparent and lastparent != r:
  2443                     if lastparent and lastparent != r:
  2430                         raise error.Abort(
  2444                         raise error.Abort(
  2431                             _('revision %d is not the parent of ' '%d')
  2445                             _(b'revision %d is not the parent of ' b'%d')
  2432                             % (r, lastparent)
  2446                             % (r, lastparent)
  2433                         )
  2447                         )
  2434                     lastparent = p1
  2448                     lastparent = p1
  2435 
  2449 
  2436                     if not patchname:
  2450                     if not patchname:
  2437                         patchname = self.makepatchname(
  2451                         patchname = self.makepatchname(
  2438                             repo[r].description().split('\n', 1)[0],
  2452                             repo[r].description().split(b'\n', 1)[0],
  2439                             '%d.diff' % r,
  2453                             b'%d.diff' % r,
  2440                         )
  2454                         )
  2441                     checkseries(patchname)
  2455                     checkseries(patchname)
  2442                     self.checkpatchname(patchname, force)
  2456                     self.checkpatchname(patchname, force)
  2443                     self.fullseries.insert(0, patchname)
  2457                     self.fullseries.insert(0, patchname)
  2444 
  2458 
  2445                     with self.opener(patchname, "w") as fp:
  2459                     with self.opener(patchname, b"w") as fp:
  2446                         cmdutil.exportfile(repo, [n], fp, opts=diffopts)
  2460                         cmdutil.exportfile(repo, [n], fp, opts=diffopts)
  2447 
  2461 
  2448                     se = statusentry(n, patchname)
  2462                     se = statusentry(n, patchname)
  2449                     self.applied.insert(0, se)
  2463                     self.applied.insert(0, se)
  2450 
  2464 
  2451                     self.added.append(patchname)
  2465                     self.added.append(patchname)
  2452                     imported.append(patchname)
  2466                     imported.append(patchname)
  2453                     patchname = None
  2467                     patchname = None
  2454                     if rev and repo.ui.configbool('mq', 'secret'):
  2468                     if rev and repo.ui.configbool(b'mq', b'secret'):
  2455                         # if we added anything with --rev, move the secret root
  2469                         # if we added anything with --rev, move the secret root
  2456                         phases.retractboundary(repo, tr, phases.secret, [n])
  2470                         phases.retractboundary(repo, tr, phases.secret, [n])
  2457                     self.parseseries()
  2471                     self.parseseries()
  2458                     self.applieddirty = True
  2472                     self.applieddirty = True
  2459                     self.seriesdirty = True
  2473                     self.seriesdirty = True
  2460 
  2474 
  2461         for i, filename in enumerate(files):
  2475         for i, filename in enumerate(files):
  2462             if existing:
  2476             if existing:
  2463                 if filename == '-':
  2477                 if filename == b'-':
  2464                     raise error.Abort(
  2478                     raise error.Abort(
  2465                         _('-e is incompatible with import from -')
  2479                         _(b'-e is incompatible with import from -')
  2466                     )
  2480                     )
  2467                 filename = normname(filename)
  2481                 filename = normname(filename)
  2468                 self.checkreservedname(filename)
  2482                 self.checkreservedname(filename)
  2469                 if util.url(filename).islocal():
  2483                 if util.url(filename).islocal():
  2470                     originpath = self.join(filename)
  2484                     originpath = self.join(filename)
  2471                     if not os.path.isfile(originpath):
  2485                     if not os.path.isfile(originpath):
  2472                         raise error.Abort(
  2486                         raise error.Abort(
  2473                             _("patch %s does not exist") % filename
  2487                             _(b"patch %s does not exist") % filename
  2474                         )
  2488                         )
  2475 
  2489 
  2476                 if patchname:
  2490                 if patchname:
  2477                     self.checkpatchname(patchname, force)
  2491                     self.checkpatchname(patchname, force)
  2478 
  2492 
  2479                     self.ui.write(
  2493                     self.ui.write(
  2480                         _('renaming %s to %s\n') % (filename, patchname)
  2494                         _(b'renaming %s to %s\n') % (filename, patchname)
  2481                     )
  2495                     )
  2482                     util.rename(originpath, self.join(patchname))
  2496                     util.rename(originpath, self.join(patchname))
  2483                 else:
  2497                 else:
  2484                     patchname = filename
  2498                     patchname = filename
  2485 
  2499 
  2486             else:
  2500             else:
  2487                 if filename == '-' and not patchname:
  2501                 if filename == b'-' and not patchname:
  2488                     raise error.Abort(_('need --name to import a patch from -'))
  2502                     raise error.Abort(
       
  2503                         _(b'need --name to import a patch from -')
       
  2504                     )
  2489                 elif not patchname:
  2505                 elif not patchname:
  2490                     patchname = normname(os.path.basename(filename.rstrip('/')))
  2506                     patchname = normname(
       
  2507                         os.path.basename(filename.rstrip(b'/'))
       
  2508                     )
  2491                 self.checkpatchname(patchname, force)
  2509                 self.checkpatchname(patchname, force)
  2492                 try:
  2510                 try:
  2493                     if filename == '-':
  2511                     if filename == b'-':
  2494                         text = self.ui.fin.read()
  2512                         text = self.ui.fin.read()
  2495                     else:
  2513                     else:
  2496                         fp = hg.openpath(self.ui, filename)
  2514                         fp = hg.openpath(self.ui, filename)
  2497                         text = fp.read()
  2515                         text = fp.read()
  2498                         fp.close()
  2516                         fp.close()
  2499                 except (OSError, IOError):
  2517                 except (OSError, IOError):
  2500                     raise error.Abort(_("unable to read file %s") % filename)
  2518                     raise error.Abort(_(b"unable to read file %s") % filename)
  2501                 patchf = self.opener(patchname, "w")
  2519                 patchf = self.opener(patchname, b"w")
  2502                 patchf.write(text)
  2520                 patchf.write(text)
  2503                 patchf.close()
  2521                 patchf.close()
  2504             if not force:
  2522             if not force:
  2505                 checkseries(patchname)
  2523                 checkseries(patchname)
  2506             if patchname not in self.series:
  2524             if patchname not in self.series:
  2507                 index = self.fullseriesend() + i
  2525                 index = self.fullseriesend() + i
  2508                 self.fullseries[index:index] = [patchname]
  2526                 self.fullseries[index:index] = [patchname]
  2509             self.parseseries()
  2527             self.parseseries()
  2510             self.seriesdirty = True
  2528             self.seriesdirty = True
  2511             self.ui.warn(_("adding %s to series file\n") % patchname)
  2529             self.ui.warn(_(b"adding %s to series file\n") % patchname)
  2512             self.added.append(patchname)
  2530             self.added.append(patchname)
  2513             imported.append(patchname)
  2531             imported.append(patchname)
  2514             patchname = None
  2532             patchname = None
  2515 
  2533 
  2516         self.removeundo(repo)
  2534         self.removeundo(repo)
  2517         return imported
  2535         return imported
  2518 
  2536 
  2519 
  2537 
  2520 def fixkeepchangesopts(ui, opts):
  2538 def fixkeepchangesopts(ui, opts):
  2521     if (
  2539     if (
  2522         not ui.configbool('mq', 'keepchanges')
  2540         not ui.configbool(b'mq', b'keepchanges')
  2523         or opts.get('force')
  2541         or opts.get(b'force')
  2524         or opts.get('exact')
  2542         or opts.get(b'exact')
  2525     ):
  2543     ):
  2526         return opts
  2544         return opts
  2527     opts = dict(opts)
  2545     opts = dict(opts)
  2528     opts['keep_changes'] = True
  2546     opts[b'keep_changes'] = True
  2529     return opts
  2547     return opts
  2530 
  2548 
  2531 
  2549 
  2532 @command(
  2550 @command(
  2533     "qdelete|qremove|qrm",
  2551     b"qdelete|qremove|qrm",
  2534     [
  2552     [
  2535         ('k', 'keep', None, _('keep patch file')),
  2553         (b'k', b'keep', None, _(b'keep patch file')),
  2536         ('r', 'rev', [], _('stop managing a revision (DEPRECATED)'), _('REV')),
  2554         (
       
  2555             b'r',
       
  2556             b'rev',
       
  2557             [],
       
  2558             _(b'stop managing a revision (DEPRECATED)'),
       
  2559             _(b'REV'),
       
  2560         ),
  2537     ],
  2561     ],
  2538     _('hg qdelete [-k] [PATCH]...'),
  2562     _(b'hg qdelete [-k] [PATCH]...'),
  2539     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  2563     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  2540 )
  2564 )
  2541 def delete(ui, repo, *patches, **opts):
  2565 def delete(ui, repo, *patches, **opts):
  2542     """remove patches from queue
  2566     """remove patches from queue
  2543 
  2567 
  2552     q.savedirty()
  2576     q.savedirty()
  2553     return 0
  2577     return 0
  2554 
  2578 
  2555 
  2579 
  2556 @command(
  2580 @command(
  2557     "qapplied",
  2581     b"qapplied",
  2558     [('1', 'last', None, _('show only the preceding applied patch'))]
  2582     [(b'1', b'last', None, _(b'show only the preceding applied patch'))]
  2559     + seriesopts,
  2583     + seriesopts,
  2560     _('hg qapplied [-1] [-s] [PATCH]'),
  2584     _(b'hg qapplied [-1] [-s] [PATCH]'),
  2561     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  2585     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  2562 )
  2586 )
  2563 def applied(ui, repo, patch=None, **opts):
  2587 def applied(ui, repo, patch=None, **opts):
  2564     """print the patches already applied
  2588     """print the patches already applied
  2565 
  2589 
  2568     q = repo.mq
  2592     q = repo.mq
  2569     opts = pycompat.byteskwargs(opts)
  2593     opts = pycompat.byteskwargs(opts)
  2570 
  2594 
  2571     if patch:
  2595     if patch:
  2572         if patch not in q.series:
  2596         if patch not in q.series:
  2573             raise error.Abort(_("patch %s is not in series file") % patch)
  2597             raise error.Abort(_(b"patch %s is not in series file") % patch)
  2574         end = q.series.index(patch) + 1
  2598         end = q.series.index(patch) + 1
  2575     else:
  2599     else:
  2576         end = q.seriesend(True)
  2600         end = q.seriesend(True)
  2577 
  2601 
  2578     if opts.get('last') and not end:
  2602     if opts.get(b'last') and not end:
  2579         ui.write(_("no patches applied\n"))
  2603         ui.write(_(b"no patches applied\n"))
  2580         return 1
  2604         return 1
  2581     elif opts.get('last') and end == 1:
  2605     elif opts.get(b'last') and end == 1:
  2582         ui.write(_("only one patch applied\n"))
  2606         ui.write(_(b"only one patch applied\n"))
  2583         return 1
  2607         return 1
  2584     elif opts.get('last'):
  2608     elif opts.get(b'last'):
  2585         start = end - 2
  2609         start = end - 2
  2586         end = 1
  2610         end = 1
  2587     else:
  2611     else:
  2588         start = 0
  2612         start = 0
  2589 
  2613 
  2590     q.qseries(
  2614     q.qseries(
  2591         repo, length=end, start=start, status='A', summary=opts.get('summary')
  2615         repo, length=end, start=start, status=b'A', summary=opts.get(b'summary')
  2592     )
  2616     )
  2593 
  2617 
  2594 
  2618 
  2595 @command(
  2619 @command(
  2596     "qunapplied",
  2620     b"qunapplied",
  2597     [('1', 'first', None, _('show only the first patch'))] + seriesopts,
  2621     [(b'1', b'first', None, _(b'show only the first patch'))] + seriesopts,
  2598     _('hg qunapplied [-1] [-s] [PATCH]'),
  2622     _(b'hg qunapplied [-1] [-s] [PATCH]'),
  2599     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  2623     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  2600 )
  2624 )
  2601 def unapplied(ui, repo, patch=None, **opts):
  2625 def unapplied(ui, repo, patch=None, **opts):
  2602     """print the patches not yet applied
  2626     """print the patches not yet applied
  2603 
  2627 
  2605 
  2629 
  2606     q = repo.mq
  2630     q = repo.mq
  2607     opts = pycompat.byteskwargs(opts)
  2631     opts = pycompat.byteskwargs(opts)
  2608     if patch:
  2632     if patch:
  2609         if patch not in q.series:
  2633         if patch not in q.series:
  2610             raise error.Abort(_("patch %s is not in series file") % patch)
  2634             raise error.Abort(_(b"patch %s is not in series file") % patch)
  2611         start = q.series.index(patch) + 1
  2635         start = q.series.index(patch) + 1
  2612     else:
  2636     else:
  2613         start = q.seriesend(True)
  2637         start = q.seriesend(True)
  2614 
  2638 
  2615     if start == len(q.series) and opts.get('first'):
  2639     if start == len(q.series) and opts.get(b'first'):
  2616         ui.write(_("all patches applied\n"))
  2640         ui.write(_(b"all patches applied\n"))
  2617         return 1
  2641         return 1
  2618 
  2642 
  2619     if opts.get('first'):
  2643     if opts.get(b'first'):
  2620         length = 1
  2644         length = 1
  2621     else:
  2645     else:
  2622         length = None
  2646         length = None
  2623     q.qseries(
  2647     q.qseries(
  2624         repo,
  2648         repo,
  2625         start=start,
  2649         start=start,
  2626         length=length,
  2650         length=length,
  2627         status='U',
  2651         status=b'U',
  2628         summary=opts.get('summary'),
  2652         summary=opts.get(b'summary'),
  2629     )
  2653     )
  2630 
  2654 
  2631 
  2655 
  2632 @command(
  2656 @command(
  2633     "qimport",
  2657     b"qimport",
  2634     [
  2658     [
  2635         ('e', 'existing', None, _('import file in patch directory')),
  2659         (b'e', b'existing', None, _(b'import file in patch directory')),
  2636         ('n', 'name', '', _('name of patch file'), _('NAME')),
  2660         (b'n', b'name', b'', _(b'name of patch file'), _(b'NAME')),
  2637         ('f', 'force', None, _('overwrite existing files')),
  2661         (b'f', b'force', None, _(b'overwrite existing files')),
  2638         (
  2662         (
  2639             'r',
  2663             b'r',
  2640             'rev',
  2664             b'rev',
  2641             [],
  2665             [],
  2642             _('place existing revisions under mq control'),
  2666             _(b'place existing revisions under mq control'),
  2643             _('REV'),
  2667             _(b'REV'),
  2644         ),
  2668         ),
  2645         ('g', 'git', None, _('use git extended diff format')),
  2669         (b'g', b'git', None, _(b'use git extended diff format')),
  2646         ('P', 'push', None, _('qpush after importing')),
  2670         (b'P', b'push', None, _(b'qpush after importing')),
  2647     ],
  2671     ],
  2648     _('hg qimport [-e] [-n NAME] [-f] [-g] [-P] [-r REV]... [FILE]...'),
  2672     _(b'hg qimport [-e] [-n NAME] [-f] [-g] [-P] [-r REV]... [FILE]...'),
  2649     helpcategory=command.CATEGORY_IMPORT_EXPORT,
  2673     helpcategory=command.CATEGORY_IMPORT_EXPORT,
  2650 )
  2674 )
  2651 def qimport(ui, repo, *filename, **opts):
  2675 def qimport(ui, repo, *filename, **opts):
  2652     """import a patch or existing changeset
  2676     """import a patch or existing changeset
  2653 
  2677 
  2687         q = repo.mq
  2711         q = repo.mq
  2688         try:
  2712         try:
  2689             imported = q.qimport(
  2713             imported = q.qimport(
  2690                 repo,
  2714                 repo,
  2691                 filename,
  2715                 filename,
  2692                 patchname=opts.get('name'),
  2716                 patchname=opts.get(b'name'),
  2693                 existing=opts.get('existing'),
  2717                 existing=opts.get(b'existing'),
  2694                 force=opts.get('force'),
  2718                 force=opts.get(b'force'),
  2695                 rev=opts.get('rev'),
  2719                 rev=opts.get(b'rev'),
  2696                 git=opts.get('git'),
  2720                 git=opts.get(b'git'),
  2697             )
  2721             )
  2698         finally:
  2722         finally:
  2699             q.savedirty()
  2723             q.savedirty()
  2700 
  2724 
  2701     if imported and opts.get('push') and not opts.get('rev'):
  2725     if imported and opts.get(b'push') and not opts.get(b'rev'):
  2702         return q.push(repo, imported[-1])
  2726         return q.push(repo, imported[-1])
  2703     return 0
  2727     return 0
  2704 
  2728 
  2705 
  2729 
  2706 def qinit(ui, repo, create):
  2730 def qinit(ui, repo, create):
  2713     Returns 0 if initialization succeeded."""
  2737     Returns 0 if initialization succeeded."""
  2714     q = repo.mq
  2738     q = repo.mq
  2715     r = q.init(repo, create)
  2739     r = q.init(repo, create)
  2716     q.savedirty()
  2740     q.savedirty()
  2717     if r:
  2741     if r:
  2718         if not os.path.exists(r.wjoin('.hgignore')):
  2742         if not os.path.exists(r.wjoin(b'.hgignore')):
  2719             fp = r.wvfs('.hgignore', 'w')
  2743             fp = r.wvfs(b'.hgignore', b'w')
  2720             fp.write('^\\.hg\n')
  2744             fp.write(b'^\\.hg\n')
  2721             fp.write('^\\.mq\n')
  2745             fp.write(b'^\\.mq\n')
  2722             fp.write('syntax: glob\n')
  2746             fp.write(b'syntax: glob\n')
  2723             fp.write('status\n')
  2747             fp.write(b'status\n')
  2724             fp.write('guards\n')
  2748             fp.write(b'guards\n')
  2725             fp.close()
  2749             fp.close()
  2726         if not os.path.exists(r.wjoin('series')):
  2750         if not os.path.exists(r.wjoin(b'series')):
  2727             r.wvfs('series', 'w').close()
  2751             r.wvfs(b'series', b'w').close()
  2728         r[None].add(['.hgignore', 'series'])
  2752         r[None].add([b'.hgignore', b'series'])
  2729         commands.add(ui, r)
  2753         commands.add(ui, r)
  2730     return 0
  2754     return 0
  2731 
  2755 
  2732 
  2756 
  2733 @command(
  2757 @command(
  2734     "qinit",
  2758     b"qinit",
  2735     [('c', 'create-repo', None, _('create queue repository'))],
  2759     [(b'c', b'create-repo', None, _(b'create queue repository'))],
  2736     _('hg qinit [-c]'),
  2760     _(b'hg qinit [-c]'),
  2737     helpcategory=command.CATEGORY_REPO_CREATION,
  2761     helpcategory=command.CATEGORY_REPO_CREATION,
  2738     helpbasic=True,
  2762     helpbasic=True,
  2739 )
  2763 )
  2740 def init(ui, repo, **opts):
  2764 def init(ui, repo, **opts):
  2741     """init a new queue repository (DEPRECATED)
  2765     """init a new queue repository (DEPRECATED)
  2750     commands. With -c, use :hg:`init --mq` instead."""
  2774     commands. With -c, use :hg:`init --mq` instead."""
  2751     return qinit(ui, repo, create=opts.get(r'create_repo'))
  2775     return qinit(ui, repo, create=opts.get(r'create_repo'))
  2752 
  2776 
  2753 
  2777 
  2754 @command(
  2778 @command(
  2755     "qclone",
  2779     b"qclone",
  2756     [
  2780     [
  2757         ('', 'pull', None, _('use pull protocol to copy metadata')),
  2781         (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
  2758         ('U', 'noupdate', None, _('do not update the new working directories')),
       
  2759         (
  2782         (
  2760             '',
  2783             b'U',
  2761             'uncompressed',
  2784             b'noupdate',
  2762             None,
  2785             None,
  2763             _('use uncompressed transfer (fast over LAN)'),
  2786             _(b'do not update the new working directories'),
  2764         ),
  2787         ),
  2765         (
  2788         (
  2766             'p',
  2789             b'',
  2767             'patches',
  2790             b'uncompressed',
  2768             '',
  2791             None,
  2769             _('location of source patch repository'),
  2792             _(b'use uncompressed transfer (fast over LAN)'),
  2770             _('REPO'),
  2793         ),
       
  2794         (
       
  2795             b'p',
       
  2796             b'patches',
       
  2797             b'',
       
  2798             _(b'location of source patch repository'),
       
  2799             _(b'REPO'),
  2771         ),
  2800         ),
  2772     ]
  2801     ]
  2773     + cmdutil.remoteopts,
  2802     + cmdutil.remoteopts,
  2774     _('hg qclone [OPTION]... SOURCE [DEST]'),
  2803     _(b'hg qclone [OPTION]... SOURCE [DEST]'),
  2775     helpcategory=command.CATEGORY_REPO_CREATION,
  2804     helpcategory=command.CATEGORY_REPO_CREATION,
  2776     norepo=True,
  2805     norepo=True,
  2777 )
  2806 )
  2778 def clone(ui, source, dest=None, **opts):
  2807 def clone(ui, source, dest=None, **opts):
  2779     '''clone main and patch repository at same time
  2808     '''clone main and patch repository at same time
  2795     opts = pycompat.byteskwargs(opts)
  2824     opts = pycompat.byteskwargs(opts)
  2796 
  2825 
  2797     def patchdir(repo):
  2826     def patchdir(repo):
  2798         """compute a patch repo url from a repo object"""
  2827         """compute a patch repo url from a repo object"""
  2799         url = repo.url()
  2828         url = repo.url()
  2800         if url.endswith('/'):
  2829         if url.endswith(b'/'):
  2801             url = url[:-1]
  2830             url = url[:-1]
  2802         return url + '/.hg/patches'
  2831         return url + b'/.hg/patches'
  2803 
  2832 
  2804     # main repo (destination and sources)
  2833     # main repo (destination and sources)
  2805     if dest is None:
  2834     if dest is None:
  2806         dest = hg.defaultdest(source)
  2835         dest = hg.defaultdest(source)
  2807     sr = hg.peer(ui, opts, ui.expandpath(source))
  2836     sr = hg.peer(ui, opts, ui.expandpath(source))
  2808 
  2837 
  2809     # patches repo (source only)
  2838     # patches repo (source only)
  2810     if opts.get('patches'):
  2839     if opts.get(b'patches'):
  2811         patchespath = ui.expandpath(opts.get('patches'))
  2840         patchespath = ui.expandpath(opts.get(b'patches'))
  2812     else:
  2841     else:
  2813         patchespath = patchdir(sr)
  2842         patchespath = patchdir(sr)
  2814     try:
  2843     try:
  2815         hg.peer(ui, opts, patchespath)
  2844         hg.peer(ui, opts, patchespath)
  2816     except error.RepoError:
  2845     except error.RepoError:
  2817         raise error.Abort(
  2846         raise error.Abort(
  2818             _('versioned patch repository not found' ' (see init --mq)')
  2847             _(b'versioned patch repository not found' b' (see init --mq)')
  2819         )
  2848         )
  2820     qbase, destrev = None, None
  2849     qbase, destrev = None, None
  2821     if sr.local():
  2850     if sr.local():
  2822         repo = sr.local()
  2851         repo = sr.local()
  2823         if repo.mq.applied and repo[qbase].phase() != phases.secret:
  2852         if repo.mq.applied and repo[qbase].phase() != phases.secret:
  2824             qbase = repo.mq.applied[0].node
  2853             qbase = repo.mq.applied[0].node
  2825             if not hg.islocal(dest):
  2854             if not hg.islocal(dest):
  2826                 heads = set(repo.heads())
  2855                 heads = set(repo.heads())
  2827                 destrev = list(heads.difference(repo.heads(qbase)))
  2856                 destrev = list(heads.difference(repo.heads(qbase)))
  2828                 destrev.append(repo.changelog.parents(qbase)[0])
  2857                 destrev.append(repo.changelog.parents(qbase)[0])
  2829     elif sr.capable('lookup'):
  2858     elif sr.capable(b'lookup'):
  2830         try:
  2859         try:
  2831             qbase = sr.lookup('qbase')
  2860             qbase = sr.lookup(b'qbase')
  2832         except error.RepoError:
  2861         except error.RepoError:
  2833             pass
  2862             pass
  2834 
  2863 
  2835     ui.note(_('cloning main repository\n'))
  2864     ui.note(_(b'cloning main repository\n'))
  2836     sr, dr = hg.clone(
  2865     sr, dr = hg.clone(
  2837         ui,
  2866         ui,
  2838         opts,
  2867         opts,
  2839         sr.url(),
  2868         sr.url(),
  2840         dest,
  2869         dest,
  2841         pull=opts.get('pull'),
  2870         pull=opts.get(b'pull'),
  2842         revs=destrev,
  2871         revs=destrev,
  2843         update=False,
  2872         update=False,
  2844         stream=opts.get('uncompressed'),
  2873         stream=opts.get(b'uncompressed'),
  2845     )
  2874     )
  2846 
  2875 
  2847     ui.note(_('cloning patch repository\n'))
  2876     ui.note(_(b'cloning patch repository\n'))
  2848     hg.clone(
  2877     hg.clone(
  2849         ui,
  2878         ui,
  2850         opts,
  2879         opts,
  2851         opts.get('patches') or patchdir(sr),
  2880         opts.get(b'patches') or patchdir(sr),
  2852         patchdir(dr),
  2881         patchdir(dr),
  2853         pull=opts.get('pull'),
  2882         pull=opts.get(b'pull'),
  2854         update=not opts.get('noupdate'),
  2883         update=not opts.get(b'noupdate'),
  2855         stream=opts.get('uncompressed'),
  2884         stream=opts.get(b'uncompressed'),
  2856     )
  2885     )
  2857 
  2886 
  2858     if dr.local():
  2887     if dr.local():
  2859         repo = dr.local()
  2888         repo = dr.local()
  2860         if qbase:
  2889         if qbase:
  2861             ui.note(
  2890             ui.note(
  2862                 _('stripping applied patches from destination ' 'repository\n')
  2891                 _(
       
  2892                     b'stripping applied patches from destination '
       
  2893                     b'repository\n'
       
  2894                 )
  2863             )
  2895             )
  2864             strip(ui, repo, [qbase], update=False, backup=None)
  2896             strip(ui, repo, [qbase], update=False, backup=None)
  2865         if not opts.get('noupdate'):
  2897         if not opts.get(b'noupdate'):
  2866             ui.note(_('updating destination repository\n'))
  2898             ui.note(_(b'updating destination repository\n'))
  2867             hg.update(repo, repo.changelog.tip())
  2899             hg.update(repo, repo.changelog.tip())
  2868 
  2900 
  2869 
  2901 
  2870 @command(
  2902 @command(
  2871     "qcommit|qci",
  2903     b"qcommit|qci",
  2872     commands.table["commit|ci"][1],
  2904     commands.table[b"commit|ci"][1],
  2873     _('hg qcommit [OPTION]... [FILE]...'),
  2905     _(b'hg qcommit [OPTION]... [FILE]...'),
  2874     helpcategory=command.CATEGORY_COMMITTING,
  2906     helpcategory=command.CATEGORY_COMMITTING,
  2875     inferrepo=True,
  2907     inferrepo=True,
  2876 )
  2908 )
  2877 def commit(ui, repo, *pats, **opts):
  2909 def commit(ui, repo, *pats, **opts):
  2878     """commit changes in the queue repository (DEPRECATED)
  2910     """commit changes in the queue repository (DEPRECATED)
  2879 
  2911 
  2880     This command is deprecated; use :hg:`commit --mq` instead."""
  2912     This command is deprecated; use :hg:`commit --mq` instead."""
  2881     q = repo.mq
  2913     q = repo.mq
  2882     r = q.qrepo()
  2914     r = q.qrepo()
  2883     if not r:
  2915     if not r:
  2884         raise error.Abort('no queue repository')
  2916         raise error.Abort(b'no queue repository')
  2885     commands.commit(r.ui, r, *pats, **opts)
  2917     commands.commit(r.ui, r, *pats, **opts)
  2886 
  2918 
  2887 
  2919 
  2888 @command(
  2920 @command(
  2889     "qseries",
  2921     b"qseries",
  2890     [('m', 'missing', None, _('print patches not in series')),] + seriesopts,
  2922     [(b'm', b'missing', None, _(b'print patches not in series')),] + seriesopts,
  2891     _('hg qseries [-ms]'),
  2923     _(b'hg qseries [-ms]'),
  2892     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  2924     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  2893 )
  2925 )
  2894 def series(ui, repo, **opts):
  2926 def series(ui, repo, **opts):
  2895     """print the entire series file
  2927     """print the entire series file
  2896 
  2928 
  2900     )
  2932     )
  2901     return 0
  2933     return 0
  2902 
  2934 
  2903 
  2935 
  2904 @command(
  2936 @command(
  2905     "qtop",
  2937     b"qtop",
  2906     seriesopts,
  2938     seriesopts,
  2907     _('hg qtop [-s]'),
  2939     _(b'hg qtop [-s]'),
  2908     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  2940     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  2909 )
  2941 )
  2910 def top(ui, repo, **opts):
  2942 def top(ui, repo, **opts):
  2911     """print the name of the current patch
  2943     """print the name of the current patch
  2912 
  2944 
  2920     if t:
  2952     if t:
  2921         q.qseries(
  2953         q.qseries(
  2922             repo,
  2954             repo,
  2923             start=t - 1,
  2955             start=t - 1,
  2924             length=1,
  2956             length=1,
  2925             status='A',
  2957             status=b'A',
  2926             summary=opts.get(r'summary'),
  2958             summary=opts.get(r'summary'),
  2927         )
  2959         )
  2928     else:
  2960     else:
  2929         ui.write(_("no patches applied\n"))
  2961         ui.write(_(b"no patches applied\n"))
  2930         return 1
  2962         return 1
  2931 
  2963 
  2932 
  2964 
  2933 @command(
  2965 @command(
  2934     "qnext",
  2966     b"qnext",
  2935     seriesopts,
  2967     seriesopts,
  2936     _('hg qnext [-s]'),
  2968     _(b'hg qnext [-s]'),
  2937     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  2969     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  2938 )
  2970 )
  2939 def next(ui, repo, **opts):
  2971 def next(ui, repo, **opts):
  2940     """print the name of the next pushable patch
  2972     """print the name of the next pushable patch
  2941 
  2973 
  2942     Returns 0 on success."""
  2974     Returns 0 on success."""
  2943     q = repo.mq
  2975     q = repo.mq
  2944     end = q.seriesend()
  2976     end = q.seriesend()
  2945     if end == len(q.series):
  2977     if end == len(q.series):
  2946         ui.write(_("all patches applied\n"))
  2978         ui.write(_(b"all patches applied\n"))
  2947         return 1
  2979         return 1
  2948     q.qseries(repo, start=end, length=1, summary=opts.get(r'summary'))
  2980     q.qseries(repo, start=end, length=1, summary=opts.get(r'summary'))
  2949 
  2981 
  2950 
  2982 
  2951 @command(
  2983 @command(
  2952     "qprev",
  2984     b"qprev",
  2953     seriesopts,
  2985     seriesopts,
  2954     _('hg qprev [-s]'),
  2986     _(b'hg qprev [-s]'),
  2955     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  2987     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  2956 )
  2988 )
  2957 def prev(ui, repo, **opts):
  2989 def prev(ui, repo, **opts):
  2958     """print the name of the preceding applied patch
  2990     """print the name of the preceding applied patch
  2959 
  2991 
  2960     Returns 0 on success."""
  2992     Returns 0 on success."""
  2961     q = repo.mq
  2993     q = repo.mq
  2962     l = len(q.applied)
  2994     l = len(q.applied)
  2963     if l == 1:
  2995     if l == 1:
  2964         ui.write(_("only one patch applied\n"))
  2996         ui.write(_(b"only one patch applied\n"))
  2965         return 1
  2997         return 1
  2966     if not l:
  2998     if not l:
  2967         ui.write(_("no patches applied\n"))
  2999         ui.write(_(b"no patches applied\n"))
  2968         return 1
  3000         return 1
  2969     idx = q.series.index(q.applied[-2].name)
  3001     idx = q.series.index(q.applied[-2].name)
  2970     q.qseries(
  3002     q.qseries(
  2971         repo, start=idx, length=1, status='A', summary=opts.get(r'summary')
  3003         repo, start=idx, length=1, status=b'A', summary=opts.get(r'summary')
  2972     )
  3004     )
  2973 
  3005 
  2974 
  3006 
  2975 def setupheaderopts(ui, opts):
  3007 def setupheaderopts(ui, opts):
  2976     if not opts.get('user') and opts.get('currentuser'):
  3008     if not opts.get(b'user') and opts.get(b'currentuser'):
  2977         opts['user'] = ui.username()
  3009         opts[b'user'] = ui.username()
  2978     if not opts.get('date') and opts.get('currentdate'):
  3010     if not opts.get(b'date') and opts.get(b'currentdate'):
  2979         opts['date'] = "%d %d" % dateutil.makedate()
  3011         opts[b'date'] = b"%d %d" % dateutil.makedate()
  2980 
  3012 
  2981 
  3013 
  2982 @command(
  3014 @command(
  2983     "qnew",
  3015     b"qnew",
  2984     [
  3016     [
  2985         ('e', 'edit', None, _('invoke editor on commit messages')),
  3017         (b'e', b'edit', None, _(b'invoke editor on commit messages')),
  2986         ('f', 'force', None, _('import uncommitted changes (DEPRECATED)')),
  3018         (b'f', b'force', None, _(b'import uncommitted changes (DEPRECATED)')),
  2987         ('g', 'git', None, _('use git extended diff format')),
  3019         (b'g', b'git', None, _(b'use git extended diff format')),
  2988         ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
  3020         (b'U', b'currentuser', None, _(b'add "From: <current user>" to patch')),
  2989         ('u', 'user', '', _('add "From: <USER>" to patch'), _('USER')),
  3021         (b'u', b'user', b'', _(b'add "From: <USER>" to patch'), _(b'USER')),
  2990         ('D', 'currentdate', None, _('add "Date: <current date>" to patch')),
  3022         (b'D', b'currentdate', None, _(b'add "Date: <current date>" to patch')),
  2991         ('d', 'date', '', _('add "Date: <DATE>" to patch'), _('DATE')),
  3023         (b'd', b'date', b'', _(b'add "Date: <DATE>" to patch'), _(b'DATE')),
  2992     ]
  3024     ]
  2993     + cmdutil.walkopts
  3025     + cmdutil.walkopts
  2994     + cmdutil.commitopts,
  3026     + cmdutil.commitopts,
  2995     _('hg qnew [-e] [-m TEXT] [-l FILE] PATCH [FILE]...'),
  3027     _(b'hg qnew [-e] [-m TEXT] [-l FILE] PATCH [FILE]...'),
  2996     helpcategory=command.CATEGORY_COMMITTING,
  3028     helpcategory=command.CATEGORY_COMMITTING,
  2997     helpbasic=True,
  3029     helpbasic=True,
  2998     inferrepo=True,
  3030     inferrepo=True,
  2999 )
  3031 )
  3000 def new(ui, repo, patch, *args, **opts):
  3032 def new(ui, repo, patch, *args, **opts):
  3023     Returns 0 on successful creation of a new patch.
  3055     Returns 0 on successful creation of a new patch.
  3024     """
  3056     """
  3025     opts = pycompat.byteskwargs(opts)
  3057     opts = pycompat.byteskwargs(opts)
  3026     msg = cmdutil.logmessage(ui, opts)
  3058     msg = cmdutil.logmessage(ui, opts)
  3027     q = repo.mq
  3059     q = repo.mq
  3028     opts['msg'] = msg
  3060     opts[b'msg'] = msg
  3029     setupheaderopts(ui, opts)
  3061     setupheaderopts(ui, opts)
  3030     q.new(repo, patch, *args, **pycompat.strkwargs(opts))
  3062     q.new(repo, patch, *args, **pycompat.strkwargs(opts))
  3031     q.savedirty()
  3063     q.savedirty()
  3032     return 0
  3064     return 0
  3033 
  3065 
  3034 
  3066 
  3035 @command(
  3067 @command(
  3036     "qrefresh",
  3068     b"qrefresh",
  3037     [
  3069     [
  3038         ('e', 'edit', None, _('invoke editor on commit messages')),
  3070         (b'e', b'edit', None, _(b'invoke editor on commit messages')),
  3039         ('g', 'git', None, _('use git extended diff format')),
  3071         (b'g', b'git', None, _(b'use git extended diff format')),
  3040         (
  3072         (
  3041             's',
  3073             b's',
  3042             'short',
  3074             b'short',
  3043             None,
  3075             None,
  3044             _('refresh only files already in the patch and specified files'),
  3076             _(b'refresh only files already in the patch and specified files'),
  3045         ),
  3077         ),
  3046         (
  3078         (
  3047             'U',
  3079             b'U',
  3048             'currentuser',
  3080             b'currentuser',
  3049             None,
  3081             None,
  3050             _('add/update author field in patch with current user'),
  3082             _(b'add/update author field in patch with current user'),
  3051         ),
  3083         ),
  3052         (
  3084         (
  3053             'u',
  3085             b'u',
  3054             'user',
  3086             b'user',
  3055             '',
  3087             b'',
  3056             _('add/update author field in patch with given user'),
  3088             _(b'add/update author field in patch with given user'),
  3057             _('USER'),
  3089             _(b'USER'),
  3058         ),
  3090         ),
  3059         (
  3091         (
  3060             'D',
  3092             b'D',
  3061             'currentdate',
  3093             b'currentdate',
  3062             None,
  3094             None,
  3063             _('add/update date field in patch with current date'),
  3095             _(b'add/update date field in patch with current date'),
  3064         ),
  3096         ),
  3065         (
  3097         (
  3066             'd',
  3098             b'd',
  3067             'date',
  3099             b'date',
  3068             '',
  3100             b'',
  3069             _('add/update date field in patch with given date'),
  3101             _(b'add/update date field in patch with given date'),
  3070             _('DATE'),
  3102             _(b'DATE'),
  3071         ),
  3103         ),
  3072     ]
  3104     ]
  3073     + cmdutil.walkopts
  3105     + cmdutil.walkopts
  3074     + cmdutil.commitopts,
  3106     + cmdutil.commitopts,
  3075     _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...'),
  3107     _(b'hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...'),
  3076     helpcategory=command.CATEGORY_COMMITTING,
  3108     helpcategory=command.CATEGORY_COMMITTING,
  3077     helpbasic=True,
  3109     helpbasic=True,
  3078     inferrepo=True,
  3110     inferrepo=True,
  3079 )
  3111 )
  3080 def refresh(ui, repo, *pats, **opts):
  3112 def refresh(ui, repo, *pats, **opts):
  3107         q.savedirty()
  3139         q.savedirty()
  3108         return ret
  3140         return ret
  3109 
  3141 
  3110 
  3142 
  3111 @command(
  3143 @command(
  3112     "qdiff",
  3144     b"qdiff",
  3113     cmdutil.diffopts + cmdutil.diffopts2 + cmdutil.walkopts,
  3145     cmdutil.diffopts + cmdutil.diffopts2 + cmdutil.walkopts,
  3114     _('hg qdiff [OPTION]... [FILE]...'),
  3146     _(b'hg qdiff [OPTION]... [FILE]...'),
  3115     helpcategory=command.CATEGORY_FILE_CONTENTS,
  3147     helpcategory=command.CATEGORY_FILE_CONTENTS,
  3116     helpbasic=True,
  3148     helpbasic=True,
  3117     inferrepo=True,
  3149     inferrepo=True,
  3118 )
  3150 )
  3119 def diff(ui, repo, *pats, **opts):
  3151 def diff(ui, repo, *pats, **opts):
  3129     made by the current patch without including changes made since the
  3161     made by the current patch without including changes made since the
  3130     qrefresh.
  3162     qrefresh.
  3131 
  3163 
  3132     Returns 0 on success.
  3164     Returns 0 on success.
  3133     """
  3165     """
  3134     ui.pager('qdiff')
  3166     ui.pager(b'qdiff')
  3135     repo.mq.diff(repo, pats, pycompat.byteskwargs(opts))
  3167     repo.mq.diff(repo, pats, pycompat.byteskwargs(opts))
  3136     return 0
  3168     return 0
  3137 
  3169 
  3138 
  3170 
  3139 @command(
  3171 @command(
  3140     'qfold',
  3172     b'qfold',
  3141     [
  3173     [
  3142         ('e', 'edit', None, _('invoke editor on commit messages')),
  3174         (b'e', b'edit', None, _(b'invoke editor on commit messages')),
  3143         ('k', 'keep', None, _('keep folded patch files')),
  3175         (b'k', b'keep', None, _(b'keep folded patch files')),
  3144     ]
  3176     ]
  3145     + cmdutil.commitopts,
  3177     + cmdutil.commitopts,
  3146     _('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...'),
  3178     _(b'hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...'),
  3147     helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
  3179     helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
  3148 )
  3180 )
  3149 def fold(ui, repo, *files, **opts):
  3181 def fold(ui, repo, *files, **opts):
  3150     """fold the named patches into the current patch
  3182     """fold the named patches into the current patch
  3151 
  3183 
  3161 
  3193 
  3162     Returns 0 on success."""
  3194     Returns 0 on success."""
  3163     opts = pycompat.byteskwargs(opts)
  3195     opts = pycompat.byteskwargs(opts)
  3164     q = repo.mq
  3196     q = repo.mq
  3165     if not files:
  3197     if not files:
  3166         raise error.Abort(_('qfold requires at least one patch name'))
  3198         raise error.Abort(_(b'qfold requires at least one patch name'))
  3167     if not q.checktoppatch(repo)[0]:
  3199     if not q.checktoppatch(repo)[0]:
  3168         raise error.Abort(_('no patches applied'))
  3200         raise error.Abort(_(b'no patches applied'))
  3169     q.checklocalchanges(repo)
  3201     q.checklocalchanges(repo)
  3170 
  3202 
  3171     message = cmdutil.logmessage(ui, opts)
  3203     message = cmdutil.logmessage(ui, opts)
  3172 
  3204 
  3173     parent = q.lookup('qtip')
  3205     parent = q.lookup(b'qtip')
  3174     patches = []
  3206     patches = []
  3175     messages = []
  3207     messages = []
  3176     for f in files:
  3208     for f in files:
  3177         p = q.lookup(f)
  3209         p = q.lookup(f)
  3178         if p in patches or p == parent:
  3210         if p in patches or p == parent:
  3179             ui.warn(_('skipping already folded patch %s\n') % p)
  3211             ui.warn(_(b'skipping already folded patch %s\n') % p)
  3180         if q.isapplied(p):
  3212         if q.isapplied(p):
  3181             raise error.Abort(
  3213             raise error.Abort(
  3182                 _('qfold cannot fold already applied patch %s') % p
  3214                 _(b'qfold cannot fold already applied patch %s') % p
  3183             )
  3215             )
  3184         patches.append(p)
  3216         patches.append(p)
  3185 
  3217 
  3186     for p in patches:
  3218     for p in patches:
  3187         if not message:
  3219         if not message:
  3189             if ph.message:
  3221             if ph.message:
  3190                 messages.append(ph.message)
  3222                 messages.append(ph.message)
  3191         pf = q.join(p)
  3223         pf = q.join(p)
  3192         (patchsuccess, files, fuzz) = q.patch(repo, pf)
  3224         (patchsuccess, files, fuzz) = q.patch(repo, pf)
  3193         if not patchsuccess:
  3225         if not patchsuccess:
  3194             raise error.Abort(_('error folding patch %s') % p)
  3226             raise error.Abort(_(b'error folding patch %s') % p)
  3195 
  3227 
  3196     if not message:
  3228     if not message:
  3197         ph = patchheader(q.join(parent), q.plainmode)
  3229         ph = patchheader(q.join(parent), q.plainmode)
  3198         message = ph.message
  3230         message = ph.message
  3199         for msg in messages:
  3231         for msg in messages:
  3200             if msg:
  3232             if msg:
  3201                 if message:
  3233                 if message:
  3202                     message.append('* * *')
  3234                     message.append(b'* * *')
  3203                 message.extend(msg)
  3235                 message.extend(msg)
  3204         message = '\n'.join(message)
  3236         message = b'\n'.join(message)
  3205 
  3237 
  3206     diffopts = q.patchopts(q.diffopts(), *patches)
  3238     diffopts = q.patchopts(q.diffopts(), *patches)
  3207     with repo.wlock():
  3239     with repo.wlock():
  3208         q.refresh(
  3240         q.refresh(
  3209             repo,
  3241             repo,
  3210             msg=message,
  3242             msg=message,
  3211             git=diffopts.git,
  3243             git=diffopts.git,
  3212             edit=opts.get('edit'),
  3244             edit=opts.get(b'edit'),
  3213             editform='mq.qfold',
  3245             editform=b'mq.qfold',
  3214         )
  3246         )
  3215         q.delete(repo, patches, opts)
  3247         q.delete(repo, patches, opts)
  3216         q.savedirty()
  3248         q.savedirty()
  3217 
  3249 
  3218 
  3250 
  3219 @command(
  3251 @command(
  3220     "qgoto",
  3252     b"qgoto",
  3221     [
  3253     [
  3222         ('', 'keep-changes', None, _('tolerate non-conflicting local changes')),
  3254         (
  3223         ('f', 'force', None, _('overwrite any local changes')),
  3255             b'',
  3224         ('', 'no-backup', None, _('do not save backup copies of files')),
  3256             b'keep-changes',
       
  3257             None,
       
  3258             _(b'tolerate non-conflicting local changes'),
       
  3259         ),
       
  3260         (b'f', b'force', None, _(b'overwrite any local changes')),
       
  3261         (b'', b'no-backup', None, _(b'do not save backup copies of files')),
  3225     ],
  3262     ],
  3226     _('hg qgoto [OPTION]... PATCH'),
  3263     _(b'hg qgoto [OPTION]... PATCH'),
  3227     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  3264     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  3228 )
  3265 )
  3229 def goto(ui, repo, patch, **opts):
  3266 def goto(ui, repo, patch, **opts):
  3230     '''push or pop patches until named patch is at top of stack
  3267     '''push or pop patches until named patch is at top of stack
  3231 
  3268 
  3232     Returns 0 on success.'''
  3269     Returns 0 on success.'''
  3233     opts = pycompat.byteskwargs(opts)
  3270     opts = pycompat.byteskwargs(opts)
  3234     opts = fixkeepchangesopts(ui, opts)
  3271     opts = fixkeepchangesopts(ui, opts)
  3235     q = repo.mq
  3272     q = repo.mq
  3236     patch = q.lookup(patch)
  3273     patch = q.lookup(patch)
  3237     nobackup = opts.get('no_backup')
  3274     nobackup = opts.get(b'no_backup')
  3238     keepchanges = opts.get('keep_changes')
  3275     keepchanges = opts.get(b'keep_changes')
  3239     if q.isapplied(patch):
  3276     if q.isapplied(patch):
  3240         ret = q.pop(
  3277         ret = q.pop(
  3241             repo,
  3278             repo,
  3242             patch,
  3279             patch,
  3243             force=opts.get('force'),
  3280             force=opts.get(b'force'),
  3244             nobackup=nobackup,
  3281             nobackup=nobackup,
  3245             keepchanges=keepchanges,
  3282             keepchanges=keepchanges,
  3246         )
  3283         )
  3247     else:
  3284     else:
  3248         ret = q.push(
  3285         ret = q.push(
  3249             repo,
  3286             repo,
  3250             patch,
  3287             patch,
  3251             force=opts.get('force'),
  3288             force=opts.get(b'force'),
  3252             nobackup=nobackup,
  3289             nobackup=nobackup,
  3253             keepchanges=keepchanges,
  3290             keepchanges=keepchanges,
  3254         )
  3291         )
  3255     q.savedirty()
  3292     q.savedirty()
  3256     return ret
  3293     return ret
  3257 
  3294 
  3258 
  3295 
  3259 @command(
  3296 @command(
  3260     "qguard",
  3297     b"qguard",
  3261     [
  3298     [
  3262         ('l', 'list', None, _('list all patches and guards')),
  3299         (b'l', b'list', None, _(b'list all patches and guards')),
  3263         ('n', 'none', None, _('drop all guards')),
  3300         (b'n', b'none', None, _(b'drop all guards')),
  3264     ],
  3301     ],
  3265     _('hg qguard [-l] [-n] [PATCH] [-- [+GUARD]... [-GUARD]...]'),
  3302     _(b'hg qguard [-l] [-n] [PATCH] [-- [+GUARD]... [-GUARD]...]'),
  3266     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  3303     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  3267 )
  3304 )
  3268 def guard(ui, repo, *args, **opts):
  3305 def guard(ui, repo, *args, **opts):
  3269     '''set or print guards for a patch
  3306     '''set or print guards for a patch
  3270 
  3307 
  3287 
  3324 
  3288     Returns 0 on success.
  3325     Returns 0 on success.
  3289     '''
  3326     '''
  3290 
  3327 
  3291     def status(idx):
  3328     def status(idx):
  3292         guards = q.seriesguards[idx] or ['unguarded']
  3329         guards = q.seriesguards[idx] or [b'unguarded']
  3293         if q.series[idx] in applied:
  3330         if q.series[idx] in applied:
  3294             state = 'applied'
  3331             state = b'applied'
  3295         elif q.pushable(idx)[0]:
  3332         elif q.pushable(idx)[0]:
  3296             state = 'unapplied'
  3333             state = b'unapplied'
  3297         else:
  3334         else:
  3298             state = 'guarded'
  3335             state = b'guarded'
  3299         label = 'qguard.patch qguard.%s qseries.%s' % (state, state)
  3336         label = b'qguard.patch qguard.%s qseries.%s' % (state, state)
  3300         ui.write('%s: ' % ui.label(q.series[idx], label))
  3337         ui.write(b'%s: ' % ui.label(q.series[idx], label))
  3301 
  3338 
  3302         for i, guard in enumerate(guards):
  3339         for i, guard in enumerate(guards):
  3303             if guard.startswith('+'):
  3340             if guard.startswith(b'+'):
  3304                 ui.write(guard, label='qguard.positive')
  3341                 ui.write(guard, label=b'qguard.positive')
  3305             elif guard.startswith('-'):
  3342             elif guard.startswith(b'-'):
  3306                 ui.write(guard, label='qguard.negative')
  3343                 ui.write(guard, label=b'qguard.negative')
  3307             else:
  3344             else:
  3308                 ui.write(guard, label='qguard.unguarded')
  3345                 ui.write(guard, label=b'qguard.unguarded')
  3309             if i != len(guards) - 1:
  3346             if i != len(guards) - 1:
  3310                 ui.write(' ')
  3347                 ui.write(b' ')
  3311         ui.write('\n')
  3348         ui.write(b'\n')
  3312 
  3349 
  3313     q = repo.mq
  3350     q = repo.mq
  3314     applied = set(p.name for p in q.applied)
  3351     applied = set(p.name for p in q.applied)
  3315     patch = None
  3352     patch = None
  3316     args = list(args)
  3353     args = list(args)
  3317     if opts.get(r'list'):
  3354     if opts.get(r'list'):
  3318         if args or opts.get(r'none'):
  3355         if args or opts.get(r'none'):
  3319             raise error.Abort(
  3356             raise error.Abort(
  3320                 _('cannot mix -l/--list with options or ' 'arguments')
  3357                 _(b'cannot mix -l/--list with options or ' b'arguments')
  3321             )
  3358             )
  3322         for i in pycompat.xrange(len(q.series)):
  3359         for i in pycompat.xrange(len(q.series)):
  3323             status(i)
  3360             status(i)
  3324         return
  3361         return
  3325     if not args or args[0][0:1] in '-+':
  3362     if not args or args[0][0:1] in b'-+':
  3326         if not q.applied:
  3363         if not q.applied:
  3327             raise error.Abort(_('no patches applied'))
  3364             raise error.Abort(_(b'no patches applied'))
  3328         patch = q.applied[-1].name
  3365         patch = q.applied[-1].name
  3329     if patch is None and args[0][0:1] not in '-+':
  3366     if patch is None and args[0][0:1] not in b'-+':
  3330         patch = args.pop(0)
  3367         patch = args.pop(0)
  3331     if patch is None:
  3368     if patch is None:
  3332         raise error.Abort(_('no patch to work with'))
  3369         raise error.Abort(_(b'no patch to work with'))
  3333     if args or opts.get(r'none'):
  3370     if args or opts.get(r'none'):
  3334         idx = q.findseries(patch)
  3371         idx = q.findseries(patch)
  3335         if idx is None:
  3372         if idx is None:
  3336             raise error.Abort(_('no patch named %s') % patch)
  3373             raise error.Abort(_(b'no patch named %s') % patch)
  3337         q.setguards(idx, args)
  3374         q.setguards(idx, args)
  3338         q.savedirty()
  3375         q.savedirty()
  3339     else:
  3376     else:
  3340         status(q.series.index(q.lookup(patch)))
  3377         status(q.series.index(q.lookup(patch)))
  3341 
  3378 
  3342 
  3379 
  3343 @command(
  3380 @command(
  3344     "qheader",
  3381     b"qheader",
  3345     [],
  3382     [],
  3346     _('hg qheader [PATCH]'),
  3383     _(b'hg qheader [PATCH]'),
  3347     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  3384     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  3348 )
  3385 )
  3349 def header(ui, repo, patch=None):
  3386 def header(ui, repo, patch=None):
  3350     """print the header of the topmost or specified patch
  3387     """print the header of the topmost or specified patch
  3351 
  3388 
  3354 
  3391 
  3355     if patch:
  3392     if patch:
  3356         patch = q.lookup(patch)
  3393         patch = q.lookup(patch)
  3357     else:
  3394     else:
  3358         if not q.applied:
  3395         if not q.applied:
  3359             ui.write(_('no patches applied\n'))
  3396             ui.write(_(b'no patches applied\n'))
  3360             return 1
  3397             return 1
  3361         patch = q.lookup('qtip')
  3398         patch = q.lookup(b'qtip')
  3362     ph = patchheader(q.join(patch), q.plainmode)
  3399     ph = patchheader(q.join(patch), q.plainmode)
  3363 
  3400 
  3364     ui.write('\n'.join(ph.message) + '\n')
  3401     ui.write(b'\n'.join(ph.message) + b'\n')
  3365 
  3402 
  3366 
  3403 
  3367 def lastsavename(path):
  3404 def lastsavename(path):
  3368     (directory, base) = os.path.split(path)
  3405     (directory, base) = os.path.split(path)
  3369     names = os.listdir(directory)
  3406     names = os.listdir(directory)
  3370     namere = re.compile("%s.([0-9]+)" % base)
  3407     namere = re.compile(b"%s.([0-9]+)" % base)
  3371     maxindex = None
  3408     maxindex = None
  3372     maxname = None
  3409     maxname = None
  3373     for f in names:
  3410     for f in names:
  3374         m = namere.match(f)
  3411         m = namere.match(f)
  3375         if m:
  3412         if m:
  3384 
  3421 
  3385 def savename(path):
  3422 def savename(path):
  3386     (last, index) = lastsavename(path)
  3423     (last, index) = lastsavename(path)
  3387     if last is None:
  3424     if last is None:
  3388         index = 0
  3425         index = 0
  3389     newpath = path + ".%d" % (index + 1)
  3426     newpath = path + b".%d" % (index + 1)
  3390     return newpath
  3427     return newpath
  3391 
  3428 
  3392 
  3429 
  3393 @command(
  3430 @command(
  3394     "qpush",
  3431     b"qpush",
  3395     [
  3432     [
  3396         ('', 'keep-changes', None, _('tolerate non-conflicting local changes')),
       
  3397         ('f', 'force', None, _('apply on top of local changes')),
       
  3398         (
  3433         (
  3399             'e',
  3434             b'',
  3400             'exact',
  3435             b'keep-changes',
  3401             None,
  3436             None,
  3402             _('apply the target patch to its recorded parent'),
  3437             _(b'tolerate non-conflicting local changes'),
  3403         ),
  3438         ),
  3404         ('l', 'list', None, _('list patch name in commit text')),
  3439         (b'f', b'force', None, _(b'apply on top of local changes')),
  3405         ('a', 'all', None, _('apply all patches')),
  3440         (
  3406         ('m', 'merge', None, _('merge from another queue (DEPRECATED)')),
  3441             b'e',
  3407         ('n', 'name', '', _('merge queue name (DEPRECATED)'), _('NAME')),
  3442             b'exact',
  3408         ('', 'move', None, _('reorder patch series and apply only the patch')),
  3443             None,
  3409         ('', 'no-backup', None, _('do not save backup copies of files')),
  3444             _(b'apply the target patch to its recorded parent'),
       
  3445         ),
       
  3446         (b'l', b'list', None, _(b'list patch name in commit text')),
       
  3447         (b'a', b'all', None, _(b'apply all patches')),
       
  3448         (b'm', b'merge', None, _(b'merge from another queue (DEPRECATED)')),
       
  3449         (b'n', b'name', b'', _(b'merge queue name (DEPRECATED)'), _(b'NAME')),
       
  3450         (
       
  3451             b'',
       
  3452             b'move',
       
  3453             None,
       
  3454             _(b'reorder patch series and apply only the patch'),
       
  3455         ),
       
  3456         (b'', b'no-backup', None, _(b'do not save backup copies of files')),
  3410     ],
  3457     ],
  3411     _('hg qpush [-f] [-l] [-a] [--move] [PATCH | INDEX]'),
  3458     _(b'hg qpush [-f] [-l] [-a] [--move] [PATCH | INDEX]'),
  3412     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  3459     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  3413     helpbasic=True,
  3460     helpbasic=True,
  3414 )
  3461 )
  3415 def push(ui, repo, patch=None, **opts):
  3462 def push(ui, repo, patch=None, **opts):
  3416     """push the next patch onto the stack
  3463     """push the next patch onto the stack
  3425     q = repo.mq
  3472     q = repo.mq
  3426     mergeq = None
  3473     mergeq = None
  3427 
  3474 
  3428     opts = pycompat.byteskwargs(opts)
  3475     opts = pycompat.byteskwargs(opts)
  3429     opts = fixkeepchangesopts(ui, opts)
  3476     opts = fixkeepchangesopts(ui, opts)
  3430     if opts.get('merge'):
  3477     if opts.get(b'merge'):
  3431         if opts.get('name'):
  3478         if opts.get(b'name'):
  3432             newpath = repo.vfs.join(opts.get('name'))
  3479             newpath = repo.vfs.join(opts.get(b'name'))
  3433         else:
  3480         else:
  3434             newpath, i = lastsavename(q.path)
  3481             newpath, i = lastsavename(q.path)
  3435         if not newpath:
  3482         if not newpath:
  3436             ui.warn(_("no saved queues found, please use -n\n"))
  3483             ui.warn(_(b"no saved queues found, please use -n\n"))
  3437             return 1
  3484             return 1
  3438         mergeq = queue(ui, repo.baseui, repo.path, newpath)
  3485         mergeq = queue(ui, repo.baseui, repo.path, newpath)
  3439         ui.warn(_("merging with queue at: %s\n") % mergeq.path)
  3486         ui.warn(_(b"merging with queue at: %s\n") % mergeq.path)
  3440     ret = q.push(
  3487     ret = q.push(
  3441         repo,
  3488         repo,
  3442         patch,
  3489         patch,
  3443         force=opts.get('force'),
  3490         force=opts.get(b'force'),
  3444         list=opts.get('list'),
  3491         list=opts.get(b'list'),
  3445         mergeq=mergeq,
  3492         mergeq=mergeq,
  3446         all=opts.get('all'),
  3493         all=opts.get(b'all'),
  3447         move=opts.get('move'),
  3494         move=opts.get(b'move'),
  3448         exact=opts.get('exact'),
  3495         exact=opts.get(b'exact'),
  3449         nobackup=opts.get('no_backup'),
  3496         nobackup=opts.get(b'no_backup'),
  3450         keepchanges=opts.get('keep_changes'),
  3497         keepchanges=opts.get(b'keep_changes'),
  3451     )
  3498     )
  3452     return ret
  3499     return ret
  3453 
  3500 
  3454 
  3501 
  3455 @command(
  3502 @command(
  3456     "qpop",
  3503     b"qpop",
  3457     [
  3504     [
  3458         ('a', 'all', None, _('pop all patches')),
  3505         (b'a', b'all', None, _(b'pop all patches')),
  3459         ('n', 'name', '', _('queue name to pop (DEPRECATED)'), _('NAME')),
  3506         (b'n', b'name', b'', _(b'queue name to pop (DEPRECATED)'), _(b'NAME')),
  3460         ('', 'keep-changes', None, _('tolerate non-conflicting local changes')),
  3507         (
  3461         ('f', 'force', None, _('forget any local changes to patched files')),
  3508             b'',
  3462         ('', 'no-backup', None, _('do not save backup copies of files')),
  3509             b'keep-changes',
       
  3510             None,
       
  3511             _(b'tolerate non-conflicting local changes'),
       
  3512         ),
       
  3513         (b'f', b'force', None, _(b'forget any local changes to patched files')),
       
  3514         (b'', b'no-backup', None, _(b'do not save backup copies of files')),
  3463     ],
  3515     ],
  3464     _('hg qpop [-a] [-f] [PATCH | INDEX]'),
  3516     _(b'hg qpop [-a] [-f] [PATCH | INDEX]'),
  3465     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  3517     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  3466     helpbasic=True,
  3518     helpbasic=True,
  3467 )
  3519 )
  3468 def pop(ui, repo, patch=None, **opts):
  3520 def pop(ui, repo, patch=None, **opts):
  3469     """pop the current patch off the stack
  3521     """pop the current patch off the stack
  3480     Return 0 on success.
  3532     Return 0 on success.
  3481     """
  3533     """
  3482     opts = pycompat.byteskwargs(opts)
  3534     opts = pycompat.byteskwargs(opts)
  3483     opts = fixkeepchangesopts(ui, opts)
  3535     opts = fixkeepchangesopts(ui, opts)
  3484     localupdate = True
  3536     localupdate = True
  3485     if opts.get('name'):
  3537     if opts.get(b'name'):
  3486         q = queue(ui, repo.baseui, repo.path, repo.vfs.join(opts.get('name')))
  3538         q = queue(ui, repo.baseui, repo.path, repo.vfs.join(opts.get(b'name')))
  3487         ui.warn(_('using patch queue: %s\n') % q.path)
  3539         ui.warn(_(b'using patch queue: %s\n') % q.path)
  3488         localupdate = False
  3540         localupdate = False
  3489     else:
  3541     else:
  3490         q = repo.mq
  3542         q = repo.mq
  3491     ret = q.pop(
  3543     ret = q.pop(
  3492         repo,
  3544         repo,
  3493         patch,
  3545         patch,
  3494         force=opts.get('force'),
  3546         force=opts.get(b'force'),
  3495         update=localupdate,
  3547         update=localupdate,
  3496         all=opts.get('all'),
  3548         all=opts.get(b'all'),
  3497         nobackup=opts.get('no_backup'),
  3549         nobackup=opts.get(b'no_backup'),
  3498         keepchanges=opts.get('keep_changes'),
  3550         keepchanges=opts.get(b'keep_changes'),
  3499     )
  3551     )
  3500     q.savedirty()
  3552     q.savedirty()
  3501     return ret
  3553     return ret
  3502 
  3554 
  3503 
  3555 
  3504 @command(
  3556 @command(
  3505     "qrename|qmv",
  3557     b"qrename|qmv",
  3506     [],
  3558     [],
  3507     _('hg qrename PATCH1 [PATCH2]'),
  3559     _(b'hg qrename PATCH1 [PATCH2]'),
  3508     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  3560     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  3509 )
  3561 )
  3510 def rename(ui, repo, patch, name=None, **opts):
  3562 def rename(ui, repo, patch, name=None, **opts):
  3511     """rename a patch
  3563     """rename a patch
  3512 
  3564 
  3521 
  3573 
  3522     if patch:
  3574     if patch:
  3523         patch = q.lookup(patch)
  3575         patch = q.lookup(patch)
  3524     else:
  3576     else:
  3525         if not q.applied:
  3577         if not q.applied:
  3526             ui.write(_('no patches applied\n'))
  3578             ui.write(_(b'no patches applied\n'))
  3527             return
  3579             return
  3528         patch = q.lookup('qtip')
  3580         patch = q.lookup(b'qtip')
  3529     absdest = q.join(name)
  3581     absdest = q.join(name)
  3530     if os.path.isdir(absdest):
  3582     if os.path.isdir(absdest):
  3531         name = normname(os.path.join(name, os.path.basename(patch)))
  3583         name = normname(os.path.join(name, os.path.basename(patch)))
  3532         absdest = q.join(name)
  3584         absdest = q.join(name)
  3533     q.checkpatchname(name)
  3585     q.checkpatchname(name)
  3534 
  3586 
  3535     ui.note(_('renaming %s to %s\n') % (patch, name))
  3587     ui.note(_(b'renaming %s to %s\n') % (patch, name))
  3536     i = q.findseries(patch)
  3588     i = q.findseries(patch)
  3537     guards = q.guard_re.findall(q.fullseries[i])
  3589     guards = q.guard_re.findall(q.fullseries[i])
  3538     q.fullseries[i] = name + ''.join([' #' + g for g in guards])
  3590     q.fullseries[i] = name + b''.join([b' #' + g for g in guards])
  3539     q.parseseries()
  3591     q.parseseries()
  3540     q.seriesdirty = True
  3592     q.seriesdirty = True
  3541 
  3593 
  3542     info = q.isapplied(patch)
  3594     info = q.isapplied(patch)
  3543     if info:
  3595     if info:
  3550     util.rename(q.join(patch), absdest)
  3602     util.rename(q.join(patch), absdest)
  3551     r = q.qrepo()
  3603     r = q.qrepo()
  3552     if r and patch in r.dirstate:
  3604     if r and patch in r.dirstate:
  3553         wctx = r[None]
  3605         wctx = r[None]
  3554         with r.wlock():
  3606         with r.wlock():
  3555             if r.dirstate[patch] == 'a':
  3607             if r.dirstate[patch] == b'a':
  3556                 r.dirstate.drop(patch)
  3608                 r.dirstate.drop(patch)
  3557                 r.dirstate.add(name)
  3609                 r.dirstate.add(name)
  3558             else:
  3610             else:
  3559                 wctx.copy(patch, name)
  3611                 wctx.copy(patch, name)
  3560                 wctx.forget([patch])
  3612                 wctx.forget([patch])
  3561 
  3613 
  3562     q.savedirty()
  3614     q.savedirty()
  3563 
  3615 
  3564 
  3616 
  3565 @command(
  3617 @command(
  3566     "qrestore",
  3618     b"qrestore",
  3567     [
  3619     [
  3568         ('d', 'delete', None, _('delete save entry')),
  3620         (b'd', b'delete', None, _(b'delete save entry')),
  3569         ('u', 'update', None, _('update queue working directory')),
  3621         (b'u', b'update', None, _(b'update queue working directory')),
  3570     ],
  3622     ],
  3571     _('hg qrestore [-d] [-u] REV'),
  3623     _(b'hg qrestore [-d] [-u] REV'),
  3572     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  3624     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  3573 )
  3625 )
  3574 def restore(ui, repo, rev, **opts):
  3626 def restore(ui, repo, rev, **opts):
  3575     """restore the queue state saved by a revision (DEPRECATED)
  3627     """restore the queue state saved by a revision (DEPRECATED)
  3576 
  3628 
  3583     q.savedirty()
  3635     q.savedirty()
  3584     return 0
  3636     return 0
  3585 
  3637 
  3586 
  3638 
  3587 @command(
  3639 @command(
  3588     "qsave",
  3640     b"qsave",
  3589     [
  3641     [
  3590         ('c', 'copy', None, _('copy patch directory')),
  3642         (b'c', b'copy', None, _(b'copy patch directory')),
  3591         ('n', 'name', '', _('copy directory name'), _('NAME')),
  3643         (b'n', b'name', b'', _(b'copy directory name'), _(b'NAME')),
  3592         ('e', 'empty', None, _('clear queue status file')),
  3644         (b'e', b'empty', None, _(b'clear queue status file')),
  3593         ('f', 'force', None, _('force copy')),
  3645         (b'f', b'force', None, _(b'force copy')),
  3594     ]
  3646     ]
  3595     + cmdutil.commitopts,
  3647     + cmdutil.commitopts,
  3596     _('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'),
  3648     _(b'hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'),
  3597     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  3649     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  3598 )
  3650 )
  3599 def save(ui, repo, **opts):
  3651 def save(ui, repo, **opts):
  3600     """save current queue state (DEPRECATED)
  3652     """save current queue state (DEPRECATED)
  3601 
  3653 
  3605     message = cmdutil.logmessage(ui, opts)
  3657     message = cmdutil.logmessage(ui, opts)
  3606     ret = q.save(repo, msg=message)
  3658     ret = q.save(repo, msg=message)
  3607     if ret:
  3659     if ret:
  3608         return ret
  3660         return ret
  3609     q.savedirty()  # save to .hg/patches before copying
  3661     q.savedirty()  # save to .hg/patches before copying
  3610     if opts.get('copy'):
  3662     if opts.get(b'copy'):
  3611         path = q.path
  3663         path = q.path
  3612         if opts.get('name'):
  3664         if opts.get(b'name'):
  3613             newpath = os.path.join(q.basepath, opts.get('name'))
  3665             newpath = os.path.join(q.basepath, opts.get(b'name'))
  3614             if os.path.exists(newpath):
  3666             if os.path.exists(newpath):
  3615                 if not os.path.isdir(newpath):
  3667                 if not os.path.isdir(newpath):
  3616                     raise error.Abort(
  3668                     raise error.Abort(
  3617                         _('destination %s exists and is not ' 'a directory')
  3669                         _(b'destination %s exists and is not ' b'a directory')
  3618                         % newpath
  3670                         % newpath
  3619                     )
  3671                     )
  3620                 if not opts.get('force'):
  3672                 if not opts.get(b'force'):
  3621                     raise error.Abort(
  3673                     raise error.Abort(
  3622                         _('destination %s exists, ' 'use -f to force') % newpath
  3674                         _(b'destination %s exists, ' b'use -f to force')
       
  3675                         % newpath
  3623                     )
  3676                     )
  3624         else:
  3677         else:
  3625             newpath = savename(path)
  3678             newpath = savename(path)
  3626         ui.warn(_("copy %s to %s\n") % (path, newpath))
  3679         ui.warn(_(b"copy %s to %s\n") % (path, newpath))
  3627         util.copyfiles(path, newpath)
  3680         util.copyfiles(path, newpath)
  3628     if opts.get('empty'):
  3681     if opts.get(b'empty'):
  3629         del q.applied[:]
  3682         del q.applied[:]
  3630         q.applieddirty = True
  3683         q.applieddirty = True
  3631         q.savedirty()
  3684         q.savedirty()
  3632     return 0
  3685     return 0
  3633 
  3686 
  3634 
  3687 
  3635 @command(
  3688 @command(
  3636     "qselect",
  3689     b"qselect",
  3637     [
  3690     [
  3638         ('n', 'none', None, _('disable all guards')),
  3691         (b'n', b'none', None, _(b'disable all guards')),
  3639         ('s', 'series', None, _('list all guards in series file')),
  3692         (b's', b'series', None, _(b'list all guards in series file')),
  3640         ('', 'pop', None, _('pop to before first guarded applied patch')),
  3693         (b'', b'pop', None, _(b'pop to before first guarded applied patch')),
  3641         ('', 'reapply', None, _('pop, then reapply patches')),
  3694         (b'', b'reapply', None, _(b'pop, then reapply patches')),
  3642     ],
  3695     ],
  3643     _('hg qselect [OPTION]... [GUARD]...'),
  3696     _(b'hg qselect [OPTION]... [GUARD]...'),
  3644     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  3697     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  3645 )
  3698 )
  3646 def select(ui, repo, *args, **opts):
  3699 def select(ui, repo, *args, **opts):
  3647     '''set or print guarded patches to push
  3700     '''set or print guarded patches to push
  3648 
  3701 
  3680 
  3733 
  3681     q = repo.mq
  3734     q = repo.mq
  3682     opts = pycompat.byteskwargs(opts)
  3735     opts = pycompat.byteskwargs(opts)
  3683     guards = q.active()
  3736     guards = q.active()
  3684     pushable = lambda i: q.pushable(q.applied[i].name)[0]
  3737     pushable = lambda i: q.pushable(q.applied[i].name)[0]
  3685     if args or opts.get('none'):
  3738     if args or opts.get(b'none'):
  3686         old_unapplied = q.unapplied(repo)
  3739         old_unapplied = q.unapplied(repo)
  3687         old_guarded = [
  3740         old_guarded = [
  3688             i for i in pycompat.xrange(len(q.applied)) if not pushable(i)
  3741             i for i in pycompat.xrange(len(q.applied)) if not pushable(i)
  3689         ]
  3742         ]
  3690         q.setactive(args)
  3743         q.setactive(args)
  3691         q.savedirty()
  3744         q.savedirty()
  3692         if not args:
  3745         if not args:
  3693             ui.status(_('guards deactivated\n'))
  3746             ui.status(_(b'guards deactivated\n'))
  3694         if not opts.get('pop') and not opts.get('reapply'):
  3747         if not opts.get(b'pop') and not opts.get(b'reapply'):
  3695             unapplied = q.unapplied(repo)
  3748             unapplied = q.unapplied(repo)
  3696             guarded = [
  3749             guarded = [
  3697                 i for i in pycompat.xrange(len(q.applied)) if not pushable(i)
  3750                 i for i in pycompat.xrange(len(q.applied)) if not pushable(i)
  3698             ]
  3751             ]
  3699             if len(unapplied) != len(old_unapplied):
  3752             if len(unapplied) != len(old_unapplied):
  3700                 ui.status(
  3753                 ui.status(
  3701                     _(
  3754                     _(
  3702                         'number of unguarded, unapplied patches has '
  3755                         b'number of unguarded, unapplied patches has '
  3703                         'changed from %d to %d\n'
  3756                         b'changed from %d to %d\n'
  3704                     )
  3757                     )
  3705                     % (len(old_unapplied), len(unapplied))
  3758                     % (len(old_unapplied), len(unapplied))
  3706                 )
  3759                 )
  3707             if len(guarded) != len(old_guarded):
  3760             if len(guarded) != len(old_guarded):
  3708                 ui.status(
  3761                 ui.status(
  3709                     _(
  3762                     _(
  3710                         'number of guarded, applied patches has changed '
  3763                         b'number of guarded, applied patches has changed '
  3711                         'from %d to %d\n'
  3764                         b'from %d to %d\n'
  3712                     )
  3765                     )
  3713                     % (len(old_guarded), len(guarded))
  3766                     % (len(old_guarded), len(guarded))
  3714                 )
  3767                 )
  3715     elif opts.get('series'):
  3768     elif opts.get(b'series'):
  3716         guards = {}
  3769         guards = {}
  3717         noguards = 0
  3770         noguards = 0
  3718         for gs in q.seriesguards:
  3771         for gs in q.seriesguards:
  3719             if not gs:
  3772             if not gs:
  3720                 noguards += 1
  3773                 noguards += 1
  3721             for g in gs:
  3774             for g in gs:
  3722                 guards.setdefault(g, 0)
  3775                 guards.setdefault(g, 0)
  3723                 guards[g] += 1
  3776                 guards[g] += 1
  3724         if ui.verbose:
  3777         if ui.verbose:
  3725             guards['NONE'] = noguards
  3778             guards[b'NONE'] = noguards
  3726         guards = list(guards.items())
  3779         guards = list(guards.items())
  3727         guards.sort(key=lambda x: x[0][1:])
  3780         guards.sort(key=lambda x: x[0][1:])
  3728         if guards:
  3781         if guards:
  3729             ui.note(_('guards in series file:\n'))
  3782             ui.note(_(b'guards in series file:\n'))
  3730             for guard, count in guards:
  3783             for guard, count in guards:
  3731                 ui.note('%2d  ' % count)
  3784                 ui.note(b'%2d  ' % count)
  3732                 ui.write(guard, '\n')
  3785                 ui.write(guard, b'\n')
  3733         else:
  3786         else:
  3734             ui.note(_('no guards in series file\n'))
  3787             ui.note(_(b'no guards in series file\n'))
  3735     else:
  3788     else:
  3736         if guards:
  3789         if guards:
  3737             ui.note(_('active guards:\n'))
  3790             ui.note(_(b'active guards:\n'))
  3738             for g in guards:
  3791             for g in guards:
  3739                 ui.write(g, '\n')
  3792                 ui.write(g, b'\n')
  3740         else:
  3793         else:
  3741             ui.write(_('no active guards\n'))
  3794             ui.write(_(b'no active guards\n'))
  3742     reapply = opts.get('reapply') and q.applied and q.applied[-1].name
  3795     reapply = opts.get(b'reapply') and q.applied and q.applied[-1].name
  3743     popped = False
  3796     popped = False
  3744     if opts.get('pop') or opts.get('reapply'):
  3797     if opts.get(b'pop') or opts.get(b'reapply'):
  3745         for i in pycompat.xrange(len(q.applied)):
  3798         for i in pycompat.xrange(len(q.applied)):
  3746             if not pushable(i):
  3799             if not pushable(i):
  3747                 ui.status(_('popping guarded patches\n'))
  3800                 ui.status(_(b'popping guarded patches\n'))
  3748                 popped = True
  3801                 popped = True
  3749                 if i == 0:
  3802                 if i == 0:
  3750                     q.pop(repo, all=True)
  3803                     q.pop(repo, all=True)
  3751                 else:
  3804                 else:
  3752                     q.pop(repo, q.applied[i - 1].name)
  3805                     q.pop(repo, q.applied[i - 1].name)
  3753                 break
  3806                 break
  3754     if popped:
  3807     if popped:
  3755         try:
  3808         try:
  3756             if reapply:
  3809             if reapply:
  3757                 ui.status(_('reapplying unguarded patches\n'))
  3810                 ui.status(_(b'reapplying unguarded patches\n'))
  3758                 q.push(repo, reapply)
  3811                 q.push(repo, reapply)
  3759         finally:
  3812         finally:
  3760             q.savedirty()
  3813             q.savedirty()
  3761 
  3814 
  3762 
  3815 
  3763 @command(
  3816 @command(
  3764     "qfinish",
  3817     b"qfinish",
  3765     [('a', 'applied', None, _('finish all applied changesets'))],
  3818     [(b'a', b'applied', None, _(b'finish all applied changesets'))],
  3766     _('hg qfinish [-a] [REV]...'),
  3819     _(b'hg qfinish [-a] [REV]...'),
  3767     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  3820     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  3768 )
  3821 )
  3769 def finish(ui, repo, *revrange, **opts):
  3822 def finish(ui, repo, *revrange, **opts):
  3770     """move applied patches into repository history
  3823     """move applied patches into repository history
  3771 
  3824 
  3783     to upstream.
  3836     to upstream.
  3784 
  3837 
  3785     Returns 0 on success.
  3838     Returns 0 on success.
  3786     """
  3839     """
  3787     if not opts.get(r'applied') and not revrange:
  3840     if not opts.get(r'applied') and not revrange:
  3788         raise error.Abort(_('no revisions specified'))
  3841         raise error.Abort(_(b'no revisions specified'))
  3789     elif opts.get(r'applied'):
  3842     elif opts.get(r'applied'):
  3790         revrange = ('qbase::qtip',) + revrange
  3843         revrange = (b'qbase::qtip',) + revrange
  3791 
  3844 
  3792     q = repo.mq
  3845     q = repo.mq
  3793     if not q.applied:
  3846     if not q.applied:
  3794         ui.status(_('no patches applied\n'))
  3847         ui.status(_(b'no patches applied\n'))
  3795         return 0
  3848         return 0
  3796 
  3849 
  3797     revs = scmutil.revrange(repo, revrange)
  3850     revs = scmutil.revrange(repo, revrange)
  3798     if repo['.'].rev() in revs and repo[None].files():
  3851     if repo[b'.'].rev() in revs and repo[None].files():
  3799         ui.warn(_('warning: uncommitted changes in the working directory\n'))
  3852         ui.warn(_(b'warning: uncommitted changes in the working directory\n'))
  3800     # queue.finish may changes phases but leave the responsibility to lock the
  3853     # queue.finish may changes phases but leave the responsibility to lock the
  3801     # repo to the caller to avoid deadlock with wlock. This command code is
  3854     # repo to the caller to avoid deadlock with wlock. This command code is
  3802     # responsibility for this locking.
  3855     # responsibility for this locking.
  3803     with repo.lock():
  3856     with repo.lock():
  3804         q.finish(repo, revs)
  3857         q.finish(repo, revs)
  3805         q.savedirty()
  3858         q.savedirty()
  3806     return 0
  3859     return 0
  3807 
  3860 
  3808 
  3861 
  3809 @command(
  3862 @command(
  3810     "qqueue",
  3863     b"qqueue",
  3811     [
  3864     [
  3812         ('l', 'list', False, _('list all available queues')),
  3865         (b'l', b'list', False, _(b'list all available queues')),
  3813         ('', 'active', False, _('print name of active queue')),
  3866         (b'', b'active', False, _(b'print name of active queue')),
  3814         ('c', 'create', False, _('create new queue')),
  3867         (b'c', b'create', False, _(b'create new queue')),
  3815         ('', 'rename', False, _('rename active queue')),
  3868         (b'', b'rename', False, _(b'rename active queue')),
  3816         ('', 'delete', False, _('delete reference to queue')),
  3869         (b'', b'delete', False, _(b'delete reference to queue')),
  3817         ('', 'purge', False, _('delete queue, and remove patch dir')),
  3870         (b'', b'purge', False, _(b'delete queue, and remove patch dir')),
  3818     ],
  3871     ],
  3819     _('[OPTION] [QUEUE]'),
  3872     _(b'[OPTION] [QUEUE]'),
  3820     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  3873     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  3821 )
  3874 )
  3822 def qqueue(ui, repo, name=None, **opts):
  3875 def qqueue(ui, repo, name=None, **opts):
  3823     '''manage multiple patch queues
  3876     '''manage multiple patch queues
  3824 
  3877 
  3839     active queue.
  3892     active queue.
  3840 
  3893 
  3841     Returns 0 on success.
  3894     Returns 0 on success.
  3842     '''
  3895     '''
  3843     q = repo.mq
  3896     q = repo.mq
  3844     _defaultqueue = 'patches'
  3897     _defaultqueue = b'patches'
  3845     _allqueues = 'patches.queues'
  3898     _allqueues = b'patches.queues'
  3846     _activequeue = 'patches.queue'
  3899     _activequeue = b'patches.queue'
  3847 
  3900 
  3848     def _getcurrent():
  3901     def _getcurrent():
  3849         cur = os.path.basename(q.path)
  3902         cur = os.path.basename(q.path)
  3850         if cur.startswith('patches-'):
  3903         if cur.startswith(b'patches-'):
  3851             cur = cur[8:]
  3904             cur = cur[8:]
  3852         return cur
  3905         return cur
  3853 
  3906 
  3854     def _noqueues():
  3907     def _noqueues():
  3855         try:
  3908         try:
  3856             fh = repo.vfs(_allqueues, 'r')
  3909             fh = repo.vfs(_allqueues, b'r')
  3857             fh.close()
  3910             fh.close()
  3858         except IOError:
  3911         except IOError:
  3859             return True
  3912             return True
  3860 
  3913 
  3861         return False
  3914         return False
  3862 
  3915 
  3863     def _getqueues():
  3916     def _getqueues():
  3864         current = _getcurrent()
  3917         current = _getcurrent()
  3865 
  3918 
  3866         try:
  3919         try:
  3867             fh = repo.vfs(_allqueues, 'r')
  3920             fh = repo.vfs(_allqueues, b'r')
  3868             queues = [queue.strip() for queue in fh if queue.strip()]
  3921             queues = [queue.strip() for queue in fh if queue.strip()]
  3869             fh.close()
  3922             fh.close()
  3870             if current not in queues:
  3923             if current not in queues:
  3871                 queues.append(current)
  3924                 queues.append(current)
  3872         except IOError:
  3925         except IOError:
  3876 
  3929 
  3877     def _setactive(name):
  3930     def _setactive(name):
  3878         if q.applied:
  3931         if q.applied:
  3879             raise error.Abort(
  3932             raise error.Abort(
  3880                 _(
  3933                 _(
  3881                     'new queue created, but cannot make active '
  3934                     b'new queue created, but cannot make active '
  3882                     'as patches are applied'
  3935                     b'as patches are applied'
  3883                 )
  3936                 )
  3884             )
  3937             )
  3885         _setactivenocheck(name)
  3938         _setactivenocheck(name)
  3886 
  3939 
  3887     def _setactivenocheck(name):
  3940     def _setactivenocheck(name):
  3888         fh = repo.vfs(_activequeue, 'w')
  3941         fh = repo.vfs(_activequeue, b'w')
  3889         if name != 'patches':
  3942         if name != b'patches':
  3890             fh.write(name)
  3943             fh.write(name)
  3891         fh.close()
  3944         fh.close()
  3892 
  3945 
  3893     def _addqueue(name):
  3946     def _addqueue(name):
  3894         fh = repo.vfs(_allqueues, 'a')
  3947         fh = repo.vfs(_allqueues, b'a')
  3895         fh.write('%s\n' % (name,))
  3948         fh.write(b'%s\n' % (name,))
  3896         fh.close()
  3949         fh.close()
  3897 
  3950 
  3898     def _queuedir(name):
  3951     def _queuedir(name):
  3899         if name == 'patches':
  3952         if name == b'patches':
  3900             return repo.vfs.join('patches')
  3953             return repo.vfs.join(b'patches')
  3901         else:
  3954         else:
  3902             return repo.vfs.join('patches-' + name)
  3955             return repo.vfs.join(b'patches-' + name)
  3903 
  3956 
  3904     def _validname(name):
  3957     def _validname(name):
  3905         for n in name:
  3958         for n in name:
  3906             if n in ':\\/.':
  3959             if n in b':\\/.':
  3907                 return False
  3960                 return False
  3908         return True
  3961         return True
  3909 
  3962 
  3910     def _delete(name):
  3963     def _delete(name):
  3911         if name not in existing:
  3964         if name not in existing:
  3912             raise error.Abort(_('cannot delete queue that does not exist'))
  3965             raise error.Abort(_(b'cannot delete queue that does not exist'))
  3913 
  3966 
  3914         current = _getcurrent()
  3967         current = _getcurrent()
  3915 
  3968 
  3916         if name == current:
  3969         if name == current:
  3917             raise error.Abort(_('cannot delete currently active queue'))
  3970             raise error.Abort(_(b'cannot delete currently active queue'))
  3918 
  3971 
  3919         fh = repo.vfs('patches.queues.new', 'w')
  3972         fh = repo.vfs(b'patches.queues.new', b'w')
  3920         for queue in existing:
  3973         for queue in existing:
  3921             if queue == name:
  3974             if queue == name:
  3922                 continue
  3975                 continue
  3923             fh.write('%s\n' % (queue,))
  3976             fh.write(b'%s\n' % (queue,))
  3924         fh.close()
  3977         fh.close()
  3925         repo.vfs.rename('patches.queues.new', _allqueues)
  3978         repo.vfs.rename(b'patches.queues.new', _allqueues)
  3926 
  3979 
  3927     opts = pycompat.byteskwargs(opts)
  3980     opts = pycompat.byteskwargs(opts)
  3928     if not name or opts.get('list') or opts.get('active'):
  3981     if not name or opts.get(b'list') or opts.get(b'active'):
  3929         current = _getcurrent()
  3982         current = _getcurrent()
  3930         if opts.get('active'):
  3983         if opts.get(b'active'):
  3931             ui.write('%s\n' % (current,))
  3984             ui.write(b'%s\n' % (current,))
  3932             return
  3985             return
  3933         for queue in _getqueues():
  3986         for queue in _getqueues():
  3934             ui.write('%s' % (queue,))
  3987             ui.write(b'%s' % (queue,))
  3935             if queue == current and not ui.quiet:
  3988             if queue == current and not ui.quiet:
  3936                 ui.write(_(' (active)\n'))
  3989                 ui.write(_(b' (active)\n'))
  3937             else:
  3990             else:
  3938                 ui.write('\n')
  3991                 ui.write(b'\n')
  3939         return
  3992         return
  3940 
  3993 
  3941     if not _validname(name):
  3994     if not _validname(name):
  3942         raise error.Abort(
  3995         raise error.Abort(
  3943             _('invalid queue name, may not contain the characters ":\\/."')
  3996             _(b'invalid queue name, may not contain the characters ":\\/."')
  3944         )
  3997         )
  3945 
  3998 
  3946     with repo.wlock():
  3999     with repo.wlock():
  3947         existing = _getqueues()
  4000         existing = _getqueues()
  3948 
  4001 
  3949         if opts.get('create'):
  4002         if opts.get(b'create'):
  3950             if name in existing:
  4003             if name in existing:
  3951                 raise error.Abort(_('queue "%s" already exists') % name)
  4004                 raise error.Abort(_(b'queue "%s" already exists') % name)
  3952             if _noqueues():
  4005             if _noqueues():
  3953                 _addqueue(_defaultqueue)
  4006                 _addqueue(_defaultqueue)
  3954             _addqueue(name)
  4007             _addqueue(name)
  3955             _setactive(name)
  4008             _setactive(name)
  3956         elif opts.get('rename'):
  4009         elif opts.get(b'rename'):
  3957             current = _getcurrent()
  4010             current = _getcurrent()
  3958             if name == current:
  4011             if name == current:
  3959                 raise error.Abort(
  4012                 raise error.Abort(
  3960                     _('can\'t rename "%s" to its current name') % name
  4013                     _(b'can\'t rename "%s" to its current name') % name
  3961                 )
  4014                 )
  3962             if name in existing:
  4015             if name in existing:
  3963                 raise error.Abort(_('queue "%s" already exists') % name)
  4016                 raise error.Abort(_(b'queue "%s" already exists') % name)
  3964 
  4017 
  3965             olddir = _queuedir(current)
  4018             olddir = _queuedir(current)
  3966             newdir = _queuedir(name)
  4019             newdir = _queuedir(name)
  3967 
  4020 
  3968             if os.path.exists(newdir):
  4021             if os.path.exists(newdir):
  3969                 raise error.Abort(
  4022                 raise error.Abort(
  3970                     _('non-queue directory "%s" already exists') % newdir
  4023                     _(b'non-queue directory "%s" already exists') % newdir
  3971                 )
  4024                 )
  3972 
  4025 
  3973             fh = repo.vfs('patches.queues.new', 'w')
  4026             fh = repo.vfs(b'patches.queues.new', b'w')
  3974             for queue in existing:
  4027             for queue in existing:
  3975                 if queue == current:
  4028                 if queue == current:
  3976                     fh.write('%s\n' % (name,))
  4029                     fh.write(b'%s\n' % (name,))
  3977                     if os.path.exists(olddir):
  4030                     if os.path.exists(olddir):
  3978                         util.rename(olddir, newdir)
  4031                         util.rename(olddir, newdir)
  3979                 else:
  4032                 else:
  3980                     fh.write('%s\n' % (queue,))
  4033                     fh.write(b'%s\n' % (queue,))
  3981             fh.close()
  4034             fh.close()
  3982             repo.vfs.rename('patches.queues.new', _allqueues)
  4035             repo.vfs.rename(b'patches.queues.new', _allqueues)
  3983             _setactivenocheck(name)
  4036             _setactivenocheck(name)
  3984         elif opts.get('delete'):
  4037         elif opts.get(b'delete'):
  3985             _delete(name)
  4038             _delete(name)
  3986         elif opts.get('purge'):
  4039         elif opts.get(b'purge'):
  3987             if name in existing:
  4040             if name in existing:
  3988                 _delete(name)
  4041                 _delete(name)
  3989             qdir = _queuedir(name)
  4042             qdir = _queuedir(name)
  3990             if os.path.exists(qdir):
  4043             if os.path.exists(qdir):
  3991                 shutil.rmtree(qdir)
  4044                 shutil.rmtree(qdir)
  3992         else:
  4045         else:
  3993             if name not in existing:
  4046             if name not in existing:
  3994                 raise error.Abort(_('use --create to create a new queue'))
  4047                 raise error.Abort(_(b'use --create to create a new queue'))
  3995             _setactive(name)
  4048             _setactive(name)
  3996 
  4049 
  3997 
  4050 
  3998 def mqphasedefaults(repo, roots):
  4051 def mqphasedefaults(repo, roots):
  3999     """callback used to set mq changeset as secret when no phase data exists"""
  4052     """callback used to set mq changeset as secret when no phase data exists"""
  4000     if repo.mq.applied:
  4053     if repo.mq.applied:
  4001         if repo.ui.configbool('mq', 'secret'):
  4054         if repo.ui.configbool(b'mq', b'secret'):
  4002             mqphase = phases.secret
  4055             mqphase = phases.secret
  4003         else:
  4056         else:
  4004             mqphase = phases.draft
  4057             mqphase = phases.draft
  4005         qbase = repo[repo.mq.applied[0].node]
  4058         qbase = repo[repo.mq.applied[0].node]
  4006         roots[mqphase].add(qbase.node())
  4059         roots[mqphase].add(qbase.node())
  4026                 if any(p in patches for p in parents):
  4079                 if any(p in patches for p in parents):
  4027                     raise error.Abort(errmsg)
  4080                     raise error.Abort(errmsg)
  4028 
  4081 
  4029         def commit(
  4082         def commit(
  4030             self,
  4083             self,
  4031             text="",
  4084             text=b"",
  4032             user=None,
  4085             user=None,
  4033             date=None,
  4086             date=None,
  4034             match=None,
  4087             match=None,
  4035             force=False,
  4088             force=False,
  4036             editor=False,
  4089             editor=False,
  4037             extra=None,
  4090             extra=None,
  4038         ):
  4091         ):
  4039             if extra is None:
  4092             if extra is None:
  4040                 extra = {}
  4093                 extra = {}
  4041             self.abortifwdirpatched(
  4094             self.abortifwdirpatched(
  4042                 _('cannot commit over an applied mq patch'), force
  4095                 _(b'cannot commit over an applied mq patch'), force
  4043             )
  4096             )
  4044 
  4097 
  4045             return super(mqrepo, self).commit(
  4098             return super(mqrepo, self).commit(
  4046                 text, user, date, match, force, editor, extra
  4099                 text, user, date, match, force, editor, extra
  4047             )
  4100             )
  4060                         else:
  4113                         else:
  4061                             outapplied.pop()
  4114                             outapplied.pop()
  4062                 # looking for pushed and shared changeset
  4115                 # looking for pushed and shared changeset
  4063                 for node in outapplied:
  4116                 for node in outapplied:
  4064                     if self[node].phase() < phases.secret:
  4117                     if self[node].phase() < phases.secret:
  4065                         raise error.Abort(_('source has mq patches applied'))
  4118                         raise error.Abort(_(b'source has mq patches applied'))
  4066                 # no non-secret patches pushed
  4119                 # no non-secret patches pushed
  4067             super(mqrepo, self).checkpush(pushop)
  4120             super(mqrepo, self).checkpush(pushop)
  4068 
  4121 
  4069         def _findtags(self):
  4122         def _findtags(self):
  4070             '''augment tags from base class with patch tags'''
  4123             '''augment tags from base class with patch tags'''
  4079             try:
  4132             try:
  4080                 # for now ignore filtering business
  4133                 # for now ignore filtering business
  4081                 self.unfiltered().changelog.rev(mqtags[-1][0])
  4134                 self.unfiltered().changelog.rev(mqtags[-1][0])
  4082             except error.LookupError:
  4135             except error.LookupError:
  4083                 self.ui.warn(
  4136                 self.ui.warn(
  4084                     _('mq status file refers to unknown node %s\n')
  4137                     _(b'mq status file refers to unknown node %s\n')
  4085                     % short(mqtags[-1][0])
  4138                     % short(mqtags[-1][0])
  4086                 )
  4139                 )
  4087                 return result
  4140                 return result
  4088 
  4141 
  4089             # do not add fake tags for filtered revisions
  4142             # do not add fake tags for filtered revisions
  4090             included = self.changelog.hasnode
  4143             included = self.changelog.hasnode
  4091             mqtags = [mqt for mqt in mqtags if included(mqt[0])]
  4144             mqtags = [mqt for mqt in mqtags if included(mqt[0])]
  4092             if not mqtags:
  4145             if not mqtags:
  4093                 return result
  4146                 return result
  4094 
  4147 
  4095             mqtags.append((mqtags[-1][0], 'qtip'))
  4148             mqtags.append((mqtags[-1][0], b'qtip'))
  4096             mqtags.append((mqtags[0][0], 'qbase'))
  4149             mqtags.append((mqtags[0][0], b'qbase'))
  4097             mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
  4150             mqtags.append((self.changelog.parents(mqtags[0][0])[0], b'qparent'))
  4098             tags = result[0]
  4151             tags = result[0]
  4099             for patch in mqtags:
  4152             for patch in mqtags:
  4100                 if patch[1] in tags:
  4153                 if patch[1] in tags:
  4101                     self.ui.warn(
  4154                     self.ui.warn(
  4102                         _('tag %s overrides mq patch of the same ' 'name\n')
  4155                         _(b'tag %s overrides mq patch of the same ' b'name\n')
  4103                         % patch[1]
  4156                         % patch[1]
  4104                     )
  4157                     )
  4105                 else:
  4158                 else:
  4106                     tags[patch[1]] = patch[0]
  4159                     tags[patch[1]] = patch[0]
  4107 
  4160 
  4112 
  4165 
  4113         repo._phasedefaults.append(mqphasedefaults)
  4166         repo._phasedefaults.append(mqphasedefaults)
  4114 
  4167 
  4115 
  4168 
  4116 def mqimport(orig, ui, repo, *args, **kwargs):
  4169 def mqimport(orig, ui, repo, *args, **kwargs):
  4117     if util.safehasattr(repo, 'abortifwdirpatched') and not kwargs.get(
  4170     if util.safehasattr(repo, b'abortifwdirpatched') and not kwargs.get(
  4118         r'no_commit', False
  4171         r'no_commit', False
  4119     ):
  4172     ):
  4120         repo.abortifwdirpatched(
  4173         repo.abortifwdirpatched(
  4121             _('cannot import over an applied patch'), kwargs.get(r'force')
  4174             _(b'cannot import over an applied patch'), kwargs.get(r'force')
  4122         )
  4175         )
  4123     return orig(ui, repo, *args, **kwargs)
  4176     return orig(ui, repo, *args, **kwargs)
  4124 
  4177 
  4125 
  4178 
  4126 def mqinit(orig, ui, *args, **kwargs):
  4179 def mqinit(orig, ui, *args, **kwargs):
  4131 
  4184 
  4132     if args:
  4185     if args:
  4133         repopath = args[0]
  4186         repopath = args[0]
  4134         if not hg.islocal(repopath):
  4187         if not hg.islocal(repopath):
  4135             raise error.Abort(
  4188             raise error.Abort(
  4136                 _('only a local queue repository ' 'may be initialized')
  4189                 _(b'only a local queue repository ' b'may be initialized')
  4137             )
  4190             )
  4138     else:
  4191     else:
  4139         repopath = cmdutil.findrepo(encoding.getcwd())
  4192         repopath = cmdutil.findrepo(encoding.getcwd())
  4140         if not repopath:
  4193         if not repopath:
  4141             raise error.Abort(
  4194             raise error.Abort(
  4142                 _('there is no Mercurial repository here ' '(.hg not found)')
  4195                 _(b'there is no Mercurial repository here ' b'(.hg not found)')
  4143             )
  4196             )
  4144     repo = hg.repository(ui, repopath)
  4197     repo = hg.repository(ui, repopath)
  4145     return qinit(ui, repo, True)
  4198     return qinit(ui, repo, True)
  4146 
  4199 
  4147 
  4200 
  4155         return orig(ui, repo, *args, **kwargs)
  4208         return orig(ui, repo, *args, **kwargs)
  4156 
  4209 
  4157     q = repo.mq
  4210     q = repo.mq
  4158     r = q.qrepo()
  4211     r = q.qrepo()
  4159     if not r:
  4212     if not r:
  4160         raise error.Abort(_('no queue repository'))
  4213         raise error.Abort(_(b'no queue repository'))
  4161     return orig(r.ui, r, *args, **kwargs)
  4214     return orig(r.ui, r, *args, **kwargs)
  4162 
  4215 
  4163 
  4216 
  4164 def summaryhook(ui, repo):
  4217 def summaryhook(ui, repo):
  4165     q = repo.mq
  4218     q = repo.mq
  4166     m = []
  4219     m = []
  4167     a, u = len(q.applied), len(q.unapplied(repo))
  4220     a, u = len(q.applied), len(q.unapplied(repo))
  4168     if a:
  4221     if a:
  4169         m.append(ui.label(_("%d applied"), 'qseries.applied') % a)
  4222         m.append(ui.label(_(b"%d applied"), b'qseries.applied') % a)
  4170     if u:
  4223     if u:
  4171         m.append(ui.label(_("%d unapplied"), 'qseries.unapplied') % u)
  4224         m.append(ui.label(_(b"%d unapplied"), b'qseries.unapplied') % u)
  4172     if m:
  4225     if m:
  4173         # i18n: column positioning for "hg summary"
  4226         # i18n: column positioning for "hg summary"
  4174         ui.write(_("mq:     %s\n") % ', '.join(m))
  4227         ui.write(_(b"mq:     %s\n") % b', '.join(m))
  4175     else:
  4228     else:
  4176         # i18n: column positioning for "hg summary"
  4229         # i18n: column positioning for "hg summary"
  4177         ui.note(_("mq:     (empty queue)\n"))
  4230         ui.note(_(b"mq:     (empty queue)\n"))
  4178 
  4231 
  4179 
  4232 
  4180 revsetpredicate = registrar.revsetpredicate()
  4233 revsetpredicate = registrar.revsetpredicate()
  4181 
  4234 
  4182 
  4235 
  4183 @revsetpredicate('mq()')
  4236 @revsetpredicate(b'mq()')
  4184 def revsetmq(repo, subset, x):
  4237 def revsetmq(repo, subset, x):
  4185     """Changesets managed by MQ.
  4238     """Changesets managed by MQ.
  4186     """
  4239     """
  4187     revsetlang.getargs(x, 0, 0, _("mq takes no arguments"))
  4240     revsetlang.getargs(x, 0, 0, _(b"mq takes no arguments"))
  4188     applied = {repo[r.node].rev() for r in repo.mq.applied}
  4241     applied = {repo[r.node].rev() for r in repo.mq.applied}
  4189     return smartset.baseset([r for r in subset if r in applied])
  4242     return smartset.baseset([r for r in subset if r in applied])
  4190 
  4243 
  4191 
  4244 
  4192 # tell hggettext to extract docstrings from these functions:
  4245 # tell hggettext to extract docstrings from these functions:
  4194 
  4247 
  4195 
  4248 
  4196 def extsetup(ui):
  4249 def extsetup(ui):
  4197     # Ensure mq wrappers are called first, regardless of extension load order by
  4250     # Ensure mq wrappers are called first, regardless of extension load order by
  4198     # NOT wrapping in uisetup() and instead deferring to init stage two here.
  4251     # NOT wrapping in uisetup() and instead deferring to init stage two here.
  4199     mqopt = [('', 'mq', None, _("operate on patch repository"))]
  4252     mqopt = [(b'', b'mq', None, _(b"operate on patch repository"))]
  4200 
  4253 
  4201     extensions.wrapcommand(commands.table, 'import', mqimport)
  4254     extensions.wrapcommand(commands.table, b'import', mqimport)
  4202     cmdutil.summaryhooks.add('mq', summaryhook)
  4255     cmdutil.summaryhooks.add(b'mq', summaryhook)
  4203 
  4256 
  4204     entry = extensions.wrapcommand(commands.table, 'init', mqinit)
  4257     entry = extensions.wrapcommand(commands.table, b'init', mqinit)
  4205     entry[1].extend(mqopt)
  4258     entry[1].extend(mqopt)
  4206 
  4259 
  4207     def dotable(cmdtable):
  4260     def dotable(cmdtable):
  4208         for cmd, entry in cmdtable.iteritems():
  4261         for cmd, entry in cmdtable.iteritems():
  4209             cmd = cmdutil.parsealiases(cmd)[0]
  4262             cmd = cmdutil.parsealiases(cmd)[0]
  4219         if extmodule.__file__ != __file__:
  4272         if extmodule.__file__ != __file__:
  4220             dotable(getattr(extmodule, 'cmdtable', {}))
  4273             dotable(getattr(extmodule, 'cmdtable', {}))
  4221 
  4274 
  4222 
  4275 
  4223 colortable = {
  4276 colortable = {
  4224     'qguard.negative': 'red',
  4277     b'qguard.negative': b'red',
  4225     'qguard.positive': 'yellow',
  4278     b'qguard.positive': b'yellow',
  4226     'qguard.unguarded': 'green',
  4279     b'qguard.unguarded': b'green',
  4227     'qseries.applied': 'blue bold underline',
  4280     b'qseries.applied': b'blue bold underline',
  4228     'qseries.guarded': 'black bold',
  4281     b'qseries.guarded': b'black bold',
  4229     'qseries.missing': 'red bold',
  4282     b'qseries.missing': b'red bold',
  4230     'qseries.unapplied': 'black bold',
  4283     b'qseries.unapplied': b'black bold',
  4231 }
  4284 }