hgext/mq.py
changeset 43076 2372284d9457
parent 42597 51e52a495214
child 43077 687b865b95ad
equal deleted inserted replaced
43075:57875cf423c9 43076:2372284d9457
   115 testedwith = 'ships-with-hg-core'
   115 testedwith = 'ships-with-hg-core'
   116 
   116 
   117 configtable = {}
   117 configtable = {}
   118 configitem = registrar.configitem(configtable)
   118 configitem = registrar.configitem(configtable)
   119 
   119 
   120 configitem('mq', 'git',
   120 configitem(
   121     default='auto',
   121     'mq', 'git', default='auto',
   122 )
   122 )
   123 configitem('mq', 'keepchanges',
   123 configitem(
   124     default=False,
   124     'mq', 'keepchanges', default=False,
   125 )
   125 )
   126 configitem('mq', 'plain',
   126 configitem(
   127     default=False,
   127     'mq', 'plain', default=False,
   128 )
   128 )
   129 configitem('mq', 'secret',
   129 configitem(
   130     default=False,
   130     'mq', '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('strip')
   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         def log(self, event, msgfmt, *msgargs, **opts):
   143         def log(self, event, msgfmt, *msgargs, **opts):
   143             pass
   144             pass
       
   145 
   144     stripext = extensions.load(dummyui(), 'strip', '')
   146     stripext = extensions.load(dummyui(), 'strip', '')
   145 
   147 
   146 strip = stripext.strip
   148 strip = stripext.strip
       
   149 
   147 
   150 
   148 def checksubstate(repo, baserev=None):
   151 def checksubstate(repo, baserev=None):
   149     '''return list of subrepos at a different revision than substate.
   152     '''return list of subrepos at a different revision than substate.
   150     Abort if any subrepos have uncommitted changes.'''
   153     Abort if any subrepos have uncommitted changes.'''
   151     inclsubs = []
   154     inclsubs = []
   158         wctx.sub(s).bailifchanged(True)
   161         wctx.sub(s).bailifchanged(True)
   159         if s not in bctx.substate or bctx.sub(s).dirty():
   162         if s not in bctx.substate or bctx.sub(s).dirty():
   160             inclsubs.append(s)
   163             inclsubs.append(s)
   161     return inclsubs
   164     return inclsubs
   162 
   165 
       
   166 
   163 # Patch names looks like unix-file names.
   167 # Patch names looks like unix-file names.
   164 # They must be joinable with queue directory and result in the patch path.
   168 # They must be joinable with queue directory and result in the patch path.
   165 normname = util.normpath
   169 normname = util.normpath
   166 
   170 
       
   171 
   167 class statusentry(object):
   172 class statusentry(object):
   168     def __init__(self, node, name):
   173     def __init__(self, node, name):
   169         self.node, self.name = node, name
   174         self.node, self.name = node, name
   170 
   175 
   171     def __bytes__(self):
   176     def __bytes__(self):
   172         return hex(self.node) + ':' + self.name
   177         return hex(self.node) + ':' + self.name
   173 
   178 
   174     __str__ = encoding.strmethod(__bytes__)
   179     __str__ = encoding.strmethod(__bytes__)
   175     __repr__ = encoding.strmethod(__bytes__)
   180     __repr__ = encoding.strmethod(__bytes__)
   176 
   181 
       
   182 
   177 # The order of the headers in 'hg export' HG patches:
   183 # The order of the headers in 'hg export' HG patches:
   178 HGHEADERS = [
   184 HGHEADERS = [
   179 #   '# HG changeset patch',
   185     #   '# HG changeset patch',
   180     '# User ',
   186     '# User ',
   181     '# Date ',
   187     '# Date ',
   182     '#      ',
   188     '#      ',
   183     '# Branch ',
   189     '# Branch ',
   184     '# Node ID ',
   190     '# Node ID ',
   185     '# Parent  ', # can occur twice for merges - but that is not relevant for mq
   191     '# Parent  ',  # can occur twice for merges - but that is not relevant for mq
   186     ]
   192 ]
   187 # The order of headers in plain 'mail style' patches:
   193 # The order of headers in plain 'mail style' patches:
   188 PLAINHEADERS = {
   194 PLAINHEADERS = {
   189     'from': 0,
   195     'from': 0,
   190     'date': 1,
   196     'date': 1,
   191     'subject': 2,
   197     'subject': 2,
   192     }
   198 }
       
   199 
   193 
   200 
   194 def inserthgheader(lines, header, value):
   201 def inserthgheader(lines, header, value):
   195     """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.
   196     >>> try: inserthgheader([], b'# Date ', b'z')
   203     >>> try: inserthgheader([], b'# Date ', b'z')
   197     ... except ValueError as inst: print("oops")
   204     ... except ValueError as inst: print("oops")
   227                 if lineindex == newindex:
   234                 if lineindex == newindex:
   228                     lines[i] = header + value
   235                     lines[i] = header + value
   229                     return lines
   236                     return lines
   230                 if lineindex > newindex:
   237                 if lineindex > newindex:
   231                     bestpos = min(bestpos, i)
   238                     bestpos = min(bestpos, i)
   232                 break # next line
   239                 break  # next line
   233     lines.insert(bestpos, header + value)
   240     lines.insert(bestpos, header + value)
   234     return lines
   241     return lines
       
   242 
   235 
   243 
   236 def insertplainheader(lines, header, value):
   244 def insertplainheader(lines, header, value):
   237     """For lines containing a plain patch header, add a header line with value.
   245     """For lines containing a plain patch header, add a header line with value.
   238     >>> insertplainheader([], b'Date', b'z')
   246     >>> insertplainheader([], b'Date', b'z')
   239     ['Date: z']
   247     ['Date: z']
   268                 bestpos = i
   276                 bestpos = i
   269             break
   277             break
   270     lines.insert(bestpos, '%s: %s' % (header, value))
   278     lines.insert(bestpos, '%s: %s' % (header, value))
   271     return lines
   279     return lines
   272 
   280 
       
   281 
   273 class patchheader(object):
   282 class patchheader(object):
   274     def __init__(self, pf, plainmode=False):
   283     def __init__(self, pf, plainmode=False):
   275         def eatdiff(lines):
   284         def eatdiff(lines):
   276             while lines:
   285             while lines:
   277                 l = lines[-1]
   286                 l = lines[-1]
   278                 if (l.startswith("diff -") or
   287                 if (
   279                     l.startswith("Index:") or
   288                     l.startswith("diff -")
   280                     l.startswith("===========")):
   289                     or l.startswith("Index:")
       
   290                     or l.startswith("===========")
       
   291                 ):
   281                     del lines[-1]
   292                     del lines[-1]
   282                 else:
   293                 else:
   283                     break
   294                     break
       
   295 
   284         def eatempty(lines):
   296         def eatempty(lines):
   285             while lines:
   297             while lines:
   286                 if not lines[-1].strip():
   298                 if not lines[-1].strip():
   287                     del lines[-1]
   299                     del lines[-1]
   288                 else:
   300                 else:
   299         nodeid = None
   311         nodeid = None
   300         diffstart = 0
   312         diffstart = 0
   301 
   313 
   302         for line in open(pf, 'rb'):
   314         for line in open(pf, 'rb'):
   303             line = line.rstrip()
   315             line = line.rstrip()
   304             if (line.startswith('diff --git')
   316             if line.startswith('diff --git') or (
   305                 or (diffstart and line.startswith('+++ '))):
   317                 diffstart and line.startswith('+++ ')
       
   318             ):
   306                 diffstart = 2
   319                 diffstart = 2
   307                 break
   320                 break
   308             diffstart = 0 # reset
   321             diffstart = 0  # reset
   309             if line.startswith("--- "):
   322             if line.startswith("--- "):
   310                 diffstart = 1
   323                 diffstart = 1
   311                 continue
   324                 continue
   312             elif format == "hgpatch":
   325             elif format == "hgpatch":
   313                 # parse values when importing the result of an hg export
   326                 # parse values when importing the result of an hg export
   314                 if line.startswith("# User "):
   327                 if line.startswith("# User "):
   315                     user = line[7:]
   328                     user = line[7:]
   316                 elif line.startswith("# Date "):
   329                 elif line.startswith("# Date "):
   317                     date = line[7:]
   330                     date = line[7:]
   318                 elif line.startswith("# Parent "):
   331                 elif line.startswith("# Parent "):
   319                     parent = line[9:].lstrip() # handle double trailing space
   332                     parent = line[9:].lstrip()  # handle double trailing space
   320                 elif line.startswith("# Branch "):
   333                 elif line.startswith("# Branch "):
   321                     branch = line[9:]
   334                     branch = line[9:]
   322                 elif line.startswith("# Node ID "):
   335                 elif line.startswith("# Node ID "):
   323                     nodeid = line[10:]
   336                     nodeid = line[10:]
   324                 elif not line.startswith("# ") and line:
   337                 elif not line.startswith("# ") and line:
   325                     message.append(line)
   338                     message.append(line)
   326                     format = None
   339                     format = None
   327             elif line == '# HG changeset patch':
   340             elif line == '# HG changeset patch':
   328                 message = []
   341                 message = []
   329                 format = "hgpatch"
   342                 format = "hgpatch"
   330             elif (format != "tagdone" and (line.startswith("Subject: ") or
   343             elif format != "tagdone" and (
   331                                            line.startswith("subject: "))):
   344                 line.startswith("Subject: ") or line.startswith("subject: ")
       
   345             ):
   332                 subject = line[9:]
   346                 subject = line[9:]
   333                 format = "tag"
   347                 format = "tag"
   334             elif (format != "tagdone" and (line.startswith("From: ") or
   348             elif format != "tagdone" and (
   335                                            line.startswith("from: "))):
   349                 line.startswith("From: ") or line.startswith("from: ")
       
   350             ):
   336                 user = line[6:]
   351                 user = line[6:]
   337                 format = "tag"
   352                 format = "tag"
   338             elif (format != "tagdone" and (line.startswith("Date: ") or
   353             elif format != "tagdone" and (
   339                                            line.startswith("date: "))):
   354                 line.startswith("Date: ") or line.startswith("date: ")
       
   355             ):
   340                 date = line[6:]
   356                 date = line[6:]
   341                 format = "tag"
   357                 format = "tag"
   342             elif format == "tag" and line == "":
   358             elif format == "tag" and line == "":
   343                 # when looking for tags (subject: from: etc) they
   359                 # when looking for tags (subject: from: etc) they
   344                 # end once you find a blank line in the source
   360                 # end once you find a blank line in the source
   366         self.parent = parent
   382         self.parent = parent
   367         # nodeid and branch are for external use by TortoiseHg and others
   383         # nodeid and branch are for external use by TortoiseHg and others
   368         self.nodeid = nodeid
   384         self.nodeid = nodeid
   369         self.branch = branch
   385         self.branch = branch
   370         self.haspatch = diffstart > 1
   386         self.haspatch = diffstart > 1
   371         self.plainmode = (plainmode or
   387         self.plainmode = (
   372                           '# HG changeset patch' not in self.comments and
   388             plainmode
   373                           any(c.startswith('Date: ') or
   389             or '# HG changeset patch' not in self.comments
   374                                    c.startswith('From: ')
   390             and any(
   375                                    for c in self.comments))
   391                 c.startswith('Date: ') or c.startswith('From: ')
       
   392                 for c in self.comments
       
   393             )
       
   394         )
   376 
   395 
   377     def setuser(self, user):
   396     def setuser(self, user):
   378         try:
   397         try:
   379             inserthgheader(self.comments, '# User ', user)
   398             inserthgheader(self.comments, '# User ', user)
   380         except ValueError:
   399         except ValueError:
   437         for mi in self.message:
   456         for mi in self.message:
   438             while mi != self.comments[ci]:
   457             while mi != self.comments[ci]:
   439                 ci += 1
   458                 ci += 1
   440             del self.comments[ci]
   459             del self.comments[ci]
   441 
   460 
       
   461 
   442 def newcommit(repo, phase, *args, **kwargs):
   462 def newcommit(repo, phase, *args, **kwargs):
   443     """helper dedicated to ensure a commit respect mq.secret setting
   463     """helper dedicated to ensure a commit respect mq.secret setting
   444 
   464 
   445     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
   446     creating new changeset.
   466     creating new changeset.
   454         overrides[('phases', 'new-commit')] = phase
   474         overrides[('phases', 'new-commit')] = phase
   455     with repo.ui.configoverride(overrides, 'mq'):
   475     with repo.ui.configoverride(overrides, 'mq'):
   456         repo.ui.setconfig('ui', 'allowemptycommit', True)
   476         repo.ui.setconfig('ui', 'allowemptycommit', True)
   457         return repo.commit(*args, **kwargs)
   477         return repo.commit(*args, **kwargs)
   458 
   478 
       
   479 
   459 class AbortNoCleanup(error.Abort):
   480 class AbortNoCleanup(error.Abort):
   460     pass
   481     pass
       
   482 
   461 
   483 
   462 class queue(object):
   484 class queue(object):
   463     def __init__(self, ui, baseui, path, patchdir=None):
   485     def __init__(self, ui, baseui, path, patchdir=None):
   464         self.basepath = path
   486         self.basepath = path
   465         try:
   487         try:
   504                 entry = l.split(':', 1)
   526                 entry = l.split(':', 1)
   505                 if len(entry) > 1:
   527                 if len(entry) > 1:
   506                     n, name = entry
   528                     n, name = entry
   507                     yield statusentry(bin(n), name)
   529                     yield statusentry(bin(n), name)
   508                 elif l.strip():
   530                 elif l.strip():
   509                     self.ui.warn(_('malformated mq status line: %s\n') %
   531                     self.ui.warn(
   510                                  stringutil.pprint(entry))
   532                         _('malformated mq status line: %s\n')
       
   533                         % stringutil.pprint(entry)
       
   534                     )
   511                 # else we ignore empty lines
   535                 # else we ignore empty lines
       
   536 
   512         try:
   537         try:
   513             lines = self.opener.read(self.statuspath).splitlines()
   538             lines = self.opener.read(self.statuspath).splitlines()
   514             return list(parselines(lines))
   539             return list(parselines(lines))
   515         except IOError as e:
   540         except IOError as e:
   516             if e.errno == errno.ENOENT:
   541             if e.errno == errno.ENOENT:
   546         self.activeguards = None
   571         self.activeguards = None
   547 
   572 
   548     def diffopts(self, opts=None, patchfn=None, plain=False):
   573     def diffopts(self, opts=None, patchfn=None, plain=False):
   549         """Return diff options tweaked for this mq use, possibly upgrading to
   574         """Return diff options tweaked for this mq use, possibly upgrading to
   550         git format, and possibly plain and without lossy options."""
   575         git format, and possibly plain and without lossy options."""
   551         diffopts = patchmod.difffeatureopts(self.ui, opts,
   576         diffopts = patchmod.difffeatureopts(
   552             git=True, whitespace=not plain, formatchanging=not plain)
   577             self.ui,
       
   578             opts,
       
   579             git=True,
       
   580             whitespace=not plain,
       
   581             formatchanging=not plain,
       
   582         )
   553         if self.gitmode == 'auto':
   583         if self.gitmode == 'auto':
   554             diffopts.upgrade = True
   584             diffopts.upgrade = True
   555         elif self.gitmode == 'keep':
   585         elif self.gitmode == 'keep':
   556             pass
   586             pass
   557         elif self.gitmode in ('yes', 'no'):
   587         elif self.gitmode in ('yes', 'no'):
   558             diffopts.git = self.gitmode == 'yes'
   588             diffopts.git = self.gitmode == 'yes'
   559         else:
   589         else:
   560             raise error.Abort(_('mq.git option can be auto/keep/yes/no'
   590             raise error.Abort(
   561                                ' got %s') % self.gitmode)
   591                 _('mq.git option can be auto/keep/yes/no' ' got %s')
       
   592                 % self.gitmode
       
   593             )
   562         if patchfn:
   594         if patchfn:
   563             diffopts = self.patchopts(diffopts, patchfn)
   595             diffopts = self.patchopts(diffopts, patchfn)
   564         return diffopts
   596         return diffopts
   565 
   597 
   566     def patchopts(self, diffopts, *patches):
   598     def patchopts(self, diffopts, *patches):
   570         diffopts = diffopts.copy()
   602         diffopts = diffopts.copy()
   571         if not diffopts.git and self.gitmode == 'keep':
   603         if not diffopts.git and self.gitmode == 'keep':
   572             for patchfn in patches:
   604             for patchfn in patches:
   573                 patchf = self.opener(patchfn, 'r')
   605                 patchf = self.opener(patchfn, 'r')
   574                 # 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
   575                 diffopts.git = any(line.startswith('diff --git')
   607                 diffopts.git = any(
   576                                    for line in patchf)
   608                     line.startswith('diff --git') for line in patchf
       
   609                 )
   577                 patchf.close()
   610                 patchf.close()
   578         return diffopts
   611         return diffopts
   579 
   612 
   580     def join(self, *p):
   613     def join(self, *p):
   581         return os.path.join(self.path, *p)
   614         return os.path.join(self.path, *p)
   582 
   615 
   583     def findseries(self, patch):
   616     def findseries(self, patch):
   584         def matchpatch(l):
   617         def matchpatch(l):
   585             l = l.split('#', 1)[0]
   618             l = l.split('#', 1)[0]
   586             return l.strip() == patch
   619             return l.strip() == patch
       
   620 
   587         for index, l in enumerate(self.fullseries):
   621         for index, l in enumerate(self.fullseries):
   588             if matchpatch(l):
   622             if matchpatch(l):
   589                 return index
   623                 return index
   590         return None
   624         return None
   591 
   625 
   605                 patch = l[:h]
   639                 patch = l[:h]
   606                 comment = l[h:]
   640                 comment = l[h:]
   607             patch = patch.strip()
   641             patch = patch.strip()
   608             if patch:
   642             if patch:
   609                 if patch in self.series:
   643                 if patch in self.series:
   610                     raise error.Abort(_('%s appears more than once in %s') %
   644                     raise error.Abort(
   611                                      (patch, self.join(self.seriespath)))
   645                         _('%s appears more than once in %s')
       
   646                         % (patch, self.join(self.seriespath))
       
   647                     )
   612                 self.series.append(patch)
   648                 self.series.append(patch)
   613                 self.seriesguards.append(self.guard_re.findall(comment))
   649                 self.seriesguards.append(self.guard_re.findall(comment))
   614 
   650 
   615     def checkguard(self, guard):
   651     def checkguard(self, guard):
   616         if not guard:
   652         if not guard:
   617             return _('guard cannot be an empty string')
   653             return _('guard cannot be an empty string')
   618         bad_chars = '# \t\r\n\f'
   654         bad_chars = '# \t\r\n\f'
   619         first = guard[0]
   655         first = guard[0]
   620         if first in '-+':
   656         if first in '-+':
   621             return (_('guard %r starts with invalid character: %r') %
   657             return _('guard %r starts with invalid character: %r') % (
   622                       (guard, first))
   658                 guard,
       
   659                 first,
       
   660             )
   623         for c in bad_chars:
   661         for c in bad_chars:
   624             if c in guard:
   662             if c in guard:
   625                 return _('invalid character in guard %r: %r') % (guard, c)
   663                 return _('invalid character in guard %r: %r') % (guard, c)
   626 
   664 
   627     def setactive(self, guards):
   665     def setactive(self, guards):
   644                     raise
   682                     raise
   645                 guards = []
   683                 guards = []
   646             for i, guard in enumerate(guards):
   684             for i, guard in enumerate(guards):
   647                 bad = self.checkguard(guard)
   685                 bad = self.checkguard(guard)
   648                 if bad:
   686                 if bad:
   649                     self.ui.warn('%s:%d: %s\n' %
   687                     self.ui.warn(
   650                                  (self.join(self.guardspath), i + 1, bad))
   688                         '%s:%d: %s\n' % (self.join(self.guardspath), i + 1, bad)
       
   689                     )
   651                 else:
   690                 else:
   652                     self.activeguards.append(guard)
   691                     self.activeguards.append(guard)
   653         return self.activeguards
   692         return self.activeguards
   654 
   693 
   655     def setguards(self, idx, guards):
   694     def setguards(self, idx, guards):
   671             idx = self.series.index(idx)
   710             idx = self.series.index(idx)
   672         patchguards = self.seriesguards[idx]
   711         patchguards = self.seriesguards[idx]
   673         if not patchguards:
   712         if not patchguards:
   674             return True, None
   713             return True, None
   675         guards = self.active()
   714         guards = self.active()
   676         exactneg = [g for g in patchguards
   715         exactneg = [
   677                     if g.startswith('-') and g[1:] in guards]
   716             g for g in patchguards if g.startswith('-') and g[1:] in guards
       
   717         ]
   678         if exactneg:
   718         if exactneg:
   679             return False, stringutil.pprint(exactneg[0])
   719             return False, stringutil.pprint(exactneg[0])
   680         pos = [g for g in patchguards if g.startswith('+')]
   720         pos = [g for g in patchguards if g.startswith('+')]
   681         exactpos = [g for g in pos if g[1:] in guards]
   721         exactpos = [g for g in pos if g[1:] in guards]
   682         if pos:
   722         if pos:
   695             if isinstance(idx, bytes):
   735             if isinstance(idx, bytes):
   696                 idx = self.series.index(idx)
   736                 idx = self.series.index(idx)
   697             pushable, why = self.pushable(idx)
   737             pushable, why = self.pushable(idx)
   698             if all_patches and pushable:
   738             if all_patches and pushable:
   699                 if why is None:
   739                 if why is None:
   700                     write(_('allowing %s - no guards in effect\n') %
   740                     write(
   701                           self.series[idx])
   741                         _('allowing %s - no guards in effect\n')
       
   742                         % self.series[idx]
       
   743                     )
   702                 else:
   744                 else:
   703                     if not why:
   745                     if not why:
   704                         write(_('allowing %s - no matching negative guards\n') %
   746                         write(
   705                               self.series[idx])
   747                             _('allowing %s - no matching negative guards\n')
       
   748                             % self.series[idx]
       
   749                         )
   706                     else:
   750                     else:
   707                         write(_('allowing %s - guarded by %s\n') %
   751                         write(
   708                               (self.series[idx], why))
   752                             _('allowing %s - guarded by %s\n')
       
   753                             % (self.series[idx], why)
       
   754                         )
   709             if not pushable:
   755             if not pushable:
   710                 if why:
   756                 if why:
   711                     write(_('skipping %s - guarded by %s\n') %
   757                     write(
   712                           (self.series[idx], why))
   758                         _('skipping %s - guarded by %s\n')
       
   759                         % (self.series[idx], why)
       
   760                     )
   713                 else:
   761                 else:
   714                     write(_('skipping %s - no matching guards\n') %
   762                     write(
   715                           self.series[idx])
   763                         _('skipping %s - no matching guards\n')
       
   764                         % self.series[idx]
       
   765                     )
   716 
   766 
   717     def savedirty(self):
   767     def savedirty(self):
   718         def writelist(items, path):
   768         def writelist(items, path):
   719             fp = self.opener(path, 'wb')
   769             fp = self.opener(path, 'wb')
   720             for i in items:
   770             for i in items:
   721                 fp.write("%s\n" % i)
   771                 fp.write("%s\n" % i)
   722             fp.close()
   772             fp.close()
       
   773 
   723         if self.applieddirty:
   774         if self.applieddirty:
   724             writelist(map(bytes, self.applied), self.statuspath)
   775             writelist(map(bytes, self.applied), self.statuspath)
   725             self.applieddirty = False
   776             self.applieddirty = False
   726         if self.seriesdirty:
   777         if self.seriesdirty:
   727             writelist(self.fullseries, self.seriespath)
   778             writelist(self.fullseries, self.seriespath)
   740         if not os.path.exists(undo):
   791         if not os.path.exists(undo):
   741             return
   792             return
   742         try:
   793         try:
   743             os.unlink(undo)
   794             os.unlink(undo)
   744         except OSError as inst:
   795         except OSError as inst:
   745             self.ui.warn(_('error removing undo: %s\n') %
   796             self.ui.warn(
   746                          stringutil.forcebytestr(inst))
   797                 _('error removing undo: %s\n') % stringutil.forcebytestr(inst)
       
   798             )
   747 
   799 
   748     def backup(self, repo, files, copy=False):
   800     def backup(self, repo, files, copy=False):
   749         # backup local changes in --force case
   801         # backup local changes in --force case
   750         for f in sorted(files):
   802         for f in sorted(files):
   751             absf = repo.wjoin(f)
   803             absf = repo.wjoin(f)
   752             if os.path.lexists(absf):
   804             if os.path.lexists(absf):
   753                 absorig = scmutil.backuppath(self.ui, repo, f)
   805                 absorig = scmutil.backuppath(self.ui, repo, f)
   754                 self.ui.note(_('saving current version of %s as %s\n') %
   806                 self.ui.note(
   755                              (f, os.path.relpath(absorig)))
   807                     _('saving current version of %s as %s\n')
       
   808                     % (f, os.path.relpath(absorig))
       
   809                 )
   756 
   810 
   757                 if copy:
   811                 if copy:
   758                     util.copyfile(absf, absorig)
   812                     util.copyfile(absf, absorig)
   759                 else:
   813                 else:
   760                     util.rename(absf, absorig)
   814                     util.rename(absf, absorig)
   761 
   815 
   762     def printdiff(self, repo, diffopts, node1, node2=None, files=None,
   816     def printdiff(
   763                   fp=None, changes=None, opts=None):
   817         self,
       
   818         repo,
       
   819         diffopts,
       
   820         node1,
       
   821         node2=None,
       
   822         files=None,
       
   823         fp=None,
       
   824         changes=None,
       
   825         opts=None,
       
   826     ):
   764         if opts is None:
   827         if opts is None:
   765             opts = {}
   828             opts = {}
   766         stat = opts.get('stat')
   829         stat = opts.get('stat')
   767         m = scmutil.match(repo[node1], files, opts)
   830         m = scmutil.match(repo[node1], files, opts)
   768         logcmdutil.diffordiffstat(self.ui, repo, diffopts, node1, node2, m,
   831         logcmdutil.diffordiffstat(
   769                                   changes, stat, fp)
   832             self.ui, repo, diffopts, node1, node2, m, changes, stat, fp
       
   833         )
   770 
   834 
   771     def mergeone(self, repo, mergeq, head, patch, rev, diffopts):
   835     def mergeone(self, repo, mergeq, head, patch, rev, diffopts):
   772         # first try just applying the patch
   836         # first try just applying the patch
   773         (err, n) = self.apply(repo, [patch], update_status=False,
   837         (err, n) = self.apply(
   774                               strict=True, merge=rev)
   838             repo, [patch], update_status=False, strict=True, merge=rev
       
   839         )
   775 
   840 
   776         if err == 0:
   841         if err == 0:
   777             return (err, n)
   842             return (err, n)
   778 
   843 
   779         if n is None:
   844         if n is None:
   870     def patch(self, repo, patchfile):
   935     def patch(self, repo, patchfile):
   871         '''Apply patchfile  to the working directory.
   936         '''Apply patchfile  to the working directory.
   872         patchfile: name of patch file'''
   937         patchfile: name of patch file'''
   873         files = set()
   938         files = set()
   874         try:
   939         try:
   875             fuzz = patchmod.patch(self.ui, repo, patchfile, strip=1,
   940             fuzz = patchmod.patch(
   876                                   files=files, eolmode=None)
   941                 self.ui, repo, patchfile, strip=1, files=files, eolmode=None
       
   942             )
   877             return (True, list(files), fuzz)
   943             return (True, list(files), fuzz)
   878         except Exception as inst:
   944         except Exception as inst:
   879             self.ui.note(stringutil.forcebytestr(inst) + '\n')
   945             self.ui.note(stringutil.forcebytestr(inst) + '\n')
   880             if not self.ui.verbose:
   946             if not self.ui.verbose:
   881                 self.ui.warn(_("patch failed, unable to continue (try -v)\n"))
   947                 self.ui.warn(_("patch failed, unable to continue (try -v)\n"))
   882             self.ui.traceback()
   948             self.ui.traceback()
   883             return (False, list(files), False)
   949             return (False, list(files), False)
   884 
   950 
   885     def apply(self, repo, series, list=False, update_status=True,
   951     def apply(
   886               strict=False, patchdir=None, merge=None, all_files=None,
   952         self,
   887               tobackup=None, keepchanges=False):
   953         repo,
       
   954         series,
       
   955         list=False,
       
   956         update_status=True,
       
   957         strict=False,
       
   958         patchdir=None,
       
   959         merge=None,
       
   960         all_files=None,
       
   961         tobackup=None,
       
   962         keepchanges=False,
       
   963     ):
   888         wlock = lock = tr = None
   964         wlock = lock = tr = None
   889         try:
   965         try:
   890             wlock = repo.wlock()
   966             wlock = repo.wlock()
   891             lock = repo.lock()
   967             lock = repo.lock()
   892             tr = repo.transaction("qpush")
   968             tr = repo.transaction("qpush")
   893             try:
   969             try:
   894                 ret = self._apply(repo, series, list, update_status,
   970                 ret = self._apply(
   895                                   strict, patchdir, merge, all_files=all_files,
   971                     repo,
   896                                   tobackup=tobackup, keepchanges=keepchanges)
   972                     series,
       
   973                     list,
       
   974                     update_status,
       
   975                     strict,
       
   976                     patchdir,
       
   977                     merge,
       
   978                     all_files=all_files,
       
   979                     tobackup=tobackup,
       
   980                     keepchanges=keepchanges,
       
   981                 )
   897                 tr.close()
   982                 tr.close()
   898                 self.savedirty()
   983                 self.savedirty()
   899                 return ret
   984                 return ret
   900             except AbortNoCleanup:
   985             except AbortNoCleanup:
   901                 tr.close()
   986                 tr.close()
   902                 self.savedirty()
   987                 self.savedirty()
   903                 raise
   988                 raise
   904             except: # re-raises
   989             except:  # re-raises
   905                 try:
   990                 try:
   906                     tr.abort()
   991                     tr.abort()
   907                 finally:
   992                 finally:
   908                     self.invalidate()
   993                     self.invalidate()
   909                 raise
   994                 raise
   910         finally:
   995         finally:
   911             release(tr, lock, wlock)
   996             release(tr, lock, wlock)
   912             self.removeundo(repo)
   997             self.removeundo(repo)
   913 
   998 
   914     def _apply(self, repo, series, list=False, update_status=True,
   999     def _apply(
   915                strict=False, patchdir=None, merge=None, all_files=None,
  1000         self,
   916                tobackup=None, keepchanges=False):
  1001         repo,
       
  1002         series,
       
  1003         list=False,
       
  1004         update_status=True,
       
  1005         strict=False,
       
  1006         patchdir=None,
       
  1007         merge=None,
       
  1008         all_files=None,
       
  1009         tobackup=None,
       
  1010         keepchanges=False,
       
  1011     ):
   917         """returns (error, hash)
  1012         """returns (error, hash)
   918 
  1013 
   919         error = 1 for unable to read, 2 for patch failed, 3 for patch
  1014         error = 1 for unable to read, 2 for patch failed, 3 for patch
   920         fuzz. tobackup is None or a set of files to backup before they
  1015         fuzz. tobackup is None or a set of files to backup before they
   921         are modified by a patch.
  1016         are modified by a patch.
   955                     touched = patchmod.changedfiles(self.ui, repo, pf)
  1050                     touched = patchmod.changedfiles(self.ui, repo, pf)
   956                     touched = set(touched) & tobackup
  1051                     touched = set(touched) & tobackup
   957                     if touched and keepchanges:
  1052                     if touched and keepchanges:
   958                         raise AbortNoCleanup(
  1053                         raise AbortNoCleanup(
   959                             _("conflicting local changes found"),
  1054                             _("conflicting local changes found"),
   960                             hint=_("did you forget to qrefresh?"))
  1055                             hint=_("did you forget to qrefresh?"),
       
  1056                         )
   961                     self.backup(repo, touched, copy=True)
  1057                     self.backup(repo, touched, copy=True)
   962                     tobackup = tobackup - touched
  1058                     tobackup = tobackup - touched
   963                 (patcherr, files, fuzz) = self.patch(repo, pf)
  1059                 (patcherr, files, fuzz) = self.patch(repo, pf)
   964                 if all_files is not None:
  1060                 if all_files is not None:
   965                     all_files.update(files)
  1061                     all_files.update(files)
   987 
  1083 
   988             if all_files and '.hgsubstate' in all_files:
  1084             if all_files and '.hgsubstate' in all_files:
   989                 wctx = repo[None]
  1085                 wctx = repo[None]
   990                 pctx = repo['.']
  1086                 pctx = repo['.']
   991                 overwrite = False
  1087                 overwrite = False
   992                 mergedsubstate = subrepoutil.submerge(repo, pctx, wctx, wctx,
  1088                 mergedsubstate = subrepoutil.submerge(
   993                                                       overwrite)
  1089                     repo, pctx, wctx, wctx, overwrite
       
  1090                 )
   994                 files += mergedsubstate.keys()
  1091                 files += mergedsubstate.keys()
   995 
  1092 
   996             match = scmutil.matchfiles(repo, files or [])
  1093             match = scmutil.matchfiles(repo, files or [])
   997             oldtip = repo.changelog.tip()
  1094             oldtip = repo.changelog.tip()
   998             n = newcommit(repo, None, message, ph.user, ph.date, match=match,
  1095             n = newcommit(
   999                           force=True)
  1096                 repo, None, message, ph.user, ph.date, match=match, force=True
       
  1097             )
  1000             if repo.changelog.tip() == oldtip:
  1098             if repo.changelog.tip() == oldtip:
  1001                 raise error.Abort(_("qpush exactly duplicates child changeset"))
  1099                 raise error.Abort(_("qpush exactly duplicates child changeset"))
  1002             if n is None:
  1100             if n is None:
  1003                 raise error.Abort(_("repository commit failed"))
  1101                 raise error.Abort(_("repository commit failed"))
  1004 
  1102 
  1005             if update_status:
  1103             if update_status:
  1006                 self.applied.append(statusentry(n, patchname))
  1104                 self.applied.append(statusentry(n, patchname))
  1007 
  1105 
  1008             if patcherr:
  1106             if patcherr:
  1009                 self.ui.warn(_("patch failed, rejects left in working "
  1107                 self.ui.warn(
  1010                                "directory\n"))
  1108                     _("patch failed, rejects left in working " "directory\n")
       
  1109                 )
  1011                 err = 2
  1110                 err = 2
  1012                 break
  1111                 break
  1013 
  1112 
  1014             if fuzz and strict:
  1113             if fuzz and strict:
  1015                 self.ui.warn(_("fuzz found when applying patch, stopping\n"))
  1114                 self.ui.warn(_("fuzz found when applying patch, stopping\n"))
  1052             else:
  1151             else:
  1053                 unknown.append(p)
  1152                 unknown.append(p)
  1054 
  1153 
  1055         if unknown:
  1154         if unknown:
  1056             if numrevs:
  1155             if numrevs:
  1057                 rev  = dict((entry.name, entry.node) for entry in qfinished)
  1156                 rev = dict((entry.name, entry.node) for entry in qfinished)
  1058                 for p in unknown:
  1157                 for p in unknown:
  1059                     msg = _('revision %s refers to unknown patches: %s\n')
  1158                     msg = _('revision %s refers to unknown patches: %s\n')
  1060                     self.ui.warn(msg % (short(rev[p]), p))
  1159                     self.ui.warn(msg % (short(rev[p]), p))
  1061             else:
  1160             else:
  1062                 msg = _('unknown patches: %s\n')
  1161                 msg = _('unknown patches: %s\n')
  1104                 with repo.transaction('qfinish') as tr:
  1203                 with repo.transaction('qfinish') as tr:
  1105                     phases.advanceboundary(repo, tr, tphase, qfinished)
  1204                     phases.advanceboundary(repo, tr, tphase, qfinished)
  1106 
  1205 
  1107     def delete(self, repo, patches, opts):
  1206     def delete(self, repo, patches, opts):
  1108         if not patches and not opts.get('rev'):
  1207         if not patches and not opts.get('rev'):
  1109             raise error.Abort(_('qdelete requires at least one revision or '
  1208             raise error.Abort(
  1110                                'patch name'))
  1209                 _('qdelete requires at least one revision or ' 'patch name')
       
  1210             )
  1111 
  1211 
  1112         realpatches = []
  1212         realpatches = []
  1113         for patch in patches:
  1213         for patch in patches:
  1114             patch = self.lookup(patch, strict=True)
  1214             patch = self.lookup(patch, strict=True)
  1115             info = self.isapplied(patch)
  1215             info = self.isapplied(patch)
  1143         return None, None
  1243         return None, None
  1144 
  1244 
  1145     def putsubstate2changes(self, substatestate, changes):
  1245     def putsubstate2changes(self, substatestate, changes):
  1146         for files in changes[:3]:
  1246         for files in changes[:3]:
  1147             if '.hgsubstate' in files:
  1247             if '.hgsubstate' in files:
  1148                 return # already listed up
  1248                 return  # already listed up
  1149         # not yet listed up
  1249         # not yet listed up
  1150         if substatestate in 'a?':
  1250         if substatestate in 'a?':
  1151             changes[1].append('.hgsubstate')
  1251             changes[1].append('.hgsubstate')
  1152         elif substatestate in 'r':
  1252         elif substatestate in 'r':
  1153             changes[2].append('.hgsubstate')
  1253             changes[2].append('.hgsubstate')
  1154         else: # modified
  1254         else:  # modified
  1155             changes[0].append('.hgsubstate')
  1255             changes[0].append('.hgsubstate')
  1156 
  1256 
  1157     def checklocalchanges(self, repo, force=False, refresh=True):
  1257     def checklocalchanges(self, repo, force=False, refresh=True):
  1158         excsuffix = ''
  1258         excsuffix = ''
  1159         if refresh:
  1259         if refresh:
  1164 
  1264 
  1165         s = repo.status()
  1265         s = repo.status()
  1166         if not force:
  1266         if not force:
  1167             cmdutil.checkunfinished(repo)
  1267             cmdutil.checkunfinished(repo)
  1168             if s.modified or s.added or s.removed or s.deleted:
  1268             if s.modified or s.added or s.removed or s.deleted:
  1169                 _("local changes found") # i18n tool detection
  1269                 _("local changes found")  # i18n tool detection
  1170                 raise error.Abort(_("local changes found" + excsuffix))
  1270                 raise error.Abort(_("local changes found" + excsuffix))
  1171             if checksubstate(repo):
  1271             if checksubstate(repo):
  1172                 _("local changed subrepos found") # i18n tool detection
  1272                 _("local changed subrepos found")  # i18n tool detection
  1173                 raise error.Abort(_("local changed subrepos found" + excsuffix))
  1273                 raise error.Abort(_("local changed subrepos found" + excsuffix))
  1174         else:
  1274         else:
  1175             cmdutil.checkunfinished(repo, skipmerge=True)
  1275             cmdutil.checkunfinished(repo, skipmerge=True)
  1176         return s
  1276         return s
  1177 
  1277 
  1178     _reserved = ('series', 'status', 'guards', '.', '..')
  1278     _reserved = ('series', 'status', 'guards', '.', '..')
       
  1279 
  1179     def checkreservedname(self, name):
  1280     def checkreservedname(self, name):
  1180         if name in self._reserved:
  1281         if name in self._reserved:
  1181             raise error.Abort(_('"%s" cannot be used as the name of a patch')
  1282             raise error.Abort(
  1182                              % name)
  1283                 _('"%s" cannot be used as the name of a patch') % name
       
  1284             )
  1183         if name != name.strip():
  1285         if name != name.strip():
  1184             # whitespace is stripped by parseseries()
  1286             # whitespace is stripped by parseseries()
  1185             raise error.Abort(_('patch name cannot begin or end with '
  1287             raise error.Abort(
  1186                                 'whitespace'))
  1288                 _('patch name cannot begin or end with ' 'whitespace')
       
  1289             )
  1187         for prefix in ('.hg', '.mq'):
  1290         for prefix in ('.hg', '.mq'):
  1188             if name.startswith(prefix):
  1291             if name.startswith(prefix):
  1189                 raise error.Abort(_('patch name cannot begin with "%s"')
  1292                 raise error.Abort(
  1190                                  % prefix)
  1293                     _('patch name cannot begin with "%s"') % prefix
       
  1294                 )
  1191         for c in ('#', ':', '\r', '\n'):
  1295         for c in ('#', ':', '\r', '\n'):
  1192             if c in name:
  1296             if c in name:
  1193                 raise error.Abort(_('%r cannot be used in the name of a patch')
  1297                 raise error.Abort(
  1194                                  % pycompat.bytestr(c))
  1298                     _('%r cannot be used in the name of a patch')
       
  1299                     % pycompat.bytestr(c)
       
  1300                 )
  1195 
  1301 
  1196     def checkpatchname(self, name, force=False):
  1302     def checkpatchname(self, name, force=False):
  1197         self.checkreservedname(name)
  1303         self.checkreservedname(name)
  1198         if not force and os.path.exists(self.join(name)):
  1304         if not force and os.path.exists(self.join(name)):
  1199             if os.path.isdir(self.join(name)):
  1305             if os.path.isdir(self.join(name)):
  1200                 raise error.Abort(_('"%s" already exists as a directory')
  1306                 raise error.Abort(
  1201                                  % name)
  1307                     _('"%s" already exists as a directory') % name
       
  1308                 )
  1202             else:
  1309             else:
  1203                 raise error.Abort(_('patch "%s" already exists') % name)
  1310                 raise error.Abort(_('patch "%s" already exists') % name)
  1204 
  1311 
  1205     def makepatchname(self, title, fallbackname):
  1312     def makepatchname(self, title, fallbackname):
  1206         """Return a suitable filename for title, adding a suffix to make
  1313         """Return a suitable filename for title, adding a suffix to make
  1207         it unique in the existing list"""
  1314         it unique in the existing list"""
  1208         namebase = re.sub(br'[\s\W_]+', b'_', title.lower()).strip(b'_')
  1315         namebase = re.sub(br'[\s\W_]+', b'_', title.lower()).strip(b'_')
  1209         namebase = namebase[:75] # avoid too long name (issue5117)
  1316         namebase = namebase[:75]  # avoid too long name (issue5117)
  1210         if namebase:
  1317         if namebase:
  1211             try:
  1318             try:
  1212                 self.checkreservedname(namebase)
  1319                 self.checkreservedname(namebase)
  1213             except error.Abort:
  1320             except error.Abort:
  1214                 namebase = fallbackname
  1321                 namebase = fallbackname
  1250         if inclsubs:
  1357         if inclsubs:
  1251             substatestate = repo.dirstate['.hgsubstate']
  1358             substatestate = repo.dirstate['.hgsubstate']
  1252         if opts.get('include') or opts.get('exclude') or pats:
  1359         if opts.get('include') or opts.get('exclude') or pats:
  1253             # detect missing files in pats
  1360             # detect missing files in pats
  1254             def badfn(f, msg):
  1361             def badfn(f, msg):
  1255                 if f != '.hgsubstate': # .hgsubstate is auto-created
  1362                 if f != '.hgsubstate':  # .hgsubstate is auto-created
  1256                     raise error.Abort('%s: %s' % (f, msg))
  1363                     raise error.Abort('%s: %s' % (f, msg))
       
  1364 
  1257             match = scmutil.match(repo[None], pats, opts, badfn=badfn)
  1365             match = scmutil.match(repo[None], pats, opts, badfn=badfn)
  1258             changes = repo.status(match=match)
  1366             changes = repo.status(match=match)
  1259         else:
  1367         else:
  1260             changes = self.checklocalchanges(repo, force=True)
  1368             changes = self.checklocalchanges(repo, force=True)
  1261         commitfiles = list(inclsubs)
  1369         commitfiles = list(inclsubs)
  1269         with repo.wlock():
  1377         with repo.wlock():
  1270             try:
  1378             try:
  1271                 # if patch file write fails, abort early
  1379                 # if patch file write fails, abort early
  1272                 p = self.opener(patchfn, "w")
  1380                 p = self.opener(patchfn, "w")
  1273             except IOError as e:
  1381             except IOError as e:
  1274                 raise error.Abort(_('cannot write patch "%s": %s')
  1382                 raise error.Abort(
  1275                                  % (patchfn, encoding.strtolocal(e.strerror)))
  1383                     _('cannot write patch "%s": %s')
       
  1384                     % (patchfn, encoding.strtolocal(e.strerror))
       
  1385                 )
  1276             try:
  1386             try:
  1277                 defaultmsg = "[mq]: %s" % patchfn
  1387                 defaultmsg = "[mq]: %s" % patchfn
  1278                 editor = cmdutil.getcommiteditor(editform=editform)
  1388                 editor = cmdutil.getcommiteditor(editform=editform)
  1279                 if edit:
  1389                 if edit:
       
  1390 
  1280                     def finishdesc(desc):
  1391                     def finishdesc(desc):
  1281                         if desc.rstrip():
  1392                         if desc.rstrip():
  1282                             return desc
  1393                             return desc
  1283                         else:
  1394                         else:
  1284                             return defaultmsg
  1395                             return defaultmsg
       
  1396 
  1285                     # i18n: this message is shown in editor with "HG: " prefix
  1397                     # i18n: this message is shown in editor with "HG: " prefix
  1286                     extramsg = _('Leave message empty to use default message.')
  1398                     extramsg = _('Leave message empty to use default message.')
  1287                     editor = cmdutil.getcommiteditor(finishdesc=finishdesc,
  1399                     editor = cmdutil.getcommiteditor(
  1288                                                      extramsg=extramsg,
  1400                         finishdesc=finishdesc,
  1289                                                      editform=editform)
  1401                         extramsg=extramsg,
       
  1402                         editform=editform,
       
  1403                     )
  1290                     commitmsg = msg
  1404                     commitmsg = msg
  1291                 else:
  1405                 else:
  1292                     commitmsg = msg or defaultmsg
  1406                     commitmsg = msg or defaultmsg
  1293 
  1407 
  1294                 n = newcommit(repo, None, commitmsg, user, date, match=match,
  1408                 n = newcommit(
  1295                               force=True, editor=editor)
  1409                     repo,
       
  1410                     None,
       
  1411                     commitmsg,
       
  1412                     user,
       
  1413                     date,
       
  1414                     match=match,
       
  1415                     force=True,
       
  1416                     editor=editor,
       
  1417                 )
  1296                 if n is None:
  1418                 if n is None:
  1297                     raise error.Abort(_("repo commit failed"))
  1419                     raise error.Abort(_("repo commit failed"))
  1298                 try:
  1420                 try:
  1299                     self.fullseries[insert:insert] = [patchfn]
  1421                     self.fullseries[insert:insert] = [patchfn]
  1300                     self.applied.append(statusentry(n, patchfn))
  1422                     self.applied.append(statusentry(n, patchfn))
  1315                     p.write(bytes(ph))
  1437                     p.write(bytes(ph))
  1316                     if commitfiles:
  1438                     if commitfiles:
  1317                         parent = self.qparents(repo, n)
  1439                         parent = self.qparents(repo, n)
  1318                         if inclsubs:
  1440                         if inclsubs:
  1319                             self.putsubstate2changes(substatestate, changes)
  1441                             self.putsubstate2changes(substatestate, changes)
  1320                         chunks = patchmod.diff(repo, node1=parent, node2=n,
  1442                         chunks = patchmod.diff(
  1321                                                changes=changes, opts=diffopts)
  1443                             repo,
       
  1444                             node1=parent,
       
  1445                             node2=n,
       
  1446                             changes=changes,
       
  1447                             opts=diffopts,
       
  1448                         )
  1322                         for chunk in chunks:
  1449                         for chunk in chunks:
  1323                             p.write(chunk)
  1450                             p.write(chunk)
  1324                     p.close()
  1451                     p.close()
  1325                     r = self.qrepo()
  1452                     r = self.qrepo()
  1326                     if r:
  1453                     if r:
  1327                         r[None].add([patchfn])
  1454                         r[None].add([patchfn])
  1328                 except: # re-raises
  1455                 except:  # re-raises
  1329                     repo.rollback()
  1456                     repo.rollback()
  1330                     raise
  1457                     raise
  1331             except Exception:
  1458             except Exception:
  1332                 patchpath = self.join(patchfn)
  1459                 patchpath = self.join(patchfn)
  1333                 try:
  1460                 try:
  1389                 if minus >= 0:
  1516                 if minus >= 0:
  1390                     res = partialname(patch[:minus])
  1517                     res = partialname(patch[:minus])
  1391                     if res:
  1518                     if res:
  1392                         i = self.series.index(res)
  1519                         i = self.series.index(res)
  1393                         try:
  1520                         try:
  1394                             off = int(patch[minus + 1:] or 1)
  1521                             off = int(patch[minus + 1 :] or 1)
  1395                         except (ValueError, OverflowError):
  1522                         except (ValueError, OverflowError):
  1396                             pass
  1523                             pass
  1397                         else:
  1524                         else:
  1398                             if i - off >= 0:
  1525                             if i - off >= 0:
  1399                                 return self.series[i - off]
  1526                                 return self.series[i - off]
  1401                 if plus >= 0:
  1528                 if plus >= 0:
  1402                     res = partialname(patch[:plus])
  1529                     res = partialname(patch[:plus])
  1403                     if res:
  1530                     if res:
  1404                         i = self.series.index(res)
  1531                         i = self.series.index(res)
  1405                         try:
  1532                         try:
  1406                             off = int(patch[plus + 1:] or 1)
  1533                             off = int(patch[plus + 1 :] or 1)
  1407                         except (ValueError, OverflowError):
  1534                         except (ValueError, OverflowError):
  1408                             pass
  1535                             pass
  1409                         else:
  1536                         else:
  1410                             if i + off < len(self.series):
  1537                             if i + off < len(self.series):
  1411                                 return self.series[i + off]
  1538                                 return self.series[i + off]
  1412         raise error.Abort(_("patch %s not in series") % patch)
  1539         raise error.Abort(_("patch %s not in series") % patch)
  1413 
  1540 
  1414     def push(self, repo, patch=None, force=False, list=False, mergeq=None,
  1541     def push(
  1415              all=False, move=False, exact=False, nobackup=False,
  1542         self,
  1416              keepchanges=False):
  1543         repo,
       
  1544         patch=None,
       
  1545         force=False,
       
  1546         list=False,
       
  1547         mergeq=None,
       
  1548         all=False,
       
  1549         move=False,
       
  1550         exact=False,
       
  1551         nobackup=False,
       
  1552         keepchanges=False,
       
  1553     ):
  1417         self.checkkeepchanges(keepchanges, force)
  1554         self.checkkeepchanges(keepchanges, force)
  1418         diffopts = self.diffopts()
  1555         diffopts = self.diffopts()
  1419         with repo.wlock():
  1556         with repo.wlock():
  1420             heads = []
  1557             heads = []
  1421             for hs in repo.branchmap().iterheads():
  1558             for hs in repo.branchmap().iterheads():
  1435             # go backwards with qpush)
  1572             # go backwards with qpush)
  1436             if patch:
  1573             if patch:
  1437                 patch = self.lookup(patch)
  1574                 patch = self.lookup(patch)
  1438                 info = self.isapplied(patch)
  1575                 info = self.isapplied(patch)
  1439                 if info and info[0] >= len(self.applied) - 1:
  1576                 if info and info[0] >= len(self.applied) - 1:
  1440                     self.ui.warn(
  1577                     self.ui.warn(_('qpush: %s is already at the top\n') % patch)
  1441                         _('qpush: %s is already at the top\n') % patch)
       
  1442                     return 0
  1578                     return 0
  1443 
  1579 
  1444                 pushable, reason = self.pushable(patch)
  1580                 pushable, reason = self.pushable(patch)
  1445                 if pushable:
  1581                 if pushable:
  1446                     if self.series.index(patch) < self.seriesend():
  1582                     if self.series.index(patch) < self.seriesend():
  1447                         raise error.Abort(
  1583                         raise error.Abort(
  1448                             _("cannot push to a previous patch: %s") % patch)
  1584                             _("cannot push to a previous patch: %s") % patch
       
  1585                         )
  1449                 else:
  1586                 else:
  1450                     if reason:
  1587                     if reason:
  1451                         reason = _('guarded by %s') % reason
  1588                         reason = _('guarded by %s') % reason
  1452                     else:
  1589                     else:
  1453                         reason = _('no matching guards')
  1590                         reason = _('no matching guards')
  1472                 self.checklocalchanges(repo, refresh=self.applied)
  1609                 self.checklocalchanges(repo, refresh=self.applied)
  1473 
  1610 
  1474             if exact:
  1611             if exact:
  1475                 if keepchanges:
  1612                 if keepchanges:
  1476                     raise error.Abort(
  1613                     raise error.Abort(
  1477                         _("cannot use --exact and --keep-changes together"))
  1614                         _("cannot use --exact and --keep-changes together")
       
  1615                     )
  1478                 if move:
  1616                 if move:
  1479                     raise error.Abort(_('cannot use --exact and --move '
  1617                     raise error.Abort(
  1480                                        'together'))
  1618                         _('cannot use --exact and --move ' 'together')
       
  1619                     )
  1481                 if self.applied:
  1620                 if self.applied:
  1482                     raise error.Abort(_('cannot push --exact with applied '
  1621                     raise error.Abort(
  1483                                        'patches'))
  1622                         _('cannot push --exact with applied ' 'patches')
       
  1623                     )
  1484                 root = self.series[start]
  1624                 root = self.series[start]
  1485                 target = patchheader(self.join(root), self.plainmode).parent
  1625                 target = patchheader(self.join(root), self.plainmode).parent
  1486                 if not target:
  1626                 if not target:
  1487                     raise error.Abort(
  1627                     raise error.Abort(
  1488                         _("%s does not have a parent recorded") % root)
  1628                         _("%s does not have a parent recorded") % root
       
  1629                     )
  1489                 if not repo[target] == repo['.']:
  1630                 if not repo[target] == repo['.']:
  1490                     hg.update(repo, target)
  1631                     hg.update(repo, target)
  1491 
  1632 
  1492             if move:
  1633             if move:
  1493                 if not patch:
  1634                 if not patch:
  1519 
  1660 
  1520             tobackup = set()
  1661             tobackup = set()
  1521             if (not nobackup and force) or keepchanges:
  1662             if (not nobackup and force) or keepchanges:
  1522                 status = self.checklocalchanges(repo, force=True)
  1663                 status = self.checklocalchanges(repo, force=True)
  1523                 if keepchanges:
  1664                 if keepchanges:
  1524                     tobackup.update(status.modified + status.added +
  1665                     tobackup.update(
  1525                                     status.removed + status.deleted)
  1666                         status.modified
       
  1667                         + status.added
       
  1668                         + status.removed
       
  1669                         + status.deleted
       
  1670                     )
  1526                 else:
  1671                 else:
  1527                     tobackup.update(status.modified + status.added)
  1672                     tobackup.update(status.modified + status.added)
  1528 
  1673 
  1529             s = self.series[start:end]
  1674             s = self.series[start:end]
  1530             all_files = set()
  1675             all_files = set()
  1531             try:
  1676             try:
  1532                 if mergeq:
  1677                 if mergeq:
  1533                     ret = self.mergepatch(repo, mergeq, s, diffopts)
  1678                     ret = self.mergepatch(repo, mergeq, s, diffopts)
  1534                 else:
  1679                 else:
  1535                     ret = self.apply(repo, s, list, all_files=all_files,
  1680                     ret = self.apply(
  1536                                      tobackup=tobackup, keepchanges=keepchanges)
  1681                         repo,
       
  1682                         s,
       
  1683                         list,
       
  1684                         all_files=all_files,
       
  1685                         tobackup=tobackup,
       
  1686                         keepchanges=keepchanges,
       
  1687                     )
  1537             except AbortNoCleanup:
  1688             except AbortNoCleanup:
  1538                 raise
  1689                 raise
  1539             except: # re-raises
  1690             except:  # re-raises
  1540                 self.ui.warn(_('cleaning up working directory...\n'))
  1691                 self.ui.warn(_('cleaning up working directory...\n'))
  1541                 cmdutil.revert(self.ui, repo, repo['.'],
  1692                 cmdutil.revert(
  1542                                repo.dirstate.parents(), no_backup=True)
  1693                     self.ui,
       
  1694                     repo,
       
  1695                     repo['.'],
       
  1696                     repo.dirstate.parents(),
       
  1697                     no_backup=True,
       
  1698                 )
  1543                 # only remove unknown files that we know we touched or
  1699                 # only remove unknown files that we know we touched or
  1544                 # created while patching
  1700                 # created while patching
  1545                 for f in all_files:
  1701                 for f in all_files:
  1546                     if f not in repo.dirstate:
  1702                     if f not in repo.dirstate:
  1547                         repo.wvfs.unlinkpath(f, ignoremissing=True)
  1703                         repo.wvfs.unlinkpath(f, ignoremissing=True)
  1556                 self.ui.write(msg % top)
  1712                 self.ui.write(msg % top)
  1557             else:
  1713             else:
  1558                 self.ui.write(_("now at: %s\n") % top)
  1714                 self.ui.write(_("now at: %s\n") % top)
  1559             return ret[0]
  1715             return ret[0]
  1560 
  1716 
  1561     def pop(self, repo, patch=None, force=False, update=True, all=False,
  1717     def pop(
  1562             nobackup=False, keepchanges=False):
  1718         self,
       
  1719         repo,
       
  1720         patch=None,
       
  1721         force=False,
       
  1722         update=True,
       
  1723         all=False,
       
  1724         nobackup=False,
       
  1725         keepchanges=False,
       
  1726     ):
  1563         self.checkkeepchanges(keepchanges, force)
  1727         self.checkkeepchanges(keepchanges, force)
  1564         with repo.wlock():
  1728         with repo.wlock():
  1565             if patch:
  1729             if patch:
  1566                 # index, rev, patch
  1730                 # index, rev, patch
  1567                 info = self.isapplied(patch)
  1731                 info = self.isapplied(patch)
  1595                     if p in rr:
  1759                     if p in rr:
  1596                         self.ui.warn(_("qpop: forcing dirstate update\n"))
  1760                         self.ui.warn(_("qpop: forcing dirstate update\n"))
  1597                         update = True
  1761                         update = True
  1598             else:
  1762             else:
  1599                 parents = [p.node() for p in repo[None].parents()]
  1763                 parents = [p.node() for p in repo[None].parents()]
  1600                 update = any(entry.node in parents
  1764                 update = any(
  1601                              for entry in self.applied[start:])
  1765                     entry.node in parents for entry in self.applied[start:]
       
  1766                 )
  1602 
  1767 
  1603             tobackup = set()
  1768             tobackup = set()
  1604             if update:
  1769             if update:
  1605                 s = self.checklocalchanges(repo, force=force or keepchanges)
  1770                 s = self.checklocalchanges(repo, force=force or keepchanges)
  1606                 if force:
  1771                 if force:
  1607                     if not nobackup:
  1772                     if not nobackup:
  1608                         tobackup.update(s.modified + s.added)
  1773                         tobackup.update(s.modified + s.added)
  1609                 elif keepchanges:
  1774                 elif keepchanges:
  1610                     tobackup.update(s.modified + s.added +
  1775                     tobackup.update(
  1611                                     s.removed + s.deleted)
  1776                         s.modified + s.added + s.removed + s.deleted
       
  1777                     )
  1612 
  1778 
  1613             self.applieddirty = True
  1779             self.applieddirty = True
  1614             end = len(self.applied)
  1780             end = len(self.applied)
  1615             rev = self.applied[start].node
  1781             rev = self.applied[start].node
  1616 
  1782 
  1619             except error.LookupError:
  1785             except error.LookupError:
  1620                 node = short(rev)
  1786                 node = short(rev)
  1621                 raise error.Abort(_('trying to pop unknown node %s') % node)
  1787                 raise error.Abort(_('trying to pop unknown node %s') % node)
  1622 
  1788 
  1623             if heads != [self.applied[-1].node]:
  1789             if heads != [self.applied[-1].node]:
  1624                 raise error.Abort(_("popping would remove a revision not "
  1790                 raise error.Abort(
  1625                                    "managed by this patch queue"))
  1791                     _(
       
  1792                         "popping would remove a revision not "
       
  1793                         "managed by this patch queue"
       
  1794                     )
       
  1795                 )
  1626             if not repo[self.applied[-1].node].mutable():
  1796             if not repo[self.applied[-1].node].mutable():
  1627                 raise error.Abort(
  1797                 raise error.Abort(
  1628                     _("popping would remove a public revision"),
  1798                     _("popping would remove a public revision"),
  1629                     hint=_("see 'hg help phases' for details"))
  1799                     hint=_("see 'hg help phases' for details"),
       
  1800                 )
  1630 
  1801 
  1631             # we know there are no local changes, so we can make a simplified
  1802             # we know there are no local changes, so we can make a simplified
  1632             # form of hg.update.
  1803             # form of hg.update.
  1633             if update:
  1804             if update:
  1634                 qp = self.qparents(repo, rev)
  1805                 qp = self.qparents(repo, rev)
  1692             self.checktoppatch(repo)
  1863             self.checktoppatch(repo)
  1693             (top, patchfn) = (self.applied[-1].node, self.applied[-1].name)
  1864             (top, patchfn) = (self.applied[-1].node, self.applied[-1].name)
  1694             if repo.changelog.heads(top) != [top]:
  1865             if repo.changelog.heads(top) != [top]:
  1695                 raise error.Abort(_("cannot qrefresh a revision with children"))
  1866                 raise error.Abort(_("cannot qrefresh a revision with children"))
  1696             if not repo[top].mutable():
  1867             if not repo[top].mutable():
  1697                 raise error.Abort(_("cannot qrefresh public revision"),
  1868                 raise error.Abort(
  1698                                  hint=_("see 'hg help phases' for details"))
  1869                     _("cannot qrefresh public revision"),
       
  1870                     hint=_("see 'hg help phases' for details"),
       
  1871                 )
  1699 
  1872 
  1700             cparents = repo.changelog.parents(top)
  1873             cparents = repo.changelog.parents(top)
  1701             patchparent = self.qparents(repo, top)
  1874             patchparent = self.qparents(repo, top)
  1702 
  1875 
  1703             inclsubs = checksubstate(repo, patchparent)
  1876             inclsubs = checksubstate(repo, patchparent)
  1704             if inclsubs:
  1877             if inclsubs:
  1705                 substatestate = repo.dirstate['.hgsubstate']
  1878                 substatestate = repo.dirstate['.hgsubstate']
  1706 
  1879 
  1707             ph = patchheader(self.join(patchfn), self.plainmode)
  1880             ph = patchheader(self.join(patchfn), self.plainmode)
  1708             diffopts = self.diffopts({'git': opts.get('git')}, patchfn,
  1881             diffopts = self.diffopts(
  1709                                      plain=True)
  1882                 {'git': opts.get('git')}, patchfn, plain=True
       
  1883             )
  1710             if newuser:
  1884             if newuser:
  1711                 ph.setuser(newuser)
  1885                 ph.setuser(newuser)
  1712             if newdate:
  1886             if newdate:
  1713                 ph.setdate(newdate)
  1887                 ph.setdate(newdate)
  1714             ph.setparent(hex(patchparent))
  1888             ph.setparent(hex(patchparent))
  1802                     # remember the copies between patchparent and qtip
  1976                     # remember the copies between patchparent and qtip
  1803                     for dst in aaa:
  1977                     for dst in aaa:
  1804                         src = ctx[dst].copysource()
  1978                         src = ctx[dst].copysource()
  1805                         if src:
  1979                         if src:
  1806                             copies.setdefault(src, []).extend(
  1980                             copies.setdefault(src, []).extend(
  1807                                 copies.get(dst, []))
  1981                                 copies.get(dst, [])
       
  1982                             )
  1808                             if dst in a:
  1983                             if dst in a:
  1809                                 copies[src].append(dst)
  1984                                 copies[src].append(dst)
  1810                         # we can't copy a file created by the patch itself
  1985                         # we can't copy a file created by the patch itself
  1811                         if dst in copies:
  1986                         if dst in copies:
  1812                             del copies[dst]
  1987                             del copies[dst]
  1852                 # might be nice to attempt to roll back strip after this
  2027                 # might be nice to attempt to roll back strip after this
  1853 
  2028 
  1854                 defaultmsg = "[mq]: %s" % patchfn
  2029                 defaultmsg = "[mq]: %s" % patchfn
  1855                 editor = cmdutil.getcommiteditor(editform=editform)
  2030                 editor = cmdutil.getcommiteditor(editform=editform)
  1856                 if edit:
  2031                 if edit:
       
  2032 
  1857                     def finishdesc(desc):
  2033                     def finishdesc(desc):
  1858                         if desc.rstrip():
  2034                         if desc.rstrip():
  1859                             ph.setmessage(desc)
  2035                             ph.setmessage(desc)
  1860                             return desc
  2036                             return desc
  1861                         return defaultmsg
  2037                         return defaultmsg
       
  2038 
  1862                     # i18n: this message is shown in editor with "HG: " prefix
  2039                     # i18n: this message is shown in editor with "HG: " prefix
  1863                     extramsg = _('Leave message empty to use default message.')
  2040                     extramsg = _('Leave message empty to use default message.')
  1864                     editor = cmdutil.getcommiteditor(finishdesc=finishdesc,
  2041                     editor = cmdutil.getcommiteditor(
  1865                                                      extramsg=extramsg,
  2042                         finishdesc=finishdesc,
  1866                                                      editform=editform)
  2043                         extramsg=extramsg,
       
  2044                         editform=editform,
       
  2045                     )
  1867                     message = msg or "\n".join(ph.message)
  2046                     message = msg or "\n".join(ph.message)
  1868                 elif not msg:
  2047                 elif not msg:
  1869                     if not ph.message:
  2048                     if not ph.message:
  1870                         message = defaultmsg
  2049                         message = defaultmsg
  1871                     else:
  2050                     else:
  1878                 # the old one.
  2057                 # the old one.
  1879                 lock = tr = None
  2058                 lock = tr = None
  1880                 try:
  2059                 try:
  1881                     lock = repo.lock()
  2060                     lock = repo.lock()
  1882                     tr = repo.transaction('mq')
  2061                     tr = repo.transaction('mq')
  1883                     n = newcommit(repo, oldphase, message, user, ph.date,
  2062                     n = newcommit(
  1884                               match=match, force=True, editor=editor)
  2063                         repo,
       
  2064                         oldphase,
       
  2065                         message,
       
  2066                         user,
       
  2067                         ph.date,
       
  2068                         match=match,
       
  2069                         force=True,
       
  2070                         editor=editor,
       
  2071                     )
  1885                     # only write patch after a successful commit
  2072                     # only write patch after a successful commit
  1886                     c = [list(x) for x in refreshchanges]
  2073                     c = [list(x) for x in refreshchanges]
  1887                     if inclsubs:
  2074                     if inclsubs:
  1888                         self.putsubstate2changes(substatestate, c)
  2075                         self.putsubstate2changes(substatestate, c)
  1889                     chunks = patchmod.diff(repo, patchparent,
  2076                     chunks = patchmod.diff(
  1890                                            changes=c, opts=diffopts)
  2077                         repo, patchparent, changes=c, opts=diffopts
       
  2078                     )
  1891                     comments = bytes(ph)
  2079                     comments = bytes(ph)
  1892                     if comments:
  2080                     if comments:
  1893                         patchf.write(comments)
  2081                         patchf.write(comments)
  1894                     for chunk in chunks:
  2082                     for chunk in chunks:
  1895                         patchf.write(chunk)
  2083                         patchf.write(chunk)
  1900                     tr.close()
  2088                     tr.close()
  1901 
  2089 
  1902                     self.applied.append(statusentry(n, patchfn))
  2090                     self.applied.append(statusentry(n, patchfn))
  1903                 finally:
  2091                 finally:
  1904                     lockmod.release(tr, lock)
  2092                     lockmod.release(tr, lock)
  1905             except: # re-raises
  2093             except:  # re-raises
  1906                 ctx = repo[cparents[0]]
  2094                 ctx = repo[cparents[0]]
  1907                 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
  2095                 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
  1908                 self.savedirty()
  2096                 self.savedirty()
  1909                 self.ui.warn(_('qrefresh interrupted while patch was popped! '
  2097                 self.ui.warn(
  1910                                '(revert --all, qpush to recover)\n'))
  2098                     _(
       
  2099                         'qrefresh interrupted while patch was popped! '
       
  2100                         '(revert --all, qpush to recover)\n'
       
  2101                     )
       
  2102                 )
  1911                 raise
  2103                 raise
  1912         finally:
  2104         finally:
  1913             wlock.release()
  2105             wlock.release()
  1914             self.removeundo(repo)
  2106             self.removeundo(repo)
  1915 
  2107 
  1937             if pushable:
  2129             if pushable:
  1938                 unapplied.append((i, self.series[i]))
  2130                 unapplied.append((i, self.series[i]))
  1939             self.explainpushable(i)
  2131             self.explainpushable(i)
  1940         return unapplied
  2132         return unapplied
  1941 
  2133 
  1942     def qseries(self, repo, missing=None, start=0, length=None, status=None,
  2134     def qseries(
  1943                 summary=False):
  2135         self,
       
  2136         repo,
       
  2137         missing=None,
       
  2138         start=0,
       
  2139         length=None,
       
  2140         status=None,
       
  2141         summary=False,
       
  2142     ):
  1944         def displayname(pfx, patchname, state):
  2143         def displayname(pfx, patchname, state):
  1945             if pfx:
  2144             if pfx:
  1946                 self.ui.write(pfx)
  2145                 self.ui.write(pfx)
  1947             if summary:
  2146             if summary:
  1948                 ph = patchheader(self.join(patchname), self.plainmode)
  2147                 ph = patchheader(self.join(patchname), self.plainmode)
  1985                     continue
  2184                     continue
  1986                 displayname(pfx, patch, state)
  2185                 displayname(pfx, patch, state)
  1987         else:
  2186         else:
  1988             msng_list = []
  2187             msng_list = []
  1989             for root, dirs, files in os.walk(self.path):
  2188             for root, dirs, files in os.walk(self.path):
  1990                 d = root[len(self.path) + 1:]
  2189                 d = root[len(self.path) + 1 :]
  1991                 for f in files:
  2190                 for f in files:
  1992                     fl = os.path.join(d, f)
  2191                     fl = os.path.join(d, f)
  1993                     if (fl not in self.series and
  2192                     if (
  1994                         fl not in (self.statuspath, self.seriespath,
  2193                         fl not in self.series
  1995                                    self.guardspath)
  2194                         and fl
  1996                         and not fl.startswith('.')):
  2195                         not in (
       
  2196                             self.statuspath,
       
  2197                             self.seriespath,
       
  2198                             self.guardspath,
       
  2199                         )
       
  2200                         and not fl.startswith('.')
       
  2201                     ):
  1997                         msng_list.append(fl)
  2202                         msng_list.append(fl)
  1998             for x in sorted(msng_list):
  2203             for x in sorted(msng_list):
  1999                 pfx = self.ui.verbose and ('D ') or ''
  2204                 pfx = self.ui.verbose and 'D ' or ''
  2000                 displayname(pfx, x, 'missing')
  2205                 displayname(pfx, x, 'missing')
  2001 
  2206 
  2002     def issaveline(self, l):
  2207     def issaveline(self, l):
  2003         if l.name == '.hg.patches.save.line':
  2208         if l.name == '.hg.patches.save.line':
  2004             return True
  2209             return True
  2007         ui = self.baseui.copy()
  2212         ui = self.baseui.copy()
  2008         # copy back attributes set by ui.pager()
  2213         # copy back attributes set by ui.pager()
  2009         if self.ui.pageractive and not ui.pageractive:
  2214         if self.ui.pageractive and not ui.pageractive:
  2010             ui.pageractive = self.ui.pageractive
  2215             ui.pageractive = self.ui.pageractive
  2011             # internal config: ui.formatted
  2216             # internal config: ui.formatted
  2012             ui.setconfig('ui', 'formatted',
  2217             ui.setconfig(
  2013                          self.ui.config('ui', 'formatted'), 'mqpager')
  2218                 'ui', 'formatted', self.ui.config('ui', 'formatted'), 'mqpager'
  2014             ui.setconfig('ui', 'interactive',
  2219             )
  2015                          self.ui.config('ui', 'interactive'), 'mqpager')
  2220             ui.setconfig(
       
  2221                 'ui',
       
  2222                 'interactive',
       
  2223                 self.ui.config('ui', 'interactive'),
       
  2224                 'mqpager',
       
  2225             )
  2016         if create or os.path.isdir(self.join(".hg")):
  2226         if create or os.path.isdir(self.join(".hg")):
  2017             return hg.repository(ui, path=self.path, create=create)
  2227             return hg.repository(ui, path=self.path, create=create)
  2018 
  2228 
  2019     def restore(self, repo, rev, delete=None, qupdate=None):
  2229     def restore(self, repo, rev, delete=None, qupdate=None):
  2020         desc = repo[rev].description().strip()
  2230         desc = repo[rev].description().strip()
  2058                     update = True
  2268                     update = True
  2059                 else:
  2269                 else:
  2060                     update = False
  2270                     update = False
  2061                 strip(self.ui, repo, [rev], update=update, backup=False)
  2271                 strip(self.ui, repo, [rev], update=update, backup=False)
  2062         if qpp:
  2272         if qpp:
  2063             self.ui.warn(_("saved queue repository parents: %s %s\n") %
  2273             self.ui.warn(
  2064                          (short(qpp[0]), short(qpp[1])))
  2274                 _("saved queue repository parents: %s %s\n")
       
  2275                 % (short(qpp[0]), short(qpp[1]))
       
  2276             )
  2065             if qupdate:
  2277             if qupdate:
  2066                 self.ui.status(_("updating queue directory\n"))
  2278                 self.ui.status(_("updating queue directory\n"))
  2067                 r = self.qrepo()
  2279                 r = self.qrepo()
  2068                 if not r:
  2280                 if not r:
  2069                     self.ui.warn(_("unable to load queue repository\n"))
  2281                     self.ui.warn(_("unable to load queue repository\n"))
  2110         """If all_patches is False, return the index of the next pushable patch
  2322         """If all_patches is False, return the index of the next pushable patch
  2111         in the series, or the series length. If all_patches is True, return the
  2323         in the series, or the series length. If all_patches is True, return the
  2112         index of the first patch past the last applied one.
  2324         index of the first patch past the last applied one.
  2113         """
  2325         """
  2114         end = 0
  2326         end = 0
       
  2327 
  2115         def nextpatch(start):
  2328         def nextpatch(start):
  2116             if all_patches or start >= len(self.series):
  2329             if all_patches or start >= len(self.series):
  2117                 return start
  2330                 return start
  2118             for i in pycompat.xrange(start, len(self.series)):
  2331             for i in pycompat.xrange(start, len(self.series)):
  2119                 p, reason = self.pushable(i)
  2332                 p, reason = self.pushable(i)
  2120                 if p:
  2333                 if p:
  2121                     return i
  2334                     return i
  2122                 self.explainpushable(i)
  2335                 self.explainpushable(i)
  2123             return len(self.series)
  2336             return len(self.series)
       
  2337 
  2124         if self.applied:
  2338         if self.applied:
  2125             p = self.applied[-1].name
  2339             p = self.applied[-1].name
  2126             try:
  2340             try:
  2127                 end = self.series.index(p)
  2341                 end = self.series.index(p)
  2128             except ValueError:
  2342             except ValueError:
  2136             p = pname
  2350             p = pname
  2137         else:
  2351         else:
  2138             p = ("%d" % self.series.index(pname)) + " " + pname
  2352             p = ("%d" % self.series.index(pname)) + " " + pname
  2139         return p
  2353         return p
  2140 
  2354 
  2141     def qimport(self, repo, files, patchname=None, rev=None, existing=None,
  2355     def qimport(
  2142                 force=None, git=False):
  2356         self,
       
  2357         repo,
       
  2358         files,
       
  2359         patchname=None,
       
  2360         rev=None,
       
  2361         existing=None,
       
  2362         force=None,
       
  2363         git=False,
       
  2364     ):
  2143         def checkseries(patchname):
  2365         def checkseries(patchname):
  2144             if patchname in self.series:
  2366             if patchname in self.series:
  2145                 raise error.Abort(_('patch %s is already in the series file')
  2367                 raise error.Abort(
  2146                                  % patchname)
  2368                     _('patch %s is already in the series file') % patchname
       
  2369                 )
  2147 
  2370 
  2148         if rev:
  2371         if rev:
  2149             if files:
  2372             if files:
  2150                 raise error.Abort(_('option "-r" not valid when importing '
  2373                 raise error.Abort(
  2151                                    'files'))
  2374                     _('option "-r" not valid when importing ' 'files')
       
  2375                 )
  2152             rev = scmutil.revrange(repo, rev)
  2376             rev = scmutil.revrange(repo, rev)
  2153             rev.sort(reverse=True)
  2377             rev.sort(reverse=True)
  2154         elif not files:
  2378         elif not files:
  2155             raise error.Abort(_('no files or revisions specified'))
  2379             raise error.Abort(_('no files or revisions specified'))
  2156         if (len(files) > 1 or len(rev) > 1) and patchname:
  2380         if (len(files) > 1 or len(rev) > 1) and patchname:
  2157             raise error.Abort(_('option "-n" not valid when importing multiple '
  2381             raise error.Abort(
  2158                                'patches'))
  2382                 _('option "-n" not valid when importing multiple ' 'patches')
       
  2383             )
  2159         imported = []
  2384         imported = []
  2160         if rev:
  2385         if rev:
  2161             # If mq patches are applied, we can only import revisions
  2386             # If mq patches are applied, we can only import revisions
  2162             # that form a linear path to qbase.
  2387             # that form a linear path to qbase.
  2163             # Otherwise, they should form a linear path to a head.
  2388             # Otherwise, they should form a linear path to a head.
  2164             heads = repo.changelog.heads(repo.changelog.node(rev.first()))
  2389             heads = repo.changelog.heads(repo.changelog.node(rev.first()))
  2165             if len(heads) > 1:
  2390             if len(heads) > 1:
  2166                 raise error.Abort(_('revision %d is the root of more than one '
  2391                 raise error.Abort(
  2167                                    'branch') % rev.last())
  2392                     _('revision %d is the root of more than one ' 'branch')
       
  2393                     % rev.last()
       
  2394                 )
  2168             if self.applied:
  2395             if self.applied:
  2169                 base = repo.changelog.node(rev.first())
  2396                 base = repo.changelog.node(rev.first())
  2170                 if base in [n.node for n in self.applied]:
  2397                 if base in [n.node for n in self.applied]:
  2171                     raise error.Abort(_('revision %d is already managed')
  2398                     raise error.Abort(
  2172                                      % rev.first())
  2399                         _('revision %d is already managed') % rev.first()
       
  2400                     )
  2173                 if heads != [self.applied[-1].node]:
  2401                 if heads != [self.applied[-1].node]:
  2174                     raise error.Abort(_('revision %d is not the parent of '
  2402                     raise error.Abort(
  2175                                        'the queue') % rev.first())
  2403                         _('revision %d is not the parent of ' 'the queue')
       
  2404                         % rev.first()
       
  2405                     )
  2176                 base = repo.changelog.rev(self.applied[0].node)
  2406                 base = repo.changelog.rev(self.applied[0].node)
  2177                 lastparent = repo.changelog.parentrevs(base)[0]
  2407                 lastparent = repo.changelog.parentrevs(base)[0]
  2178             else:
  2408             else:
  2179                 if heads != [repo.changelog.node(rev.first())]:
  2409                 if heads != [repo.changelog.node(rev.first())]:
  2180                     raise error.Abort(_('revision %d has unmanaged children')
  2410                     raise error.Abort(
  2181                                      % rev.first())
  2411                         _('revision %d has unmanaged children') % rev.first()
       
  2412                     )
  2182                 lastparent = None
  2413                 lastparent = None
  2183 
  2414 
  2184             diffopts = self.diffopts({'git': git})
  2415             diffopts = self.diffopts({'git': git})
  2185             with repo.transaction('qimport') as tr:
  2416             with repo.transaction('qimport') as tr:
  2186                 for r in rev:
  2417                 for r in rev:
  2187                     if not repo[r].mutable():
  2418                     if not repo[r].mutable():
  2188                         raise error.Abort(_('revision %d is not mutable') % r,
  2419                         raise error.Abort(
  2189                                          hint=_("see 'hg help phases' "
  2420                             _('revision %d is not mutable') % r,
  2190                                                 'for details'))
  2421                             hint=_("see 'hg help phases' " 'for details'),
       
  2422                         )
  2191                     p1, p2 = repo.changelog.parentrevs(r)
  2423                     p1, p2 = repo.changelog.parentrevs(r)
  2192                     n = repo.changelog.node(r)
  2424                     n = repo.changelog.node(r)
  2193                     if p2 != nullrev:
  2425                     if p2 != nullrev:
  2194                         raise error.Abort(_('cannot import merge revision %d')
  2426                         raise error.Abort(
  2195                                          % r)
  2427                             _('cannot import merge revision %d') % r
       
  2428                         )
  2196                     if lastparent and lastparent != r:
  2429                     if lastparent and lastparent != r:
  2197                         raise error.Abort(_('revision %d is not the parent of '
  2430                         raise error.Abort(
  2198                                            '%d')
  2431                             _('revision %d is not the parent of ' '%d')
  2199                                          % (r, lastparent))
  2432                             % (r, lastparent)
       
  2433                         )
  2200                     lastparent = p1
  2434                     lastparent = p1
  2201 
  2435 
  2202                     if not patchname:
  2436                     if not patchname:
  2203                         patchname = self.makepatchname(
  2437                         patchname = self.makepatchname(
  2204                             repo[r].description().split('\n', 1)[0],
  2438                             repo[r].description().split('\n', 1)[0],
  2205                             '%d.diff' % r)
  2439                             '%d.diff' % r,
       
  2440                         )
  2206                     checkseries(patchname)
  2441                     checkseries(patchname)
  2207                     self.checkpatchname(patchname, force)
  2442                     self.checkpatchname(patchname, force)
  2208                     self.fullseries.insert(0, patchname)
  2443                     self.fullseries.insert(0, patchname)
  2209 
  2444 
  2210                     with self.opener(patchname, "w") as fp:
  2445                     with self.opener(patchname, "w") as fp:
  2224                     self.seriesdirty = True
  2459                     self.seriesdirty = True
  2225 
  2460 
  2226         for i, filename in enumerate(files):
  2461         for i, filename in enumerate(files):
  2227             if existing:
  2462             if existing:
  2228                 if filename == '-':
  2463                 if filename == '-':
  2229                     raise error.Abort(_('-e is incompatible with import from -')
  2464                     raise error.Abort(
  2230                                      )
  2465                         _('-e is incompatible with import from -')
       
  2466                     )
  2231                 filename = normname(filename)
  2467                 filename = normname(filename)
  2232                 self.checkreservedname(filename)
  2468                 self.checkreservedname(filename)
  2233                 if util.url(filename).islocal():
  2469                 if util.url(filename).islocal():
  2234                     originpath = self.join(filename)
  2470                     originpath = self.join(filename)
  2235                     if not os.path.isfile(originpath):
  2471                     if not os.path.isfile(originpath):
  2236                         raise error.Abort(
  2472                         raise error.Abort(
  2237                             _("patch %s does not exist") % filename)
  2473                             _("patch %s does not exist") % filename
       
  2474                         )
  2238 
  2475 
  2239                 if patchname:
  2476                 if patchname:
  2240                     self.checkpatchname(patchname, force)
  2477                     self.checkpatchname(patchname, force)
  2241 
  2478 
  2242                     self.ui.write(_('renaming %s to %s\n')
  2479                     self.ui.write(
  2243                                         % (filename, patchname))
  2480                         _('renaming %s to %s\n') % (filename, patchname)
       
  2481                     )
  2244                     util.rename(originpath, self.join(patchname))
  2482                     util.rename(originpath, self.join(patchname))
  2245                 else:
  2483                 else:
  2246                     patchname = filename
  2484                     patchname = filename
  2247 
  2485 
  2248             else:
  2486             else:
  2276             patchname = None
  2514             patchname = None
  2277 
  2515 
  2278         self.removeundo(repo)
  2516         self.removeundo(repo)
  2279         return imported
  2517         return imported
  2280 
  2518 
       
  2519 
  2281 def fixkeepchangesopts(ui, opts):
  2520 def fixkeepchangesopts(ui, opts):
  2282     if (not ui.configbool('mq', 'keepchanges') or opts.get('force')
  2521     if (
  2283         or opts.get('exact')):
  2522         not ui.configbool('mq', 'keepchanges')
       
  2523         or opts.get('force')
       
  2524         or opts.get('exact')
       
  2525     ):
  2284         return opts
  2526         return opts
  2285     opts = dict(opts)
  2527     opts = dict(opts)
  2286     opts['keep_changes'] = True
  2528     opts['keep_changes'] = True
  2287     return opts
  2529     return opts
  2288 
  2530 
  2289 @command("qdelete|qremove|qrm",
  2531 
  2290          [('k', 'keep', None, _('keep patch file')),
  2532 @command(
  2291           ('r', 'rev', [],
  2533     "qdelete|qremove|qrm",
  2292            _('stop managing a revision (DEPRECATED)'), _('REV'))],
  2534     [
  2293          _('hg qdelete [-k] [PATCH]...'),
  2535         ('k', 'keep', None, _('keep patch file')),
  2294          helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
  2536         ('r', 'rev', [], _('stop managing a revision (DEPRECATED)'), _('REV')),
       
  2537     ],
       
  2538     _('hg qdelete [-k] [PATCH]...'),
       
  2539     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
       
  2540 )
  2295 def delete(ui, repo, *patches, **opts):
  2541 def delete(ui, repo, *patches, **opts):
  2296     """remove patches from queue
  2542     """remove patches from queue
  2297 
  2543 
  2298     The patches must not be applied, and at least one patch is required. Exact
  2544     The patches must not be applied, and at least one patch is required. Exact
  2299     patch identifiers must be given. With -k/--keep, the patch files are
  2545     patch identifiers must be given. With -k/--keep, the patch files are
  2304     q = repo.mq
  2550     q = repo.mq
  2305     q.delete(repo, patches, pycompat.byteskwargs(opts))
  2551     q.delete(repo, patches, pycompat.byteskwargs(opts))
  2306     q.savedirty()
  2552     q.savedirty()
  2307     return 0
  2553     return 0
  2308 
  2554 
  2309 @command("qapplied",
  2555 
  2310          [('1', 'last', None, _('show only the preceding applied patch'))
  2556 @command(
  2311           ] + seriesopts,
  2557     "qapplied",
  2312          _('hg qapplied [-1] [-s] [PATCH]'),
  2558     [('1', 'last', None, _('show only the preceding applied patch'))]
  2313          helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
  2559     + seriesopts,
       
  2560     _('hg qapplied [-1] [-s] [PATCH]'),
       
  2561     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
       
  2562 )
  2314 def applied(ui, repo, patch=None, **opts):
  2563 def applied(ui, repo, patch=None, **opts):
  2315     """print the patches already applied
  2564     """print the patches already applied
  2316 
  2565 
  2317     Returns 0 on success."""
  2566     Returns 0 on success."""
  2318 
  2567 
  2336         start = end - 2
  2585         start = end - 2
  2337         end = 1
  2586         end = 1
  2338     else:
  2587     else:
  2339         start = 0
  2588         start = 0
  2340 
  2589 
  2341     q.qseries(repo, length=end, start=start, status='A',
  2590     q.qseries(
  2342               summary=opts.get('summary'))
  2591         repo, length=end, start=start, status='A', summary=opts.get('summary')
  2343 
  2592     )
  2344 
  2593 
  2345 @command("qunapplied",
  2594 
  2346          [('1', 'first', None, _('show only the first patch'))] + seriesopts,
  2595 @command(
  2347          _('hg qunapplied [-1] [-s] [PATCH]'),
  2596     "qunapplied",
  2348          helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
  2597     [('1', 'first', None, _('show only the first patch'))] + seriesopts,
       
  2598     _('hg qunapplied [-1] [-s] [PATCH]'),
       
  2599     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
       
  2600 )
  2349 def unapplied(ui, repo, patch=None, **opts):
  2601 def unapplied(ui, repo, patch=None, **opts):
  2350     """print the patches not yet applied
  2602     """print the patches not yet applied
  2351 
  2603 
  2352     Returns 0 on success."""
  2604     Returns 0 on success."""
  2353 
  2605 
  2366 
  2618 
  2367     if opts.get('first'):
  2619     if opts.get('first'):
  2368         length = 1
  2620         length = 1
  2369     else:
  2621     else:
  2370         length = None
  2622         length = None
  2371     q.qseries(repo, start=start, length=length, status='U',
  2623     q.qseries(
  2372               summary=opts.get('summary'))
  2624         repo,
  2373 
  2625         start=start,
  2374 @command("qimport",
  2626         length=length,
  2375          [('e', 'existing', None, _('import file in patch directory')),
  2627         status='U',
  2376           ('n', 'name', '',
  2628         summary=opts.get('summary'),
  2377            _('name of patch file'), _('NAME')),
  2629     )
  2378           ('f', 'force', None, _('overwrite existing files')),
  2630 
  2379           ('r', 'rev', [],
  2631 
  2380            _('place existing revisions under mq control'), _('REV')),
  2632 @command(
  2381           ('g', 'git', None, _('use git extended diff format')),
  2633     "qimport",
  2382           ('P', 'push', None, _('qpush after importing'))],
  2634     [
  2383          _('hg qimport [-e] [-n NAME] [-f] [-g] [-P] [-r REV]... [FILE]...'),
  2635         ('e', 'existing', None, _('import file in patch directory')),
  2384          helpcategory=command.CATEGORY_IMPORT_EXPORT)
  2636         ('n', 'name', '', _('name of patch file'), _('NAME')),
       
  2637         ('f', 'force', None, _('overwrite existing files')),
       
  2638         (
       
  2639             'r',
       
  2640             'rev',
       
  2641             [],
       
  2642             _('place existing revisions under mq control'),
       
  2643             _('REV'),
       
  2644         ),
       
  2645         ('g', 'git', None, _('use git extended diff format')),
       
  2646         ('P', 'push', None, _('qpush after importing')),
       
  2647     ],
       
  2648     _('hg qimport [-e] [-n NAME] [-f] [-g] [-P] [-r REV]... [FILE]...'),
       
  2649     helpcategory=command.CATEGORY_IMPORT_EXPORT,
       
  2650 )
  2385 def qimport(ui, repo, *filename, **opts):
  2651 def qimport(ui, repo, *filename, **opts):
  2386     """import a patch or existing changeset
  2652     """import a patch or existing changeset
  2387 
  2653 
  2388     The patch is inserted into the series after the last applied
  2654     The patch is inserted into the series after the last applied
  2389     patch. If no patches have been applied, qimport prepends the patch
  2655     patch. If no patches have been applied, qimport prepends the patch
  2415       hg qimport -e existing-patch -n new-name
  2681       hg qimport -e existing-patch -n new-name
  2416 
  2682 
  2417     Returns 0 if import succeeded.
  2683     Returns 0 if import succeeded.
  2418     """
  2684     """
  2419     opts = pycompat.byteskwargs(opts)
  2685     opts = pycompat.byteskwargs(opts)
  2420     with repo.lock(): # cause this may move phase
  2686     with repo.lock():  # cause this may move phase
  2421         q = repo.mq
  2687         q = repo.mq
  2422         try:
  2688         try:
  2423             imported = q.qimport(
  2689             imported = q.qimport(
  2424                 repo, filename, patchname=opts.get('name'),
  2690                 repo,
  2425                 existing=opts.get('existing'), force=opts.get('force'),
  2691                 filename,
  2426                 rev=opts.get('rev'), git=opts.get('git'))
  2692                 patchname=opts.get('name'),
       
  2693                 existing=opts.get('existing'),
       
  2694                 force=opts.get('force'),
       
  2695                 rev=opts.get('rev'),
       
  2696                 git=opts.get('git'),
       
  2697             )
  2427         finally:
  2698         finally:
  2428             q.savedirty()
  2699             q.savedirty()
  2429 
  2700 
  2430     if imported and opts.get('push') and not opts.get('rev'):
  2701     if imported and opts.get('push') and not opts.get('rev'):
  2431         return q.push(repo, imported[-1])
  2702         return q.push(repo, imported[-1])
  2432     return 0
  2703     return 0
       
  2704 
  2433 
  2705 
  2434 def qinit(ui, repo, create):
  2706 def qinit(ui, repo, create):
  2435     """initialize a new queue repository
  2707     """initialize a new queue repository
  2436 
  2708 
  2437     This command also creates a series file for ordering patches, and
  2709     This command also creates a series file for ordering patches, and
  2455             r.wvfs('series', 'w').close()
  2727             r.wvfs('series', 'w').close()
  2456         r[None].add(['.hgignore', 'series'])
  2728         r[None].add(['.hgignore', 'series'])
  2457         commands.add(ui, r)
  2729         commands.add(ui, r)
  2458     return 0
  2730     return 0
  2459 
  2731 
  2460 @command("qinit",
  2732 
  2461          [('c', 'create-repo', None, _('create queue repository'))],
  2733 @command(
  2462          _('hg qinit [-c]'),
  2734     "qinit",
  2463          helpcategory=command.CATEGORY_REPO_CREATION,
  2735     [('c', 'create-repo', None, _('create queue repository'))],
  2464          helpbasic=True)
  2736     _('hg qinit [-c]'),
       
  2737     helpcategory=command.CATEGORY_REPO_CREATION,
       
  2738     helpbasic=True,
       
  2739 )
  2465 def init(ui, repo, **opts):
  2740 def init(ui, repo, **opts):
  2466     """init a new queue repository (DEPRECATED)
  2741     """init a new queue repository (DEPRECATED)
  2467 
  2742 
  2468     The queue repository is unversioned by default. If
  2743     The queue repository is unversioned by default. If
  2469     -c/--create-repo is specified, qinit will create a separate nested
  2744     -c/--create-repo is specified, qinit will create a separate nested
  2473 
  2748 
  2474     This command is deprecated. Without -c, it's implied by other relevant
  2749     This command is deprecated. Without -c, it's implied by other relevant
  2475     commands. With -c, use :hg:`init --mq` instead."""
  2750     commands. With -c, use :hg:`init --mq` instead."""
  2476     return qinit(ui, repo, create=opts.get(r'create_repo'))
  2751     return qinit(ui, repo, create=opts.get(r'create_repo'))
  2477 
  2752 
  2478 @command("qclone",
  2753 
  2479          [('', 'pull', None, _('use pull protocol to copy metadata')),
  2754 @command(
  2480           ('U', 'noupdate', None,
  2755     "qclone",
  2481            _('do not update the new working directories')),
  2756     [
  2482           ('', 'uncompressed', None,
  2757         ('', 'pull', None, _('use pull protocol to copy metadata')),
  2483            _('use uncompressed transfer (fast over LAN)')),
  2758         ('U', 'noupdate', None, _('do not update the new working directories')),
  2484           ('p', 'patches', '',
  2759         (
  2485            _('location of source patch repository'), _('REPO')),
  2760             '',
  2486          ] + cmdutil.remoteopts,
  2761             'uncompressed',
  2487          _('hg qclone [OPTION]... SOURCE [DEST]'),
  2762             None,
  2488          helpcategory=command.CATEGORY_REPO_CREATION,
  2763             _('use uncompressed transfer (fast over LAN)'),
  2489          norepo=True)
  2764         ),
       
  2765         (
       
  2766             'p',
       
  2767             'patches',
       
  2768             '',
       
  2769             _('location of source patch repository'),
       
  2770             _('REPO'),
       
  2771         ),
       
  2772     ]
       
  2773     + cmdutil.remoteopts,
       
  2774     _('hg qclone [OPTION]... SOURCE [DEST]'),
       
  2775     helpcategory=command.CATEGORY_REPO_CREATION,
       
  2776     norepo=True,
       
  2777 )
  2490 def clone(ui, source, dest=None, **opts):
  2778 def clone(ui, source, dest=None, **opts):
  2491     '''clone main and patch repository at same time
  2779     '''clone main and patch repository at same time
  2492 
  2780 
  2493     If source is local, destination will have no patches applied. If
  2781     If source is local, destination will have no patches applied. If
  2494     source is remote, this command can not check if patches are
  2782     source is remote, this command can not check if patches are
  2503     would be created by :hg:`init --mq`.
  2791     would be created by :hg:`init --mq`.
  2504 
  2792 
  2505     Return 0 on success.
  2793     Return 0 on success.
  2506     '''
  2794     '''
  2507     opts = pycompat.byteskwargs(opts)
  2795     opts = pycompat.byteskwargs(opts)
       
  2796 
  2508     def patchdir(repo):
  2797     def patchdir(repo):
  2509         """compute a patch repo url from a repo object"""
  2798         """compute a patch repo url from a repo object"""
  2510         url = repo.url()
  2799         url = repo.url()
  2511         if url.endswith('/'):
  2800         if url.endswith('/'):
  2512             url = url[:-1]
  2801             url = url[:-1]
  2523     else:
  2812     else:
  2524         patchespath = patchdir(sr)
  2813         patchespath = patchdir(sr)
  2525     try:
  2814     try:
  2526         hg.peer(ui, opts, patchespath)
  2815         hg.peer(ui, opts, patchespath)
  2527     except error.RepoError:
  2816     except error.RepoError:
  2528         raise error.Abort(_('versioned patch repository not found'
  2817         raise error.Abort(
  2529                            ' (see init --mq)'))
  2818             _('versioned patch repository not found' ' (see init --mq)')
       
  2819         )
  2530     qbase, destrev = None, None
  2820     qbase, destrev = None, None
  2531     if sr.local():
  2821     if sr.local():
  2532         repo = sr.local()
  2822         repo = sr.local()
  2533         if repo.mq.applied and repo[qbase].phase() != phases.secret:
  2823         if repo.mq.applied and repo[qbase].phase() != phases.secret:
  2534             qbase = repo.mq.applied[0].node
  2824             qbase = repo.mq.applied[0].node
  2541             qbase = sr.lookup('qbase')
  2831             qbase = sr.lookup('qbase')
  2542         except error.RepoError:
  2832         except error.RepoError:
  2543             pass
  2833             pass
  2544 
  2834 
  2545     ui.note(_('cloning main repository\n'))
  2835     ui.note(_('cloning main repository\n'))
  2546     sr, dr = hg.clone(ui, opts, sr.url(), dest,
  2836     sr, dr = hg.clone(
  2547                       pull=opts.get('pull'),
  2837         ui,
  2548                       revs=destrev,
  2838         opts,
  2549                       update=False,
  2839         sr.url(),
  2550                       stream=opts.get('uncompressed'))
  2840         dest,
       
  2841         pull=opts.get('pull'),
       
  2842         revs=destrev,
       
  2843         update=False,
       
  2844         stream=opts.get('uncompressed'),
       
  2845     )
  2551 
  2846 
  2552     ui.note(_('cloning patch repository\n'))
  2847     ui.note(_('cloning patch repository\n'))
  2553     hg.clone(ui, opts, opts.get('patches') or patchdir(sr), patchdir(dr),
  2848     hg.clone(
  2554              pull=opts.get('pull'), update=not opts.get('noupdate'),
  2849         ui,
  2555              stream=opts.get('uncompressed'))
  2850         opts,
       
  2851         opts.get('patches') or patchdir(sr),
       
  2852         patchdir(dr),
       
  2853         pull=opts.get('pull'),
       
  2854         update=not opts.get('noupdate'),
       
  2855         stream=opts.get('uncompressed'),
       
  2856     )
  2556 
  2857 
  2557     if dr.local():
  2858     if dr.local():
  2558         repo = dr.local()
  2859         repo = dr.local()
  2559         if qbase:
  2860         if qbase:
  2560             ui.note(_('stripping applied patches from destination '
  2861             ui.note(
  2561                       'repository\n'))
  2862                 _('stripping applied patches from destination ' 'repository\n')
       
  2863             )
  2562             strip(ui, repo, [qbase], update=False, backup=None)
  2864             strip(ui, repo, [qbase], update=False, backup=None)
  2563         if not opts.get('noupdate'):
  2865         if not opts.get('noupdate'):
  2564             ui.note(_('updating destination repository\n'))
  2866             ui.note(_('updating destination repository\n'))
  2565             hg.update(repo, repo.changelog.tip())
  2867             hg.update(repo, repo.changelog.tip())
  2566 
  2868 
  2567 @command("qcommit|qci",
  2869 
  2568          commands.table["commit|ci"][1],
  2870 @command(
  2569          _('hg qcommit [OPTION]... [FILE]...'),
  2871     "qcommit|qci",
  2570          helpcategory=command.CATEGORY_COMMITTING,
  2872     commands.table["commit|ci"][1],
  2571          inferrepo=True)
  2873     _('hg qcommit [OPTION]... [FILE]...'),
       
  2874     helpcategory=command.CATEGORY_COMMITTING,
       
  2875     inferrepo=True,
       
  2876 )
  2572 def commit(ui, repo, *pats, **opts):
  2877 def commit(ui, repo, *pats, **opts):
  2573     """commit changes in the queue repository (DEPRECATED)
  2878     """commit changes in the queue repository (DEPRECATED)
  2574 
  2879 
  2575     This command is deprecated; use :hg:`commit --mq` instead."""
  2880     This command is deprecated; use :hg:`commit --mq` instead."""
  2576     q = repo.mq
  2881     q = repo.mq
  2577     r = q.qrepo()
  2882     r = q.qrepo()
  2578     if not r:
  2883     if not r:
  2579         raise error.Abort('no queue repository')
  2884         raise error.Abort('no queue repository')
  2580     commands.commit(r.ui, r, *pats, **opts)
  2885     commands.commit(r.ui, r, *pats, **opts)
  2581 
  2886 
  2582 @command("qseries",
  2887 
  2583          [('m', 'missing', None, _('print patches not in series')),
  2888 @command(
  2584          ] + seriesopts,
  2889     "qseries",
  2585           _('hg qseries [-ms]'),
  2890     [('m', 'missing', None, _('print patches not in series')),] + seriesopts,
  2586          helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
  2891     _('hg qseries [-ms]'),
       
  2892     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
       
  2893 )
  2587 def series(ui, repo, **opts):
  2894 def series(ui, repo, **opts):
  2588     """print the entire series file
  2895     """print the entire series file
  2589 
  2896 
  2590     Returns 0 on success."""
  2897     Returns 0 on success."""
  2591     repo.mq.qseries(repo, missing=opts.get(r'missing'),
  2898     repo.mq.qseries(
  2592                     summary=opts.get(r'summary'))
  2899         repo, missing=opts.get(r'missing'), summary=opts.get(r'summary')
       
  2900     )
  2593     return 0
  2901     return 0
  2594 
  2902 
  2595 @command("qtop", seriesopts, _('hg qtop [-s]'),
  2903 
  2596          helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
  2904 @command(
       
  2905     "qtop",
       
  2906     seriesopts,
       
  2907     _('hg qtop [-s]'),
       
  2908     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
       
  2909 )
  2597 def top(ui, repo, **opts):
  2910 def top(ui, repo, **opts):
  2598     """print the name of the current patch
  2911     """print the name of the current patch
  2599 
  2912 
  2600     Returns 0 on success."""
  2913     Returns 0 on success."""
  2601     q = repo.mq
  2914     q = repo.mq
  2603         t = q.seriesend(True)
  2916         t = q.seriesend(True)
  2604     else:
  2917     else:
  2605         t = 0
  2918         t = 0
  2606 
  2919 
  2607     if t:
  2920     if t:
  2608         q.qseries(repo, start=t - 1, length=1, status='A',
  2921         q.qseries(
  2609                   summary=opts.get(r'summary'))
  2922             repo,
       
  2923             start=t - 1,
       
  2924             length=1,
       
  2925             status='A',
       
  2926             summary=opts.get(r'summary'),
       
  2927         )
  2610     else:
  2928     else:
  2611         ui.write(_("no patches applied\n"))
  2929         ui.write(_("no patches applied\n"))
  2612         return 1
  2930         return 1
  2613 
  2931 
  2614 @command("qnext", seriesopts, _('hg qnext [-s]'),
  2932 
  2615          helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
  2933 @command(
       
  2934     "qnext",
       
  2935     seriesopts,
       
  2936     _('hg qnext [-s]'),
       
  2937     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
       
  2938 )
  2616 def next(ui, repo, **opts):
  2939 def next(ui, repo, **opts):
  2617     """print the name of the next pushable patch
  2940     """print the name of the next pushable patch
  2618 
  2941 
  2619     Returns 0 on success."""
  2942     Returns 0 on success."""
  2620     q = repo.mq
  2943     q = repo.mq
  2622     if end == len(q.series):
  2945     if end == len(q.series):
  2623         ui.write(_("all patches applied\n"))
  2946         ui.write(_("all patches applied\n"))
  2624         return 1
  2947         return 1
  2625     q.qseries(repo, start=end, length=1, summary=opts.get(r'summary'))
  2948     q.qseries(repo, start=end, length=1, summary=opts.get(r'summary'))
  2626 
  2949 
  2627 @command("qprev", seriesopts, _('hg qprev [-s]'),
  2950 
  2628          helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
  2951 @command(
       
  2952     "qprev",
       
  2953     seriesopts,
       
  2954     _('hg qprev [-s]'),
       
  2955     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
       
  2956 )
  2629 def prev(ui, repo, **opts):
  2957 def prev(ui, repo, **opts):
  2630     """print the name of the preceding applied patch
  2958     """print the name of the preceding applied patch
  2631 
  2959 
  2632     Returns 0 on success."""
  2960     Returns 0 on success."""
  2633     q = repo.mq
  2961     q = repo.mq
  2637         return 1
  2965         return 1
  2638     if not l:
  2966     if not l:
  2639         ui.write(_("no patches applied\n"))
  2967         ui.write(_("no patches applied\n"))
  2640         return 1
  2968         return 1
  2641     idx = q.series.index(q.applied[-2].name)
  2969     idx = q.series.index(q.applied[-2].name)
  2642     q.qseries(repo, start=idx, length=1, status='A',
  2970     q.qseries(
  2643               summary=opts.get(r'summary'))
  2971         repo, start=idx, length=1, status='A', summary=opts.get(r'summary')
       
  2972     )
       
  2973 
  2644 
  2974 
  2645 def setupheaderopts(ui, opts):
  2975 def setupheaderopts(ui, opts):
  2646     if not opts.get('user') and opts.get('currentuser'):
  2976     if not opts.get('user') and opts.get('currentuser'):
  2647         opts['user'] = ui.username()
  2977         opts['user'] = ui.username()
  2648     if not opts.get('date') and opts.get('currentdate'):
  2978     if not opts.get('date') and opts.get('currentdate'):
  2649         opts['date'] = "%d %d" % dateutil.makedate()
  2979         opts['date'] = "%d %d" % dateutil.makedate()
  2650 
  2980 
  2651 @command("qnew",
  2981 
  2652          [('e', 'edit', None, _('invoke editor on commit messages')),
  2982 @command(
  2653           ('f', 'force', None, _('import uncommitted changes (DEPRECATED)')),
  2983     "qnew",
  2654           ('g', 'git', None, _('use git extended diff format')),
  2984     [
  2655           ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
  2985         ('e', 'edit', None, _('invoke editor on commit messages')),
  2656           ('u', 'user', '',
  2986         ('f', 'force', None, _('import uncommitted changes (DEPRECATED)')),
  2657            _('add "From: <USER>" to patch'), _('USER')),
  2987         ('g', 'git', None, _('use git extended diff format')),
  2658           ('D', 'currentdate', None, _('add "Date: <current date>" to patch')),
  2988         ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
  2659           ('d', 'date', '',
  2989         ('u', 'user', '', _('add "From: <USER>" to patch'), _('USER')),
  2660            _('add "Date: <DATE>" to patch'), _('DATE'))
  2990         ('D', 'currentdate', None, _('add "Date: <current date>" to patch')),
  2661           ] + cmdutil.walkopts + cmdutil.commitopts,
  2991         ('d', 'date', '', _('add "Date: <DATE>" to patch'), _('DATE')),
  2662          _('hg qnew [-e] [-m TEXT] [-l FILE] PATCH [FILE]...'),
  2992     ]
  2663          helpcategory=command.CATEGORY_COMMITTING, helpbasic=True,
  2993     + cmdutil.walkopts
  2664          inferrepo=True)
  2994     + cmdutil.commitopts,
       
  2995     _('hg qnew [-e] [-m TEXT] [-l FILE] PATCH [FILE]...'),
       
  2996     helpcategory=command.CATEGORY_COMMITTING,
       
  2997     helpbasic=True,
       
  2998     inferrepo=True,
       
  2999 )
  2665 def new(ui, repo, patch, *args, **opts):
  3000 def new(ui, repo, patch, *args, **opts):
  2666     """create a new patch
  3001     """create a new patch
  2667 
  3002 
  2668     qnew creates a new patch on top of the currently-applied patch (if
  3003     qnew creates a new patch on top of the currently-applied patch (if
  2669     any). The patch will be initialized with any outstanding changes
  3004     any). The patch will be initialized with any outstanding changes
  2694     setupheaderopts(ui, opts)
  3029     setupheaderopts(ui, opts)
  2695     q.new(repo, patch, *args, **pycompat.strkwargs(opts))
  3030     q.new(repo, patch, *args, **pycompat.strkwargs(opts))
  2696     q.savedirty()
  3031     q.savedirty()
  2697     return 0
  3032     return 0
  2698 
  3033 
  2699 @command("qrefresh",
  3034 
  2700          [('e', 'edit', None, _('invoke editor on commit messages')),
  3035 @command(
  2701           ('g', 'git', None, _('use git extended diff format')),
  3036     "qrefresh",
  2702           ('s', 'short', None,
  3037     [
  2703            _('refresh only files already in the patch and specified files')),
  3038         ('e', 'edit', None, _('invoke editor on commit messages')),
  2704           ('U', 'currentuser', None,
  3039         ('g', 'git', None, _('use git extended diff format')),
  2705            _('add/update author field in patch with current user')),
  3040         (
  2706           ('u', 'user', '',
  3041             's',
  2707            _('add/update author field in patch with given user'), _('USER')),
  3042             'short',
  2708           ('D', 'currentdate', None,
  3043             None,
  2709            _('add/update date field in patch with current date')),
  3044             _('refresh only files already in the patch and specified files'),
  2710           ('d', 'date', '',
  3045         ),
  2711            _('add/update date field in patch with given date'), _('DATE'))
  3046         (
  2712           ] + cmdutil.walkopts + cmdutil.commitopts,
  3047             'U',
  2713          _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...'),
  3048             'currentuser',
  2714          helpcategory=command.CATEGORY_COMMITTING, helpbasic=True,
  3049             None,
  2715          inferrepo=True)
  3050             _('add/update author field in patch with current user'),
       
  3051         ),
       
  3052         (
       
  3053             'u',
       
  3054             'user',
       
  3055             '',
       
  3056             _('add/update author field in patch with given user'),
       
  3057             _('USER'),
       
  3058         ),
       
  3059         (
       
  3060             'D',
       
  3061             'currentdate',
       
  3062             None,
       
  3063             _('add/update date field in patch with current date'),
       
  3064         ),
       
  3065         (
       
  3066             'd',
       
  3067             'date',
       
  3068             '',
       
  3069             _('add/update date field in patch with given date'),
       
  3070             _('DATE'),
       
  3071         ),
       
  3072     ]
       
  3073     + cmdutil.walkopts
       
  3074     + cmdutil.commitopts,
       
  3075     _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...'),
       
  3076     helpcategory=command.CATEGORY_COMMITTING,
       
  3077     helpbasic=True,
       
  3078     inferrepo=True,
       
  3079 )
  2716 def refresh(ui, repo, *pats, **opts):
  3080 def refresh(ui, repo, *pats, **opts):
  2717     """update the current patch
  3081     """update the current patch
  2718 
  3082 
  2719     If any file patterns are provided, the refreshed patch will
  3083     If any file patterns are provided, the refreshed patch will
  2720     contain only the modifications that match those patterns; the
  3084     contain only the modifications that match those patterns; the
  2741     with repo.wlock():
  3105     with repo.wlock():
  2742         ret = q.refresh(repo, pats, msg=message, **pycompat.strkwargs(opts))
  3106         ret = q.refresh(repo, pats, msg=message, **pycompat.strkwargs(opts))
  2743         q.savedirty()
  3107         q.savedirty()
  2744         return ret
  3108         return ret
  2745 
  3109 
  2746 @command("qdiff",
  3110 
  2747          cmdutil.diffopts + cmdutil.diffopts2 + cmdutil.walkopts,
  3111 @command(
  2748          _('hg qdiff [OPTION]... [FILE]...'),
  3112     "qdiff",
  2749          helpcategory=command.CATEGORY_FILE_CONTENTS, helpbasic=True,
  3113     cmdutil.diffopts + cmdutil.diffopts2 + cmdutil.walkopts,
  2750          inferrepo=True)
  3114     _('hg qdiff [OPTION]... [FILE]...'),
       
  3115     helpcategory=command.CATEGORY_FILE_CONTENTS,
       
  3116     helpbasic=True,
       
  3117     inferrepo=True,
       
  3118 )
  2751 def diff(ui, repo, *pats, **opts):
  3119 def diff(ui, repo, *pats, **opts):
  2752     """diff of the current patch and subsequent modifications
  3120     """diff of the current patch and subsequent modifications
  2753 
  3121 
  2754     Shows a diff which includes the current patch as well as any
  3122     Shows a diff which includes the current patch as well as any
  2755     changes which have been made in the working directory since the
  3123     changes which have been made in the working directory since the
  2765     """
  3133     """
  2766     ui.pager('qdiff')
  3134     ui.pager('qdiff')
  2767     repo.mq.diff(repo, pats, pycompat.byteskwargs(opts))
  3135     repo.mq.diff(repo, pats, pycompat.byteskwargs(opts))
  2768     return 0
  3136     return 0
  2769 
  3137 
  2770 @command('qfold',
  3138 
  2771          [('e', 'edit', None, _('invoke editor on commit messages')),
  3139 @command(
  2772           ('k', 'keep', None, _('keep folded patch files')),
  3140     'qfold',
  2773          ] + cmdutil.commitopts,
  3141     [
  2774          _('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...'),
  3142         ('e', 'edit', None, _('invoke editor on commit messages')),
  2775          helpcategory=command.CATEGORY_CHANGE_MANAGEMENT)
  3143         ('k', 'keep', None, _('keep folded patch files')),
       
  3144     ]
       
  3145     + cmdutil.commitopts,
       
  3146     _('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...'),
       
  3147     helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
       
  3148 )
  2776 def fold(ui, repo, *files, **opts):
  3149 def fold(ui, repo, *files, **opts):
  2777     """fold the named patches into the current patch
  3150     """fold the named patches into the current patch
  2778 
  3151 
  2779     Patches must not yet be applied. Each patch will be successively
  3152     Patches must not yet be applied. Each patch will be successively
  2780     applied to the current patch in the order given. If all the
  3153     applied to the current patch in the order given. If all the
  2803     for f in files:
  3176     for f in files:
  2804         p = q.lookup(f)
  3177         p = q.lookup(f)
  2805         if p in patches or p == parent:
  3178         if p in patches or p == parent:
  2806             ui.warn(_('skipping already folded patch %s\n') % p)
  3179             ui.warn(_('skipping already folded patch %s\n') % p)
  2807         if q.isapplied(p):
  3180         if q.isapplied(p):
  2808             raise error.Abort(_('qfold cannot fold already applied patch %s')
  3181             raise error.Abort(
  2809                              % p)
  3182                 _('qfold cannot fold already applied patch %s') % p
       
  3183             )
  2810         patches.append(p)
  3184         patches.append(p)
  2811 
  3185 
  2812     for p in patches:
  3186     for p in patches:
  2813         if not message:
  3187         if not message:
  2814             ph = patchheader(q.join(p), q.plainmode)
  3188             ph = patchheader(q.join(p), q.plainmode)
  2829                 message.extend(msg)
  3203                 message.extend(msg)
  2830         message = '\n'.join(message)
  3204         message = '\n'.join(message)
  2831 
  3205 
  2832     diffopts = q.patchopts(q.diffopts(), *patches)
  3206     diffopts = q.patchopts(q.diffopts(), *patches)
  2833     with repo.wlock():
  3207     with repo.wlock():
  2834         q.refresh(repo, msg=message, git=diffopts.git, edit=opts.get('edit'),
  3208         q.refresh(
  2835                   editform='mq.qfold')
  3209             repo,
       
  3210             msg=message,
       
  3211             git=diffopts.git,
       
  3212             edit=opts.get('edit'),
       
  3213             editform='mq.qfold',
       
  3214         )
  2836         q.delete(repo, patches, opts)
  3215         q.delete(repo, patches, opts)
  2837         q.savedirty()
  3216         q.savedirty()
  2838 
  3217 
  2839 @command("qgoto",
  3218 
  2840          [('', 'keep-changes', None,
  3219 @command(
  2841            _('tolerate non-conflicting local changes')),
  3220     "qgoto",
  2842           ('f', 'force', None, _('overwrite any local changes')),
  3221     [
  2843           ('', 'no-backup', None, _('do not save backup copies of files'))],
  3222         ('', 'keep-changes', None, _('tolerate non-conflicting local changes')),
  2844          _('hg qgoto [OPTION]... PATCH'),
  3223         ('f', 'force', None, _('overwrite any local changes')),
  2845          helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
  3224         ('', 'no-backup', None, _('do not save backup copies of files')),
       
  3225     ],
       
  3226     _('hg qgoto [OPTION]... PATCH'),
       
  3227     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
       
  3228 )
  2846 def goto(ui, repo, patch, **opts):
  3229 def goto(ui, repo, patch, **opts):
  2847     '''push or pop patches until named patch is at top of stack
  3230     '''push or pop patches until named patch is at top of stack
  2848 
  3231 
  2849     Returns 0 on success.'''
  3232     Returns 0 on success.'''
  2850     opts = pycompat.byteskwargs(opts)
  3233     opts = pycompat.byteskwargs(opts)
  2852     q = repo.mq
  3235     q = repo.mq
  2853     patch = q.lookup(patch)
  3236     patch = q.lookup(patch)
  2854     nobackup = opts.get('no_backup')
  3237     nobackup = opts.get('no_backup')
  2855     keepchanges = opts.get('keep_changes')
  3238     keepchanges = opts.get('keep_changes')
  2856     if q.isapplied(patch):
  3239     if q.isapplied(patch):
  2857         ret = q.pop(repo, patch, force=opts.get('force'), nobackup=nobackup,
  3240         ret = q.pop(
  2858                     keepchanges=keepchanges)
  3241             repo,
       
  3242             patch,
       
  3243             force=opts.get('force'),
       
  3244             nobackup=nobackup,
       
  3245             keepchanges=keepchanges,
       
  3246         )
  2859     else:
  3247     else:
  2860         ret = q.push(repo, patch, force=opts.get('force'), nobackup=nobackup,
  3248         ret = q.push(
  2861                      keepchanges=keepchanges)
  3249             repo,
       
  3250             patch,
       
  3251             force=opts.get('force'),
       
  3252             nobackup=nobackup,
       
  3253             keepchanges=keepchanges,
       
  3254         )
  2862     q.savedirty()
  3255     q.savedirty()
  2863     return ret
  3256     return ret
  2864 
  3257 
  2865 @command("qguard",
  3258 
  2866          [('l', 'list', None, _('list all patches and guards')),
  3259 @command(
  2867           ('n', 'none', None, _('drop all guards'))],
  3260     "qguard",
  2868          _('hg qguard [-l] [-n] [PATCH] [-- [+GUARD]... [-GUARD]...]'),
  3261     [
  2869          helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
  3262         ('l', 'list', None, _('list all patches and guards')),
       
  3263         ('n', 'none', None, _('drop all guards')),
       
  3264     ],
       
  3265     _('hg qguard [-l] [-n] [PATCH] [-- [+GUARD]... [-GUARD]...]'),
       
  3266     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
       
  3267 )
  2870 def guard(ui, repo, *args, **opts):
  3268 def guard(ui, repo, *args, **opts):
  2871     '''set or print guards for a patch
  3269     '''set or print guards for a patch
  2872 
  3270 
  2873     Guards control whether a patch can be pushed. A patch with no
  3271     Guards control whether a patch can be pushed. A patch with no
  2874     guards is always pushed. A patch with a positive guard ("+foo") is
  3272     guards is always pushed. A patch with a positive guard ("+foo") is
  2887 
  3285 
  2888       hg qguard other.patch -- +2.6.17 -stable
  3286       hg qguard other.patch -- +2.6.17 -stable
  2889 
  3287 
  2890     Returns 0 on success.
  3288     Returns 0 on success.
  2891     '''
  3289     '''
       
  3290 
  2892     def status(idx):
  3291     def status(idx):
  2893         guards = q.seriesguards[idx] or ['unguarded']
  3292         guards = q.seriesguards[idx] or ['unguarded']
  2894         if q.series[idx] in applied:
  3293         if q.series[idx] in applied:
  2895             state = 'applied'
  3294             state = 'applied'
  2896         elif q.pushable(idx)[0]:
  3295         elif q.pushable(idx)[0]:
  2908             else:
  3307             else:
  2909                 ui.write(guard, label='qguard.unguarded')
  3308                 ui.write(guard, label='qguard.unguarded')
  2910             if i != len(guards) - 1:
  3309             if i != len(guards) - 1:
  2911                 ui.write(' ')
  3310                 ui.write(' ')
  2912         ui.write('\n')
  3311         ui.write('\n')
       
  3312 
  2913     q = repo.mq
  3313     q = repo.mq
  2914     applied = set(p.name for p in q.applied)
  3314     applied = set(p.name for p in q.applied)
  2915     patch = None
  3315     patch = None
  2916     args = list(args)
  3316     args = list(args)
  2917     if opts.get(r'list'):
  3317     if opts.get(r'list'):
  2918         if args or opts.get(r'none'):
  3318         if args or opts.get(r'none'):
  2919             raise error.Abort(_('cannot mix -l/--list with options or '
  3319             raise error.Abort(
  2920                                'arguments'))
  3320                 _('cannot mix -l/--list with options or ' 'arguments')
       
  3321             )
  2921         for i in pycompat.xrange(len(q.series)):
  3322         for i in pycompat.xrange(len(q.series)):
  2922             status(i)
  3323             status(i)
  2923         return
  3324         return
  2924     if not args or args[0][0:1] in '-+':
  3325     if not args or args[0][0:1] in '-+':
  2925         if not q.applied:
  3326         if not q.applied:
  2936         q.setguards(idx, args)
  3337         q.setguards(idx, args)
  2937         q.savedirty()
  3338         q.savedirty()
  2938     else:
  3339     else:
  2939         status(q.series.index(q.lookup(patch)))
  3340         status(q.series.index(q.lookup(patch)))
  2940 
  3341 
  2941 @command("qheader", [], _('hg qheader [PATCH]'),
  3342 
  2942          helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
  3343 @command(
       
  3344     "qheader",
       
  3345     [],
       
  3346     _('hg qheader [PATCH]'),
       
  3347     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
       
  3348 )
  2943 def header(ui, repo, patch=None):
  3349 def header(ui, repo, patch=None):
  2944     """print the header of the topmost or specified patch
  3350     """print the header of the topmost or specified patch
  2945 
  3351 
  2946     Returns 0 on success."""
  3352     Returns 0 on success."""
  2947     q = repo.mq
  3353     q = repo.mq
  2954             return 1
  3360             return 1
  2955         patch = q.lookup('qtip')
  3361         patch = q.lookup('qtip')
  2956     ph = patchheader(q.join(patch), q.plainmode)
  3362     ph = patchheader(q.join(patch), q.plainmode)
  2957 
  3363 
  2958     ui.write('\n'.join(ph.message) + '\n')
  3364     ui.write('\n'.join(ph.message) + '\n')
       
  3365 
  2959 
  3366 
  2960 def lastsavename(path):
  3367 def lastsavename(path):
  2961     (directory, base) = os.path.split(path)
  3368     (directory, base) = os.path.split(path)
  2962     names = os.listdir(directory)
  3369     names = os.listdir(directory)
  2963     namere = re.compile("%s.([0-9]+)" % base)
  3370     namere = re.compile("%s.([0-9]+)" % base)
  2972                 maxname = f
  3379                 maxname = f
  2973     if maxname:
  3380     if maxname:
  2974         return (os.path.join(directory, maxname), maxindex)
  3381         return (os.path.join(directory, maxname), maxindex)
  2975     return (None, None)
  3382     return (None, None)
  2976 
  3383 
       
  3384 
  2977 def savename(path):
  3385 def savename(path):
  2978     (last, index) = lastsavename(path)
  3386     (last, index) = lastsavename(path)
  2979     if last is None:
  3387     if last is None:
  2980         index = 0
  3388         index = 0
  2981     newpath = path + ".%d" % (index + 1)
  3389     newpath = path + ".%d" % (index + 1)
  2982     return newpath
  3390     return newpath
  2983 
  3391 
  2984 @command("qpush",
  3392 
  2985          [('', 'keep-changes', None,
  3393 @command(
  2986            _('tolerate non-conflicting local changes')),
  3394     "qpush",
  2987           ('f', 'force', None, _('apply on top of local changes')),
  3395     [
  2988           ('e', 'exact', None,
  3396         ('', 'keep-changes', None, _('tolerate non-conflicting local changes')),
  2989            _('apply the target patch to its recorded parent')),
  3397         ('f', 'force', None, _('apply on top of local changes')),
  2990           ('l', 'list', None, _('list patch name in commit text')),
  3398         (
  2991           ('a', 'all', None, _('apply all patches')),
  3399             'e',
  2992           ('m', 'merge', None, _('merge from another queue (DEPRECATED)')),
  3400             'exact',
  2993           ('n', 'name', '',
  3401             None,
  2994            _('merge queue name (DEPRECATED)'), _('NAME')),
  3402             _('apply the target patch to its recorded parent'),
  2995           ('', 'move', None,
  3403         ),
  2996            _('reorder patch series and apply only the patch')),
  3404         ('l', 'list', None, _('list patch name in commit text')),
  2997           ('', 'no-backup', None, _('do not save backup copies of files'))],
  3405         ('a', 'all', None, _('apply all patches')),
  2998          _('hg qpush [-f] [-l] [-a] [--move] [PATCH | INDEX]'),
  3406         ('m', 'merge', None, _('merge from another queue (DEPRECATED)')),
  2999          helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  3407         ('n', 'name', '', _('merge queue name (DEPRECATED)'), _('NAME')),
  3000          helpbasic=True)
  3408         ('', 'move', None, _('reorder patch series and apply only the patch')),
       
  3409         ('', 'no-backup', None, _('do not save backup copies of files')),
       
  3410     ],
       
  3411     _('hg qpush [-f] [-l] [-a] [--move] [PATCH | INDEX]'),
       
  3412     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
       
  3413     helpbasic=True,
       
  3414 )
  3001 def push(ui, repo, patch=None, **opts):
  3415 def push(ui, repo, patch=None, **opts):
  3002     """push the next patch onto the stack
  3416     """push the next patch onto the stack
  3003 
  3417 
  3004     By default, abort if the working directory contains uncommitted
  3418     By default, abort if the working directory contains uncommitted
  3005     changes. With --keep-changes, abort only if the uncommitted files
  3419     changes. With --keep-changes, abort only if the uncommitted files
  3021         if not newpath:
  3435         if not newpath:
  3022             ui.warn(_("no saved queues found, please use -n\n"))
  3436             ui.warn(_("no saved queues found, please use -n\n"))
  3023             return 1
  3437             return 1
  3024         mergeq = queue(ui, repo.baseui, repo.path, newpath)
  3438         mergeq = queue(ui, repo.baseui, repo.path, newpath)
  3025         ui.warn(_("merging with queue at: %s\n") % mergeq.path)
  3439         ui.warn(_("merging with queue at: %s\n") % mergeq.path)
  3026     ret = q.push(repo, patch, force=opts.get('force'), list=opts.get('list'),
  3440     ret = q.push(
  3027                  mergeq=mergeq, all=opts.get('all'), move=opts.get('move'),
  3441         repo,
  3028                  exact=opts.get('exact'), nobackup=opts.get('no_backup'),
  3442         patch,
  3029                  keepchanges=opts.get('keep_changes'))
  3443         force=opts.get('force'),
       
  3444         list=opts.get('list'),
       
  3445         mergeq=mergeq,
       
  3446         all=opts.get('all'),
       
  3447         move=opts.get('move'),
       
  3448         exact=opts.get('exact'),
       
  3449         nobackup=opts.get('no_backup'),
       
  3450         keepchanges=opts.get('keep_changes'),
       
  3451     )
  3030     return ret
  3452     return ret
  3031 
  3453 
  3032 @command("qpop",
  3454 
  3033          [('a', 'all', None, _('pop all patches')),
  3455 @command(
  3034           ('n', 'name', '',
  3456     "qpop",
  3035            _('queue name to pop (DEPRECATED)'), _('NAME')),
  3457     [
  3036           ('', 'keep-changes', None,
  3458         ('a', 'all', None, _('pop all patches')),
  3037            _('tolerate non-conflicting local changes')),
  3459         ('n', 'name', '', _('queue name to pop (DEPRECATED)'), _('NAME')),
  3038           ('f', 'force', None, _('forget any local changes to patched files')),
  3460         ('', 'keep-changes', None, _('tolerate non-conflicting local changes')),
  3039           ('', 'no-backup', None, _('do not save backup copies of files'))],
  3461         ('f', 'force', None, _('forget any local changes to patched files')),
  3040          _('hg qpop [-a] [-f] [PATCH | INDEX]'),
  3462         ('', 'no-backup', None, _('do not save backup copies of files')),
  3041          helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
  3463     ],
  3042          helpbasic=True)
  3464     _('hg qpop [-a] [-f] [PATCH | INDEX]'),
       
  3465     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
       
  3466     helpbasic=True,
       
  3467 )
  3043 def pop(ui, repo, patch=None, **opts):
  3468 def pop(ui, repo, patch=None, **opts):
  3044     """pop the current patch off the stack
  3469     """pop the current patch off the stack
  3045 
  3470 
  3046     Without argument, pops off the top of the patch stack. If given a
  3471     Without argument, pops off the top of the patch stack. If given a
  3047     patch name, keeps popping off patches until the named patch is at
  3472     patch name, keeps popping off patches until the named patch is at
  3061         q = queue(ui, repo.baseui, repo.path, repo.vfs.join(opts.get('name')))
  3486         q = queue(ui, repo.baseui, repo.path, repo.vfs.join(opts.get('name')))
  3062         ui.warn(_('using patch queue: %s\n') % q.path)
  3487         ui.warn(_('using patch queue: %s\n') % q.path)
  3063         localupdate = False
  3488         localupdate = False
  3064     else:
  3489     else:
  3065         q = repo.mq
  3490         q = repo.mq
  3066     ret = q.pop(repo, patch, force=opts.get('force'), update=localupdate,
  3491     ret = q.pop(
  3067                 all=opts.get('all'), nobackup=opts.get('no_backup'),
  3492         repo,
  3068                 keepchanges=opts.get('keep_changes'))
  3493         patch,
       
  3494         force=opts.get('force'),
       
  3495         update=localupdate,
       
  3496         all=opts.get('all'),
       
  3497         nobackup=opts.get('no_backup'),
       
  3498         keepchanges=opts.get('keep_changes'),
       
  3499     )
  3069     q.savedirty()
  3500     q.savedirty()
  3070     return ret
  3501     return ret
  3071 
  3502 
  3072 @command("qrename|qmv", [], _('hg qrename PATCH1 [PATCH2]'),
  3503 
  3073          helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
  3504 @command(
       
  3505     "qrename|qmv",
       
  3506     [],
       
  3507     _('hg qrename PATCH1 [PATCH2]'),
       
  3508     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
       
  3509 )
  3074 def rename(ui, repo, patch, name=None, **opts):
  3510 def rename(ui, repo, patch, name=None, **opts):
  3075     """rename a patch
  3511     """rename a patch
  3076 
  3512 
  3077     With one argument, renames the current patch to PATCH1.
  3513     With one argument, renames the current patch to PATCH1.
  3078     With two arguments, renames PATCH1 to PATCH2.
  3514     With two arguments, renames PATCH1 to PATCH2.
  3123                 wctx.copy(patch, name)
  3559                 wctx.copy(patch, name)
  3124                 wctx.forget([patch])
  3560                 wctx.forget([patch])
  3125 
  3561 
  3126     q.savedirty()
  3562     q.savedirty()
  3127 
  3563 
  3128 @command("qrestore",
  3564 
  3129          [('d', 'delete', None, _('delete save entry')),
  3565 @command(
  3130           ('u', 'update', None, _('update queue working directory'))],
  3566     "qrestore",
  3131          _('hg qrestore [-d] [-u] REV'),
  3567     [
  3132          helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
  3568         ('d', 'delete', None, _('delete save entry')),
       
  3569         ('u', 'update', None, _('update queue working directory')),
       
  3570     ],
       
  3571     _('hg qrestore [-d] [-u] REV'),
       
  3572     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
       
  3573 )
  3133 def restore(ui, repo, rev, **opts):
  3574 def restore(ui, repo, rev, **opts):
  3134     """restore the queue state saved by a revision (DEPRECATED)
  3575     """restore the queue state saved by a revision (DEPRECATED)
  3135 
  3576 
  3136     This command is deprecated, use :hg:`rebase` instead."""
  3577     This command is deprecated, use :hg:`rebase` instead."""
  3137     rev = repo.lookup(rev)
  3578     rev = repo.lookup(rev)
  3138     q = repo.mq
  3579     q = repo.mq
  3139     q.restore(repo, rev, delete=opts.get(r'delete'),
  3580     q.restore(
  3140               qupdate=opts.get(r'update'))
  3581         repo, rev, delete=opts.get(r'delete'), qupdate=opts.get(r'update')
       
  3582     )
  3141     q.savedirty()
  3583     q.savedirty()
  3142     return 0
  3584     return 0
  3143 
  3585 
  3144 @command("qsave",
  3586 
  3145          [('c', 'copy', None, _('copy patch directory')),
  3587 @command(
  3146           ('n', 'name', '',
  3588     "qsave",
  3147            _('copy directory name'), _('NAME')),
  3589     [
  3148           ('e', 'empty', None, _('clear queue status file')),
  3590         ('c', 'copy', None, _('copy patch directory')),
  3149           ('f', 'force', None, _('force copy'))] + cmdutil.commitopts,
  3591         ('n', 'name', '', _('copy directory name'), _('NAME')),
  3150          _('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'),
  3592         ('e', 'empty', None, _('clear queue status file')),
  3151          helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
  3593         ('f', 'force', None, _('force copy')),
       
  3594     ]
       
  3595     + cmdutil.commitopts,
       
  3596     _('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'),
       
  3597     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
       
  3598 )
  3152 def save(ui, repo, **opts):
  3599 def save(ui, repo, **opts):
  3153     """save current queue state (DEPRECATED)
  3600     """save current queue state (DEPRECATED)
  3154 
  3601 
  3155     This command is deprecated, use :hg:`rebase` instead."""
  3602     This command is deprecated, use :hg:`rebase` instead."""
  3156     q = repo.mq
  3603     q = repo.mq
  3157     opts = pycompat.byteskwargs(opts)
  3604     opts = pycompat.byteskwargs(opts)
  3158     message = cmdutil.logmessage(ui, opts)
  3605     message = cmdutil.logmessage(ui, opts)
  3159     ret = q.save(repo, msg=message)
  3606     ret = q.save(repo, msg=message)
  3160     if ret:
  3607     if ret:
  3161         return ret
  3608         return ret
  3162     q.savedirty() # save to .hg/patches before copying
  3609     q.savedirty()  # save to .hg/patches before copying
  3163     if opts.get('copy'):
  3610     if opts.get('copy'):
  3164         path = q.path
  3611         path = q.path
  3165         if opts.get('name'):
  3612         if opts.get('name'):
  3166             newpath = os.path.join(q.basepath, opts.get('name'))
  3613             newpath = os.path.join(q.basepath, opts.get('name'))
  3167             if os.path.exists(newpath):
  3614             if os.path.exists(newpath):
  3168                 if not os.path.isdir(newpath):
  3615                 if not os.path.isdir(newpath):
  3169                     raise error.Abort(_('destination %s exists and is not '
  3616                     raise error.Abort(
  3170                                        'a directory') % newpath)
  3617                         _('destination %s exists and is not ' 'a directory')
       
  3618                         % newpath
       
  3619                     )
  3171                 if not opts.get('force'):
  3620                 if not opts.get('force'):
  3172                     raise error.Abort(_('destination %s exists, '
  3621                     raise error.Abort(
  3173                                        'use -f to force') % newpath)
  3622                         _('destination %s exists, ' 'use -f to force') % newpath
       
  3623                     )
  3174         else:
  3624         else:
  3175             newpath = savename(path)
  3625             newpath = savename(path)
  3176         ui.warn(_("copy %s to %s\n") % (path, newpath))
  3626         ui.warn(_("copy %s to %s\n") % (path, newpath))
  3177         util.copyfiles(path, newpath)
  3627         util.copyfiles(path, newpath)
  3178     if opts.get('empty'):
  3628     if opts.get('empty'):
  3180         q.applieddirty = True
  3630         q.applieddirty = True
  3181         q.savedirty()
  3631         q.savedirty()
  3182     return 0
  3632     return 0
  3183 
  3633 
  3184 
  3634 
  3185 @command("qselect",
  3635 @command(
  3186          [('n', 'none', None, _('disable all guards')),
  3636     "qselect",
  3187           ('s', 'series', None, _('list all guards in series file')),
  3637     [
  3188           ('', 'pop', None, _('pop to before first guarded applied patch')),
  3638         ('n', 'none', None, _('disable all guards')),
  3189           ('', 'reapply', None, _('pop, then reapply patches'))],
  3639         ('s', 'series', None, _('list all guards in series file')),
  3190          _('hg qselect [OPTION]... [GUARD]...'),
  3640         ('', 'pop', None, _('pop to before first guarded applied patch')),
  3191          helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
  3641         ('', 'reapply', None, _('pop, then reapply patches')),
       
  3642     ],
       
  3643     _('hg qselect [OPTION]... [GUARD]...'),
       
  3644     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
       
  3645 )
  3192 def select(ui, repo, *args, **opts):
  3646 def select(ui, repo, *args, **opts):
  3193     '''set or print guarded patches to push
  3647     '''set or print guarded patches to push
  3194 
  3648 
  3195     Use the :hg:`qguard` command to set or print guards on patch, then use
  3649     Use the :hg:`qguard` command to set or print guards on patch, then use
  3196     qselect to tell mq which guards to use. A patch will be pushed if
  3650     qselect to tell mq which guards to use. A patch will be pushed if
  3228     opts = pycompat.byteskwargs(opts)
  3682     opts = pycompat.byteskwargs(opts)
  3229     guards = q.active()
  3683     guards = q.active()
  3230     pushable = lambda i: q.pushable(q.applied[i].name)[0]
  3684     pushable = lambda i: q.pushable(q.applied[i].name)[0]
  3231     if args or opts.get('none'):
  3685     if args or opts.get('none'):
  3232         old_unapplied = q.unapplied(repo)
  3686         old_unapplied = q.unapplied(repo)
  3233         old_guarded = [i for i in pycompat.xrange(len(q.applied))
  3687         old_guarded = [
  3234                        if not pushable(i)]
  3688             i for i in pycompat.xrange(len(q.applied)) if not pushable(i)
       
  3689         ]
  3235         q.setactive(args)
  3690         q.setactive(args)
  3236         q.savedirty()
  3691         q.savedirty()
  3237         if not args:
  3692         if not args:
  3238             ui.status(_('guards deactivated\n'))
  3693             ui.status(_('guards deactivated\n'))
  3239         if not opts.get('pop') and not opts.get('reapply'):
  3694         if not opts.get('pop') and not opts.get('reapply'):
  3240             unapplied = q.unapplied(repo)
  3695             unapplied = q.unapplied(repo)
  3241             guarded = [i for i in pycompat.xrange(len(q.applied))
  3696             guarded = [
  3242                        if not pushable(i)]
  3697                 i for i in pycompat.xrange(len(q.applied)) if not pushable(i)
       
  3698             ]
  3243             if len(unapplied) != len(old_unapplied):
  3699             if len(unapplied) != len(old_unapplied):
  3244                 ui.status(_('number of unguarded, unapplied patches has '
  3700                 ui.status(
  3245                             'changed from %d to %d\n') %
  3701                     _(
  3246                           (len(old_unapplied), len(unapplied)))
  3702                         'number of unguarded, unapplied patches has '
       
  3703                         'changed from %d to %d\n'
       
  3704                     )
       
  3705                     % (len(old_unapplied), len(unapplied))
       
  3706                 )
  3247             if len(guarded) != len(old_guarded):
  3707             if len(guarded) != len(old_guarded):
  3248                 ui.status(_('number of guarded, applied patches has changed '
  3708                 ui.status(
  3249                             'from %d to %d\n') %
  3709                     _(
  3250                           (len(old_guarded), len(guarded)))
  3710                         'number of guarded, applied patches has changed '
       
  3711                         'from %d to %d\n'
       
  3712                     )
       
  3713                     % (len(old_guarded), len(guarded))
       
  3714                 )
  3251     elif opts.get('series'):
  3715     elif opts.get('series'):
  3252         guards = {}
  3716         guards = {}
  3253         noguards = 0
  3717         noguards = 0
  3254         for gs in q.seriesguards:
  3718         for gs in q.seriesguards:
  3255             if not gs:
  3719             if not gs:
  3293                 ui.status(_('reapplying unguarded patches\n'))
  3757                 ui.status(_('reapplying unguarded patches\n'))
  3294                 q.push(repo, reapply)
  3758                 q.push(repo, reapply)
  3295         finally:
  3759         finally:
  3296             q.savedirty()
  3760             q.savedirty()
  3297 
  3761 
  3298 @command("qfinish",
  3762 
  3299          [('a', 'applied', None, _('finish all applied changesets'))],
  3763 @command(
  3300          _('hg qfinish [-a] [REV]...'),
  3764     "qfinish",
  3301          helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
  3765     [('a', 'applied', None, _('finish all applied changesets'))],
       
  3766     _('hg qfinish [-a] [REV]...'),
       
  3767     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
       
  3768 )
  3302 def finish(ui, repo, *revrange, **opts):
  3769 def finish(ui, repo, *revrange, **opts):
  3303     """move applied patches into repository history
  3770     """move applied patches into repository history
  3304 
  3771 
  3305     Finishes the specified revisions (corresponding to applied
  3772     Finishes the specified revisions (corresponding to applied
  3306     patches) by moving them out of mq control into regular repository
  3773     patches) by moving them out of mq control into regular repository
  3336     with repo.lock():
  3803     with repo.lock():
  3337         q.finish(repo, revs)
  3804         q.finish(repo, revs)
  3338         q.savedirty()
  3805         q.savedirty()
  3339     return 0
  3806     return 0
  3340 
  3807 
  3341 @command("qqueue",
  3808 
  3342          [('l', 'list', False, _('list all available queues')),
  3809 @command(
  3343           ('', 'active', False, _('print name of active queue')),
  3810     "qqueue",
  3344           ('c', 'create', False, _('create new queue')),
  3811     [
  3345           ('', 'rename', False, _('rename active queue')),
  3812         ('l', 'list', False, _('list all available queues')),
  3346           ('', 'delete', False, _('delete reference to queue')),
  3813         ('', 'active', False, _('print name of active queue')),
  3347           ('', 'purge', False, _('delete queue, and remove patch dir')),
  3814         ('c', 'create', False, _('create new queue')),
  3348          ],
  3815         ('', 'rename', False, _('rename active queue')),
  3349          _('[OPTION] [QUEUE]'),
  3816         ('', 'delete', False, _('delete reference to queue')),
  3350          helpcategory=command.CATEGORY_CHANGE_ORGANIZATION)
  3817         ('', 'purge', False, _('delete queue, and remove patch dir')),
       
  3818     ],
       
  3819     _('[OPTION] [QUEUE]'),
       
  3820     helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
       
  3821 )
  3351 def qqueue(ui, repo, name=None, **opts):
  3822 def qqueue(ui, repo, name=None, **opts):
  3352     '''manage multiple patch queues
  3823     '''manage multiple patch queues
  3353 
  3824 
  3354     Supports switching between different patch queues, as well as creating
  3825     Supports switching between different patch queues, as well as creating
  3355     new patch queues and deleting existing ones.
  3826     new patch queues and deleting existing ones.
  3403 
  3874 
  3404         return sorted(queues)
  3875         return sorted(queues)
  3405 
  3876 
  3406     def _setactive(name):
  3877     def _setactive(name):
  3407         if q.applied:
  3878         if q.applied:
  3408             raise error.Abort(_('new queue created, but cannot make active '
  3879             raise error.Abort(
  3409                                'as patches are applied'))
  3880                 _(
       
  3881                     'new queue created, but cannot make active '
       
  3882                     'as patches are applied'
       
  3883                 )
       
  3884             )
  3410         _setactivenocheck(name)
  3885         _setactivenocheck(name)
  3411 
  3886 
  3412     def _setactivenocheck(name):
  3887     def _setactivenocheck(name):
  3413         fh = repo.vfs(_activequeue, 'w')
  3888         fh = repo.vfs(_activequeue, 'w')
  3414         if name != 'patches':
  3889         if name != 'patches':
  3463                 ui.write('\n')
  3938                 ui.write('\n')
  3464         return
  3939         return
  3465 
  3940 
  3466     if not _validname(name):
  3941     if not _validname(name):
  3467         raise error.Abort(
  3942         raise error.Abort(
  3468                 _('invalid queue name, may not contain the characters ":\\/."'))
  3943             _('invalid queue name, may not contain the characters ":\\/."')
       
  3944         )
  3469 
  3945 
  3470     with repo.wlock():
  3946     with repo.wlock():
  3471         existing = _getqueues()
  3947         existing = _getqueues()
  3472 
  3948 
  3473         if opts.get('create'):
  3949         if opts.get('create'):
  3478             _addqueue(name)
  3954             _addqueue(name)
  3479             _setactive(name)
  3955             _setactive(name)
  3480         elif opts.get('rename'):
  3956         elif opts.get('rename'):
  3481             current = _getcurrent()
  3957             current = _getcurrent()
  3482             if name == current:
  3958             if name == current:
  3483                 raise error.Abort(_('can\'t rename "%s" to its current name')
  3959                 raise error.Abort(
  3484                                   % name)
  3960                     _('can\'t rename "%s" to its current name') % name
       
  3961                 )
  3485             if name in existing:
  3962             if name in existing:
  3486                 raise error.Abort(_('queue "%s" already exists') % name)
  3963                 raise error.Abort(_('queue "%s" already exists') % name)
  3487 
  3964 
  3488             olddir = _queuedir(current)
  3965             olddir = _queuedir(current)
  3489             newdir = _queuedir(name)
  3966             newdir = _queuedir(name)
  3490 
  3967 
  3491             if os.path.exists(newdir):
  3968             if os.path.exists(newdir):
  3492                 raise error.Abort(_('non-queue directory "%s" already exists') %
  3969                 raise error.Abort(
  3493                         newdir)
  3970                     _('non-queue directory "%s" already exists') % newdir
       
  3971                 )
  3494 
  3972 
  3495             fh = repo.vfs('patches.queues.new', 'w')
  3973             fh = repo.vfs('patches.queues.new', 'w')
  3496             for queue in existing:
  3974             for queue in existing:
  3497                 if queue == current:
  3975                 if queue == current:
  3498                     fh.write('%s\n' % (name,))
  3976                     fh.write('%s\n' % (name,))
  3514         else:
  3992         else:
  3515             if name not in existing:
  3993             if name not in existing:
  3516                 raise error.Abort(_('use --create to create a new queue'))
  3994                 raise error.Abort(_('use --create to create a new queue'))
  3517             _setactive(name)
  3995             _setactive(name)
  3518 
  3996 
       
  3997 
  3519 def mqphasedefaults(repo, roots):
  3998 def mqphasedefaults(repo, roots):
  3520     """callback used to set mq changeset as secret when no phase data exists"""
  3999     """callback used to set mq changeset as secret when no phase data exists"""
  3521     if repo.mq.applied:
  4000     if repo.mq.applied:
  3522         if repo.ui.configbool('mq', 'secret'):
  4001         if repo.ui.configbool('mq', 'secret'):
  3523             mqphase = phases.secret
  4002             mqphase = phases.secret
  3525             mqphase = phases.draft
  4004             mqphase = phases.draft
  3526         qbase = repo[repo.mq.applied[0].node]
  4005         qbase = repo[repo.mq.applied[0].node]
  3527         roots[mqphase].add(qbase.node())
  4006         roots[mqphase].add(qbase.node())
  3528     return roots
  4007     return roots
  3529 
  4008 
       
  4009 
  3530 def reposetup(ui, repo):
  4010 def reposetup(ui, repo):
  3531     class mqrepo(repo.__class__):
  4011     class mqrepo(repo.__class__):
  3532         @localrepo.unfilteredpropertycache
  4012         @localrepo.unfilteredpropertycache
  3533         def mq(self):
  4013         def mq(self):
  3534             return queue(self.ui, self.baseui, self.path)
  4014             return queue(self.ui, self.baseui, self.path)
  3544                 parents = self.dirstate.parents()
  4024                 parents = self.dirstate.parents()
  3545                 patches = [s.node for s in self.mq.applied]
  4025                 patches = [s.node for s in self.mq.applied]
  3546                 if any(p in patches for p in parents):
  4026                 if any(p in patches for p in parents):
  3547                     raise error.Abort(errmsg)
  4027                     raise error.Abort(errmsg)
  3548 
  4028 
  3549         def commit(self, text="", user=None, date=None, match=None,
  4029         def commit(
  3550                    force=False, editor=False, extra=None):
  4030             self,
       
  4031             text="",
       
  4032             user=None,
       
  4033             date=None,
       
  4034             match=None,
       
  4035             force=False,
       
  4036             editor=False,
       
  4037             extra=None,
       
  4038         ):
  3551             if extra is None:
  4039             if extra is None:
  3552                 extra = {}
  4040                 extra = {}
  3553             self.abortifwdirpatched(
  4041             self.abortifwdirpatched(
  3554                 _('cannot commit over an applied mq patch'),
  4042                 _('cannot commit over an applied mq patch'), force
  3555                 force)
  4043             )
  3556 
  4044 
  3557             return super(mqrepo, self).commit(text, user, date, match, force,
  4045             return super(mqrepo, self).commit(
  3558                                               editor, extra)
  4046                 text, user, date, match, force, editor, extra
       
  4047             )
  3559 
  4048 
  3560         def checkpush(self, pushop):
  4049         def checkpush(self, pushop):
  3561             if self.mq.applied and self.mq.checkapplied and not pushop.force:
  4050             if self.mq.applied and self.mq.checkapplied and not pushop.force:
  3562                 outapplied = [e.node for e in self.mq.applied]
  4051                 outapplied = [e.node for e in self.mq.applied]
  3563                 if pushop.revs:
  4052                 if pushop.revs:
  3589 
  4078 
  3590             try:
  4079             try:
  3591                 # for now ignore filtering business
  4080                 # for now ignore filtering business
  3592                 self.unfiltered().changelog.rev(mqtags[-1][0])
  4081                 self.unfiltered().changelog.rev(mqtags[-1][0])
  3593             except error.LookupError:
  4082             except error.LookupError:
  3594                 self.ui.warn(_('mq status file refers to unknown node %s\n')
  4083                 self.ui.warn(
  3595                              % short(mqtags[-1][0]))
  4084                     _('mq status file refers to unknown node %s\n')
       
  4085                     % short(mqtags[-1][0])
       
  4086                 )
  3596                 return result
  4087                 return result
  3597 
  4088 
  3598             # do not add fake tags for filtered revisions
  4089             # do not add fake tags for filtered revisions
  3599             included = self.changelog.hasnode
  4090             included = self.changelog.hasnode
  3600             mqtags = [mqt for mqt in mqtags if included(mqt[0])]
  4091             mqtags = [mqt for mqt in mqtags if included(mqt[0])]
  3605             mqtags.append((mqtags[0][0], 'qbase'))
  4096             mqtags.append((mqtags[0][0], 'qbase'))
  3606             mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
  4097             mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
  3607             tags = result[0]
  4098             tags = result[0]
  3608             for patch in mqtags:
  4099             for patch in mqtags:
  3609                 if patch[1] in tags:
  4100                 if patch[1] in tags:
  3610                     self.ui.warn(_('tag %s overrides mq patch of the same '
  4101                     self.ui.warn(
  3611                                    'name\n') % patch[1])
  4102                         _('tag %s overrides mq patch of the same ' 'name\n')
       
  4103                         % patch[1]
       
  4104                     )
  3612                 else:
  4105                 else:
  3613                     tags[patch[1]] = patch[0]
  4106                     tags[patch[1]] = patch[0]
  3614 
  4107 
  3615             return result
  4108             return result
  3616 
  4109 
  3617     if repo.local():
  4110     if repo.local():
  3618         repo.__class__ = mqrepo
  4111         repo.__class__ = mqrepo
  3619 
  4112 
  3620         repo._phasedefaults.append(mqphasedefaults)
  4113         repo._phasedefaults.append(mqphasedefaults)
  3621 
  4114 
       
  4115 
  3622 def mqimport(orig, ui, repo, *args, **kwargs):
  4116 def mqimport(orig, ui, repo, *args, **kwargs):
  3623     if (util.safehasattr(repo, 'abortifwdirpatched')
  4117     if util.safehasattr(repo, 'abortifwdirpatched') and not kwargs.get(
  3624         and not kwargs.get(r'no_commit', False)):
  4118         r'no_commit', False
  3625         repo.abortifwdirpatched(_('cannot import over an applied patch'),
  4119     ):
  3626                                    kwargs.get(r'force'))
  4120         repo.abortifwdirpatched(
       
  4121             _('cannot import over an applied patch'), kwargs.get(r'force')
       
  4122         )
  3627     return orig(ui, repo, *args, **kwargs)
  4123     return orig(ui, repo, *args, **kwargs)
       
  4124 
  3628 
  4125 
  3629 def mqinit(orig, ui, *args, **kwargs):
  4126 def mqinit(orig, ui, *args, **kwargs):
  3630     mq = kwargs.pop(r'mq', None)
  4127     mq = kwargs.pop(r'mq', None)
  3631 
  4128 
  3632     if not mq:
  4129     if not mq:
  3633         return orig(ui, *args, **kwargs)
  4130         return orig(ui, *args, **kwargs)
  3634 
  4131 
  3635     if args:
  4132     if args:
  3636         repopath = args[0]
  4133         repopath = args[0]
  3637         if not hg.islocal(repopath):
  4134         if not hg.islocal(repopath):
  3638             raise error.Abort(_('only a local queue repository '
  4135             raise error.Abort(
  3639                                'may be initialized'))
  4136                 _('only a local queue repository ' 'may be initialized')
       
  4137             )
  3640     else:
  4138     else:
  3641         repopath = cmdutil.findrepo(encoding.getcwd())
  4139         repopath = cmdutil.findrepo(encoding.getcwd())
  3642         if not repopath:
  4140         if not repopath:
  3643             raise error.Abort(_('there is no Mercurial repository here '
  4141             raise error.Abort(
  3644                                '(.hg not found)'))
  4142                 _('there is no Mercurial repository here ' '(.hg not found)')
       
  4143             )
  3645     repo = hg.repository(ui, repopath)
  4144     repo = hg.repository(ui, repopath)
  3646     return qinit(ui, repo, True)
  4145     return qinit(ui, repo, True)
       
  4146 
  3647 
  4147 
  3648 def mqcommand(orig, ui, repo, *args, **kwargs):
  4148 def mqcommand(orig, ui, repo, *args, **kwargs):
  3649     """Add --mq option to operate on patch repository instead of main"""
  4149     """Add --mq option to operate on patch repository instead of main"""
  3650 
  4150 
  3651     # some commands do not like getting unknown options
  4151     # some commands do not like getting unknown options
  3657     q = repo.mq
  4157     q = repo.mq
  3658     r = q.qrepo()
  4158     r = q.qrepo()
  3659     if not r:
  4159     if not r:
  3660         raise error.Abort(_('no queue repository'))
  4160         raise error.Abort(_('no queue repository'))
  3661     return orig(r.ui, r, *args, **kwargs)
  4161     return orig(r.ui, r, *args, **kwargs)
       
  4162 
  3662 
  4163 
  3663 def summaryhook(ui, repo):
  4164 def summaryhook(ui, repo):
  3664     q = repo.mq
  4165     q = repo.mq
  3665     m = []
  4166     m = []
  3666     a, u = len(q.applied), len(q.unapplied(repo))
  4167     a, u = len(q.applied), len(q.unapplied(repo))
  3673         ui.write(_("mq:     %s\n") % ', '.join(m))
  4174         ui.write(_("mq:     %s\n") % ', '.join(m))
  3674     else:
  4175     else:
  3675         # i18n: column positioning for "hg summary"
  4176         # i18n: column positioning for "hg summary"
  3676         ui.note(_("mq:     (empty queue)\n"))
  4177         ui.note(_("mq:     (empty queue)\n"))
  3677 
  4178 
       
  4179 
  3678 revsetpredicate = registrar.revsetpredicate()
  4180 revsetpredicate = registrar.revsetpredicate()
       
  4181 
  3679 
  4182 
  3680 @revsetpredicate('mq()')
  4183 @revsetpredicate('mq()')
  3681 def revsetmq(repo, subset, x):
  4184 def revsetmq(repo, subset, x):
  3682     """Changesets managed by MQ.
  4185     """Changesets managed by MQ.
  3683     """
  4186     """
  3684     revsetlang.getargs(x, 0, 0, _("mq takes no arguments"))
  4187     revsetlang.getargs(x, 0, 0, _("mq takes no arguments"))
  3685     applied = {repo[r.node].rev() for r in repo.mq.applied}
  4188     applied = {repo[r.node].rev() for r in repo.mq.applied}
  3686     return smartset.baseset([r for r in subset if r in applied])
  4189     return smartset.baseset([r for r in subset if r in applied])
  3687 
  4190 
       
  4191 
  3688 # tell hggettext to extract docstrings from these functions:
  4192 # tell hggettext to extract docstrings from these functions:
  3689 i18nfunctions = [revsetmq]
  4193 i18nfunctions = [revsetmq]
       
  4194 
  3690 
  4195 
  3691 def extsetup(ui):
  4196 def extsetup(ui):
  3692     # Ensure mq wrappers are called first, regardless of extension load order by
  4197     # Ensure mq wrappers are called first, regardless of extension load order by
  3693     # NOT wrapping in uisetup() and instead deferring to init stage two here.
  4198     # NOT wrapping in uisetup() and instead deferring to init stage two here.
  3694     mqopt = [('', 'mq', None, _("operate on patch repository"))]
  4199     mqopt = [('', 'mq', None, _("operate on patch repository"))]
  3712 
  4217 
  3713     for extname, extmodule in extensions.extensions():
  4218     for extname, extmodule in extensions.extensions():
  3714         if extmodule.__file__ != __file__:
  4219         if extmodule.__file__ != __file__:
  3715             dotable(getattr(extmodule, 'cmdtable', {}))
  4220             dotable(getattr(extmodule, 'cmdtable', {}))
  3716 
  4221 
  3717 colortable = {'qguard.negative': 'red',
  4222 
  3718               'qguard.positive': 'yellow',
  4223 colortable = {
  3719               'qguard.unguarded': 'green',
  4224     'qguard.negative': 'red',
  3720               'qseries.applied': 'blue bold underline',
  4225     'qguard.positive': 'yellow',
  3721               'qseries.guarded': 'black bold',
  4226     'qguard.unguarded': 'green',
  3722               'qseries.missing': 'red bold',
  4227     'qseries.applied': 'blue bold underline',
  3723               'qseries.unapplied': 'black bold'}
  4228     'qseries.guarded': 'black bold',
       
  4229     'qseries.missing': 'red bold',
       
  4230     'qseries.unapplied': 'black bold',
       
  4231 }