hgext/mq.py
changeset 4915 97b734fb9c6f
parent 4906 30847b8af7ca
child 4917 126f527b3ba3
equal deleted inserted replaced
4914:9a2a73ea6135 4915:97b734fb9c6f
   437         return (True, files, fuzz)
   437         return (True, files, fuzz)
   438 
   438 
   439     def apply(self, repo, series, list=False, update_status=True,
   439     def apply(self, repo, series, list=False, update_status=True,
   440               strict=False, patchdir=None, merge=None, wlock=None,
   440               strict=False, patchdir=None, merge=None, wlock=None,
   441               all_files={}):
   441               all_files={}):
   442         if not wlock:
   442         lock = tr = None
   443             wlock = repo.wlock()
       
   444         lock = repo.lock()
       
   445         tr = repo.transaction()
       
   446         try:
   443         try:
   447             ret = self._apply(tr, repo, series, list, update_status,
   444             if not wlock:
   448                               strict, patchdir, merge, wlock,
   445                 wlock = repo.wlock()
   449                               lock=lock, all_files=all_files)
   446             lock = repo.lock()
   450             tr.close()
   447             tr = repo.transaction()
   451             self.save_dirty()
       
   452             return ret
       
   453         except:
       
   454             try:
   448             try:
   455                 tr.abort()
   449                 ret = self._apply(tr, repo, series, list, update_status,
   456             finally:
   450                                   strict, patchdir, merge, wlock,
   457                 repo.invalidate()
   451                                   lock=lock, all_files=all_files)
   458                 repo.dirstate.invalidate()
   452                 tr.close()
   459             raise
   453                 self.save_dirty()
       
   454                 return ret
       
   455             except:
       
   456                 try:
       
   457                     tr.abort()
       
   458                 finally:
       
   459                     repo.invalidate()
       
   460                     repo.dirstate.invalidate()
       
   461                 raise
       
   462         finally:
       
   463             del lock, wlock, tr
   460 
   464 
   461     def _apply(self, tr, repo, series, list=False, update_status=True,
   465     def _apply(self, tr, repo, series, list=False, update_status=True,
   462                strict=False, patchdir=None, merge=None, wlock=None,
   466                strict=False, patchdir=None, merge=None, wlock=None,
   463                lock=None, all_files={}):
   467                lock=None, all_files={}):
   464         # TODO unify with commands.py
   468         # TODO unify with commands.py
   614         else:
   618         else:
   615             m, a, r, d = self.check_localchanges(repo, force)
   619             m, a, r, d = self.check_localchanges(repo, force)
   616         commitfiles = m + a + r
   620         commitfiles = m + a + r
   617         self.check_toppatch(repo)
   621         self.check_toppatch(repo)
   618         wlock = repo.wlock()
   622         wlock = repo.wlock()
   619         insert = self.full_series_end()
   623         try:
   620         if msg:
   624             insert = self.full_series_end()
   621             n = repo.commit(commitfiles, msg, force=True, wlock=wlock)
   625             if msg:
   622         else:
   626                 n = repo.commit(commitfiles, msg, force=True, wlock=wlock)
   623             n = repo.commit(commitfiles,
   627             else:
   624                             "[mq]: %s" % patch, force=True, wlock=wlock)
   628                 n = repo.commit(commitfiles,
   625         if n == None:
   629                                 "[mq]: %s" % patch, force=True, wlock=wlock)
   626             raise util.Abort(_("repo commit failed"))
   630             if n == None:
   627         self.full_series[insert:insert] = [patch]
   631                 raise util.Abort(_("repo commit failed"))
   628         self.applied.append(statusentry(revlog.hex(n), patch))
   632             self.full_series[insert:insert] = [patch]
   629         self.parse_series()
   633             self.applied.append(statusentry(revlog.hex(n), patch))
   630         self.series_dirty = 1
   634             self.parse_series()
   631         self.applied_dirty = 1
   635             self.series_dirty = 1
   632         p = self.opener(patch, "w")
   636             self.applied_dirty = 1
   633         if msg:
   637             p = self.opener(patch, "w")
   634             msg = msg + "\n"
   638             if msg:
   635             p.write(msg)
   639                 msg = msg + "\n"
   636         p.close()
   640                 p.write(msg)
   637         wlock = None
   641             p.close()
   638         r = self.qrepo()
   642             wlock = None
   639         if r: r.add([patch])
   643             r = self.qrepo()
   640         if commitfiles:
   644             if r: r.add([patch])
   641             self.refresh(repo, short=True)
   645             if commitfiles:
   642         self.removeundo(repo)
   646                 self.refresh(repo, short=True)
       
   647             self.removeundo(repo)
       
   648         finally:
       
   649             del wlock
   643 
   650 
   644     def strip(self, repo, rev, update=True, backup="all", wlock=None):
   651     def strip(self, repo, rev, update=True, backup="all", wlock=None):
   645         if not wlock:
   652         lock = None
   646             wlock = repo.wlock()
   653         try:
   647         lock = repo.lock()
   654             if not wlock:
   648 
   655                 wlock = repo.wlock()
   649         if update:
   656             lock = repo.lock()
   650             self.check_localchanges(repo, refresh=False)
   657 
   651             urev = self.qparents(repo, rev)
   658             if update:
   652             hg.clean(repo, urev, wlock=wlock)
   659                 self.check_localchanges(repo, refresh=False)
   653             repo.dirstate.write()
   660                 urev = self.qparents(repo, rev)
   654 
   661                 hg.clean(repo, urev, wlock=wlock)
   655         self.removeundo(repo)
   662                 repo.dirstate.write()
   656         repair.strip(self.ui, repo, rev, backup)
   663 
       
   664             self.removeundo(repo)
       
   665             repair.strip(self.ui, repo, rev, backup)
       
   666         finally:
       
   667             del lock, wlock
   657 
   668 
   658     def isapplied(self, patch):
   669     def isapplied(self, patch):
   659         """returns (index, rev, patch)"""
   670         """returns (index, rev, patch)"""
   660         for i in xrange(len(self.applied)):
   671         for i in xrange(len(self.applied)):
   661             a = self.applied[i]
   672             a = self.applied[i]
   738 
   749 
   739     def push(self, repo, patch=None, force=False, list=False,
   750     def push(self, repo, patch=None, force=False, list=False,
   740              mergeq=None, wlock=None):
   751              mergeq=None, wlock=None):
   741         if not wlock:
   752         if not wlock:
   742             wlock = repo.wlock()
   753             wlock = repo.wlock()
   743         patch = self.lookup(patch)
   754         try:
   744         # Suppose our series file is: A B C and the current 'top' patch is B.
   755             patch = self.lookup(patch)
   745         # qpush C should be performed (moving forward)
   756             # Suppose our series file is: A B C and the current 'top'
   746         # qpush B is a NOP (no change)
   757             # patch is B. qpush C should be performed (moving forward)
   747         # qpush A is an error (can't go backwards with qpush)
   758             # qpush B is a NOP (no change) qpush A is an error (can't
   748         if patch:
   759             # go backwards with qpush)
   749             info = self.isapplied(patch)
   760             if patch:
   750             if info:
   761                 info = self.isapplied(patch)
   751                 if info[0] < len(self.applied) - 1:
   762                 if info:
   752                     raise util.Abort(_("cannot push to a previous patch: %s") %
   763                     if info[0] < len(self.applied) - 1:
   753                                      patch)
   764                         raise util.Abort(
   754                 if info[0] < len(self.series) - 1:
   765                             _("cannot push to a previous patch: %s") % patch)
   755                     self.ui.warn(_('qpush: %s is already at the top\n') % patch)
   766                     if info[0] < len(self.series) - 1:
       
   767                         self.ui.warn(
       
   768                             _('qpush: %s is already at the top\n') % patch)
       
   769                     else:
       
   770                         self.ui.warn(_('all patches are currently applied\n'))
       
   771                     return
       
   772 
       
   773             # Following the above example, starting at 'top' of B:
       
   774             # qpush should be performed (pushes C), but a subsequent
       
   775             # qpush without an argument is an error (nothing to
       
   776             # apply). This allows a loop of "...while hg qpush..." to
       
   777             # work as it detects an error when done
       
   778             if self.series_end() == len(self.series):
       
   779                 self.ui.warn(_('patch series already fully applied\n'))
       
   780                 return 1
       
   781             if not force:
       
   782                 self.check_localchanges(repo)
       
   783 
       
   784             self.applied_dirty = 1;
       
   785             start = self.series_end()
       
   786             if start > 0:
       
   787                 self.check_toppatch(repo)
       
   788             if not patch:
       
   789                 patch = self.series[start]
       
   790                 end = start + 1
       
   791             else:
       
   792                 end = self.series.index(patch, start) + 1
       
   793             s = self.series[start:end]
       
   794             all_files = {}
       
   795             try:
       
   796                 if mergeq:
       
   797                     ret = self.mergepatch(repo, mergeq, s, wlock)
   756                 else:
   798                 else:
   757                     self.ui.warn(_('all patches are currently applied\n'))
   799                     ret = self.apply(repo, s, list, wlock=wlock,
   758                 return
   800                                      all_files=all_files)
   759 
   801             except:
   760         # Following the above example, starting at 'top' of B:
   802                 self.ui.warn(_('cleaning up working directory...'))
   761         #  qpush should be performed (pushes C), but a subsequent qpush without
   803                 node = repo.dirstate.parents()[0]
   762         #  an argument is an error (nothing to apply). This allows a loop
   804                 hg.revert(repo, node, None, wlock)
   763         #  of "...while hg qpush..." to work as it detects an error when done
   805                 unknown = repo.status(wlock=wlock)[4]
   764         if self.series_end() == len(self.series):
   806                 # only remove unknown files that we know we touched or
   765             self.ui.warn(_('patch series already fully applied\n'))
   807                 # created while patching
   766             return 1
   808                 for f in unknown:
   767         if not force:
   809                     if f in all_files:
   768             self.check_localchanges(repo)
   810                         util.unlink(repo.wjoin(f))
   769 
   811                 self.ui.warn(_('done\n'))
   770         self.applied_dirty = 1;
   812                 raise
   771         start = self.series_end()
   813             top = self.applied[-1].name
   772         if start > 0:
   814             if ret[0]:
   773             self.check_toppatch(repo)
   815                 self.ui.write(
   774         if not patch:
   816                     "Errors during apply, please fix and refresh %s\n" % top)
   775             patch = self.series[start]
       
   776             end = start + 1
       
   777         else:
       
   778             end = self.series.index(patch, start) + 1
       
   779         s = self.series[start:end]
       
   780         all_files = {}
       
   781         try:
       
   782             if mergeq:
       
   783                 ret = self.mergepatch(repo, mergeq, s, wlock)
       
   784             else:
   817             else:
   785                 ret = self.apply(repo, s, list, wlock=wlock,
   818                 self.ui.write("Now at: %s\n" % top)
   786                                  all_files=all_files)
   819             return ret[0]
   787         except:
   820         finally:
   788             self.ui.warn(_('cleaning up working directory...'))
   821             del wlock
   789             node = repo.dirstate.parents()[0]
       
   790             hg.revert(repo, node, None, wlock)
       
   791             unknown = repo.status(wlock=wlock)[4]
       
   792             # only remove unknown files that we know we touched or
       
   793             # created while patching
       
   794             for f in unknown:
       
   795                 if f in all_files:
       
   796                     util.unlink(repo.wjoin(f))
       
   797             self.ui.warn(_('done\n'))
       
   798             raise
       
   799         top = self.applied[-1].name
       
   800         if ret[0]:
       
   801             self.ui.write("Errors during apply, please fix and refresh %s\n" %
       
   802                           top)
       
   803         else:
       
   804             self.ui.write("Now at: %s\n" % top)
       
   805         return ret[0]
       
   806 
   822 
   807     def pop(self, repo, patch=None, force=False, update=True, all=False,
   823     def pop(self, repo, patch=None, force=False, update=True, all=False,
   808             wlock=None):
   824             wlock=None):
   809         def getfile(f, rev):
   825         def getfile(f, rev):
   810             t = repo.file(f).read(rev)
   826             t = repo.file(f).read(rev)
   811             repo.wfile(f, "w").write(t)
   827             repo.wfile(f, "w").write(t)
   812 
   828 
   813         if not wlock:
   829         if not wlock:
   814             wlock = repo.wlock()
   830             wlock = repo.wlock()
   815         if patch:
   831         try:
   816             # index, rev, patch
   832             if patch:
   817             info = self.isapplied(patch)
   833                 # index, rev, patch
   818             if not info:
   834                 info = self.isapplied(patch)
   819                 patch = self.lookup(patch)
   835                 if not info:
   820             info = self.isapplied(patch)
   836                     patch = self.lookup(patch)
   821             if not info:
   837                 info = self.isapplied(patch)
   822                 raise util.Abort(_("patch %s is not applied") % patch)
   838                 if not info:
   823 
   839                     raise util.Abort(_("patch %s is not applied") % patch)
   824         if len(self.applied) == 0:
   840 
   825             # Allow qpop -a to work repeatedly,
   841             if len(self.applied) == 0:
   826             # but not qpop without an argument
   842                 # Allow qpop -a to work repeatedly,
   827             self.ui.warn(_("no patches applied\n"))
   843                 # but not qpop without an argument
   828             return not all
   844                 self.ui.warn(_("no patches applied\n"))
   829 
   845                 return not all
   830         if not update:
   846 
   831             parents = repo.dirstate.parents()
   847             if not update:
   832             rr = [ revlog.bin(x.rev) for x in self.applied ]
   848                 parents = repo.dirstate.parents()
   833             for p in parents:
   849                 rr = [ revlog.bin(x.rev) for x in self.applied ]
   834                 if p in rr:
   850                 for p in parents:
   835                     self.ui.warn("qpop: forcing dirstate update\n")
   851                     if p in rr:
   836                     update = True
   852                         self.ui.warn("qpop: forcing dirstate update\n")
   837 
   853                         update = True
   838         if not force and update:
   854 
   839             self.check_localchanges(repo)
   855             if not force and update:
   840 
   856                 self.check_localchanges(repo)
   841         self.applied_dirty = 1;
   857 
   842         end = len(self.applied)
   858             self.applied_dirty = 1;
   843         if not patch:
   859             end = len(self.applied)
   844             if all:
   860             if not patch:
   845                 popi = 0
   861                 if all:
       
   862                     popi = 0
       
   863                 else:
       
   864                     popi = len(self.applied) - 1
   846             else:
   865             else:
   847                 popi = len(self.applied) - 1
   866                 popi = info[0] + 1
   848         else:
   867                 if popi >= end:
   849             popi = info[0] + 1
   868                     self.ui.warn("qpop: %s is already at the top\n" % patch)
   850             if popi >= end:
   869                     return
   851                 self.ui.warn("qpop: %s is already at the top\n" % patch)
   870             info = [ popi ] + [self.applied[popi].rev, self.applied[popi].name]
   852                 return
   871 
   853         info = [ popi ] + [self.applied[popi].rev, self.applied[popi].name]
   872             start = info[0]
   854 
   873             rev = revlog.bin(info[1])
   855         start = info[0]
   874 
   856         rev = revlog.bin(info[1])
   875             # we know there are no local changes, so we can make a simplified
   857 
   876             # form of hg.update.
   858         # we know there are no local changes, so we can make a simplified
   877             if update:
   859         # form of hg.update.
   878                 top = self.check_toppatch(repo)
   860         if update:
   879                 qp = self.qparents(repo, rev)
   861             top = self.check_toppatch(repo)
   880                 changes = repo.changelog.read(qp)
   862             qp = self.qparents(repo, rev)
   881                 mmap = repo.manifest.read(changes[0])
   863             changes = repo.changelog.read(qp)
   882                 m, a, r, d, u = repo.status(qp, top)[:5]
   864             mmap = repo.manifest.read(changes[0])
   883                 if d:
   865             m, a, r, d, u = repo.status(qp, top)[:5]
   884                     raise util.Abort("deletions found between repo revs")
   866             if d:
   885                 for f in m:
   867                 raise util.Abort("deletions found between repo revs")
   886                     getfile(f, mmap[f])
   868             for f in m:
   887                 for f in r:
   869                 getfile(f, mmap[f])
   888                     getfile(f, mmap[f])
   870             for f in r:
   889                     util.set_exec(repo.wjoin(f), mmap.execf(f))
   871                 getfile(f, mmap[f])
   890                 for f in m + r:
   872                 util.set_exec(repo.wjoin(f), mmap.execf(f))
   891                     repo.dirstate.normal(f)
   873             for f in m + r:
   892                 for f in a:
   874                 repo.dirstate.normal(f)
   893                     try:
   875             for f in a:
   894                         os.unlink(repo.wjoin(f))
   876                 try:
   895                     except OSError, e:
   877                     os.unlink(repo.wjoin(f))
   896                         if e.errno != errno.ENOENT:
   878                 except OSError, e:
   897                             raise
   879                     if e.errno != errno.ENOENT:
   898                     try: os.removedirs(os.path.dirname(repo.wjoin(f)))
   880                         raise
   899                     except: pass
   881                 try: os.removedirs(os.path.dirname(repo.wjoin(f)))
   900                     repo.dirstate.forget(f)
   882                 except: pass
   901                 repo.dirstate.setparents(qp, revlog.nullid)
   883                 repo.dirstate.forget(f)
   902             self.strip(repo, rev, update=False, backup='strip', wlock=wlock)
   884             repo.dirstate.setparents(qp, revlog.nullid)
   903             del self.applied[start:end]
   885         self.strip(repo, rev, update=False, backup='strip', wlock=wlock)
   904             if len(self.applied):
   886         del self.applied[start:end]
   905                 self.ui.write("Now at: %s\n" % self.applied[-1].name)
   887         if len(self.applied):
   906             else:
   888             self.ui.write("Now at: %s\n" % self.applied[-1].name)
   907                 self.ui.write("Patch queue now empty\n")
   889         else:
   908         finally:
   890             self.ui.write("Patch queue now empty\n")
   909             del wlock
   891 
   910 
   892     def diff(self, repo, pats, opts):
   911     def diff(self, repo, pats, opts):
   893         top = self.check_toppatch(repo)
   912         top = self.check_toppatch(repo)
   894         if not top:
   913         if not top:
   895             self.ui.write("No patches applied\n")
   914             self.ui.write("No patches applied\n")
   902     def refresh(self, repo, pats=None, **opts):
   921     def refresh(self, repo, pats=None, **opts):
   903         if len(self.applied) == 0:
   922         if len(self.applied) == 0:
   904             self.ui.write("No patches applied\n")
   923             self.ui.write("No patches applied\n")
   905             return 1
   924             return 1
   906         wlock = repo.wlock()
   925         wlock = repo.wlock()
   907         self.check_toppatch(repo)
   926         try:
   908         (top, patchfn) = (self.applied[-1].rev, self.applied[-1].name)
   927             self.check_toppatch(repo)
   909         top = revlog.bin(top)
   928             (top, patchfn) = (self.applied[-1].rev, self.applied[-1].name)
   910         cparents = repo.changelog.parents(top)
   929             top = revlog.bin(top)
   911         patchparent = self.qparents(repo, top)
   930             cparents = repo.changelog.parents(top)
   912         message, comments, user, date, patchfound = self.readheaders(patchfn)
   931             patchparent = self.qparents(repo, top)
   913 
   932             message, comments, user, date, patchfound = self.readheaders(patchfn)
   914         patchf = self.opener(patchfn, 'r+')
   933 
   915 
   934             patchf = self.opener(patchfn, 'r+')
   916         # if the patch was a git patch, refresh it as a git patch
   935 
   917         for line in patchf:
   936             # if the patch was a git patch, refresh it as a git patch
   918             if line.startswith('diff --git'):
   937             for line in patchf:
       
   938                 if line.startswith('diff --git'):
       
   939                     self.diffopts().git = True
       
   940                     break
       
   941             patchf.seek(0)
       
   942             patchf.truncate()
       
   943 
       
   944             msg = opts.get('msg', '').rstrip()
       
   945             if msg:
       
   946                 if comments:
       
   947                     # Remove existing message.
       
   948                     ci = 0
       
   949                     subj = None
       
   950                     for mi in xrange(len(message)):
       
   951                         if comments[ci].lower().startswith('subject: '):
       
   952                             subj = comments[ci][9:]
       
   953                         while message[mi] != comments[ci] and message[mi] != subj:
       
   954                             ci += 1
       
   955                         del comments[ci]
       
   956                 comments.append(msg)
       
   957             if comments:
       
   958                 comments = "\n".join(comments) + '\n\n'
       
   959                 patchf.write(comments)
       
   960 
       
   961             if opts.get('git'):
   919                 self.diffopts().git = True
   962                 self.diffopts().git = True
   920                 break
   963             fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
   921         patchf.seek(0)
   964             tip = repo.changelog.tip()
   922         patchf.truncate()
   965             if top == tip:
   923 
   966                 # if the top of our patch queue is also the tip, there is an
   924         msg = opts.get('msg', '').rstrip()
   967                 # optimization here.  We update the dirstate in place and strip
   925         if msg:
   968                 # off the tip commit.  Then just commit the current directory
   926             if comments:
   969                 # tree.  We can also send repo.commit the list of files
   927                 # Remove existing message.
   970                 # changed to speed up the diff
   928                 ci = 0
   971                 #
   929                 subj = None
   972                 # in short mode, we only diff the files included in the
   930                 for mi in xrange(len(message)):
   973                 # patch already
   931                     if comments[ci].lower().startswith('subject: '):
   974                 #
   932                         subj = comments[ci][9:]
   975                 # this should really read:
   933                     while message[mi] != comments[ci] and message[mi] != subj:
   976                 #   mm, dd, aa, aa2, uu = repo.status(tip, patchparent)[:5]
   934                         ci += 1
   977                 # but we do it backwards to take advantage of manifest/chlog
   935                     del comments[ci]
   978                 # caching against the next repo.status call
   936             comments.append(msg)
   979                 #
   937         if comments:
   980                 mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5]
   938             comments = "\n".join(comments) + '\n\n'
   981                 changes = repo.changelog.read(tip)
   939             patchf.write(comments)
   982                 man = repo.manifest.read(changes[0])
   940 
   983                 aaa = aa[:]
   941         if opts.get('git'):
   984                 if opts.get('short'):
   942             self.diffopts().git = True
   985                     filelist = mm + aa + dd
   943         fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
   986                     match = dict.fromkeys(filelist).__contains__
   944         tip = repo.changelog.tip()
   987                 else:
   945         if top == tip:
   988                     filelist = None
   946             # if the top of our patch queue is also the tip, there is an
   989                     match = util.always
   947             # optimization here.  We update the dirstate in place and strip
   990                 m, a, r, d, u = repo.status(files=filelist, match=match)[:5]
   948             # off the tip commit.  Then just commit the current directory
   991 
   949             # tree.  We can also send repo.commit the list of files
   992                 # we might end up with files that were added between
   950             # changed to speed up the diff
   993                 # tip and the dirstate parent, but then changed in the
   951             #
   994                 # local dirstate. in this case, we want them to only
   952             # in short mode, we only diff the files included in the
   995                 # show up in the added section
   953             # patch already
   996                 for x in m:
   954             #
   997                     if x not in aa:
   955             # this should really read:
   998                         mm.append(x)
   956             #   mm, dd, aa, aa2, uu = repo.status(tip, patchparent)[:5]
   999                 # we might end up with files added by the local dirstate that
   957             # but we do it backwards to take advantage of manifest/chlog
  1000                 # were deleted by the patch.  In this case, they should only
   958             # caching against the next repo.status call
  1001                 # show up in the changed section.
   959             #
  1002                 for x in a:
   960             mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5]
  1003                     if x in dd:
   961             changes = repo.changelog.read(tip)
  1004                         del dd[dd.index(x)]
   962             man = repo.manifest.read(changes[0])
  1005                         mm.append(x)
   963             aaa = aa[:]
  1006                     else:
   964             if opts.get('short'):
  1007                         aa.append(x)
   965                 filelist = mm + aa + dd
  1008                 # make sure any files deleted in the local dirstate
   966                 match = dict.fromkeys(filelist).__contains__
  1009                 # are not in the add or change column of the patch
       
  1010                 forget = []
       
  1011                 for x in d + r:
       
  1012                     if x in aa:
       
  1013                         del aa[aa.index(x)]
       
  1014                         forget.append(x)
       
  1015                         continue
       
  1016                     elif x in mm:
       
  1017                         del mm[mm.index(x)]
       
  1018                     dd.append(x)
       
  1019 
       
  1020                 m = util.unique(mm)
       
  1021                 r = util.unique(dd)
       
  1022                 a = util.unique(aa)
       
  1023                 c = [filter(matchfn, l) for l in (m, a, r, [], u)]
       
  1024                 filelist = util.unique(c[0] + c[1] + c[2])
       
  1025                 patch.diff(repo, patchparent, files=filelist, match=matchfn,
       
  1026                            fp=patchf, changes=c, opts=self.diffopts())
       
  1027                 patchf.close()
       
  1028 
       
  1029                 repo.dirstate.setparents(*cparents)
       
  1030                 copies = {}
       
  1031                 for dst in a:
       
  1032                     src = repo.dirstate.copied(dst)
       
  1033                     if src is None:
       
  1034                         continue
       
  1035                     copies.setdefault(src, []).append(dst)
       
  1036                     repo.dirstate.add(dst)
       
  1037                 # remember the copies between patchparent and tip
       
  1038                 # this may be slow, so don't do it if we're not tracking copies
       
  1039                 if self.diffopts().git:
       
  1040                     for dst in aaa:
       
  1041                         f = repo.file(dst)
       
  1042                         src = f.renamed(man[dst])
       
  1043                         if src:
       
  1044                             copies[src[0]] = copies.get(dst, [])
       
  1045                             if dst in a:
       
  1046                                 copies[src[0]].append(dst)
       
  1047                         # we can't copy a file created by the patch itself
       
  1048                         if dst in copies:
       
  1049                             del copies[dst]
       
  1050                 for src, dsts in copies.iteritems():
       
  1051                     for dst in dsts:
       
  1052                         repo.dirstate.copy(src, dst)
       
  1053                 for f in r:
       
  1054                     repo.dirstate.remove(f)
       
  1055                 # if the patch excludes a modified file, mark that
       
  1056                 # file with mtime=0 so status can see it.
       
  1057                 mm = []
       
  1058                 for i in xrange(len(m)-1, -1, -1):
       
  1059                     if not matchfn(m[i]):
       
  1060                         mm.append(m[i])
       
  1061                         del m[i]
       
  1062                 for f in m:
       
  1063                     repo.dirstate.normal(f)
       
  1064                 for f in mm:
       
  1065                     repo.dirstate.normaldirty(f)
       
  1066                 for f in forget:
       
  1067                     repo.dirstate.forget(f)
       
  1068 
       
  1069                 if not msg:
       
  1070                     if not message:
       
  1071                         message = "[mq]: %s\n" % patchfn
       
  1072                     else:
       
  1073                         message = "\n".join(message)
       
  1074                 else:
       
  1075                     message = msg
       
  1076 
       
  1077                 self.strip(repo, top, update=False,
       
  1078                            backup='strip', wlock=wlock)
       
  1079                 n = repo.commit(filelist, message, changes[1], match=matchfn,
       
  1080                                 force=1, wlock=wlock)
       
  1081                 self.applied[-1] = statusentry(revlog.hex(n), patchfn)
       
  1082                 self.applied_dirty = 1
       
  1083                 self.removeundo(repo)
   967             else:
  1084             else:
   968                 filelist = None
  1085                 self.printdiff(repo, patchparent, fp=patchf)
   969                 match = util.always
  1086                 patchf.close()
   970             m, a, r, d, u = repo.status(files=filelist, match=match)[:5]
  1087                 added = repo.status()[1]
   971 
  1088                 for a in added:
   972             # we might end up with files that were added between tip and
  1089                     f = repo.wjoin(a)
   973             # the dirstate parent, but then changed in the local dirstate.
  1090                     try:
   974             # in this case, we want them to only show up in the added section
  1091                         os.unlink(f)
   975             for x in m:
  1092                     except OSError, e:
   976                 if x not in aa:
  1093                         if e.errno != errno.ENOENT:
   977                     mm.append(x)
  1094                             raise
   978             # we might end up with files added by the local dirstate that
  1095                     try: os.removedirs(os.path.dirname(f))
   979             # were deleted by the patch.  In this case, they should only
  1096                     except: pass
   980             # show up in the changed section.
  1097                     # forget the file copies in the dirstate
   981             for x in a:
  1098                     # push should readd the files later on
   982                 if x in dd:
  1099                     repo.dirstate.forget(a)
   983                     del dd[dd.index(x)]
  1100                 self.pop(repo, force=True, wlock=wlock)
   984                     mm.append(x)
  1101                 self.push(repo, force=True, wlock=wlock)
   985                 else:
  1102         finally:
   986                     aa.append(x)
  1103             del wlock
   987             # make sure any files deleted in the local dirstate
       
   988             # are not in the add or change column of the patch
       
   989             forget = []
       
   990             for x in d + r:
       
   991                 if x in aa:
       
   992                     del aa[aa.index(x)]
       
   993                     forget.append(x)
       
   994                     continue
       
   995                 elif x in mm:
       
   996                     del mm[mm.index(x)]
       
   997                 dd.append(x)
       
   998 
       
   999             m = util.unique(mm)
       
  1000             r = util.unique(dd)
       
  1001             a = util.unique(aa)
       
  1002             c = [filter(matchfn, l) for l in (m, a, r, [], u)]
       
  1003             filelist = util.unique(c[0] + c[1] + c[2])
       
  1004             patch.diff(repo, patchparent, files=filelist, match=matchfn,
       
  1005                        fp=patchf, changes=c, opts=self.diffopts())
       
  1006             patchf.close()
       
  1007 
       
  1008             repo.dirstate.setparents(*cparents)
       
  1009             copies = {}
       
  1010             for dst in a:
       
  1011                 src = repo.dirstate.copied(dst)
       
  1012                 if src is None:
       
  1013                     continue
       
  1014                 copies.setdefault(src, []).append(dst)
       
  1015                 repo.dirstate.add(dst)
       
  1016             # remember the copies between patchparent and tip
       
  1017             # this may be slow, so don't do it if we're not tracking copies
       
  1018             if self.diffopts().git:
       
  1019                 for dst in aaa:
       
  1020                     f = repo.file(dst)
       
  1021                     src = f.renamed(man[dst])
       
  1022                     if src:
       
  1023                         copies[src[0]] = copies.get(dst, [])
       
  1024                         if dst in a:
       
  1025                             copies[src[0]].append(dst)
       
  1026                     # we can't copy a file created by the patch itself
       
  1027                     if dst in copies:
       
  1028                         del copies[dst]
       
  1029             for src, dsts in copies.iteritems():
       
  1030                 for dst in dsts:
       
  1031                     repo.dirstate.copy(src, dst)
       
  1032             for f in r:
       
  1033                 repo.dirstate.remove(f)
       
  1034             # if the patch excludes a modified file, mark that file with mtime=0
       
  1035             # so status can see it.
       
  1036             mm = []
       
  1037             for i in xrange(len(m)-1, -1, -1):
       
  1038                 if not matchfn(m[i]):
       
  1039                     mm.append(m[i])
       
  1040                     del m[i]
       
  1041             for f in m:
       
  1042                 repo.dirstate.normal(f)
       
  1043             for f in mm:
       
  1044                 repo.dirstate.normaldirty(f)
       
  1045             for f in forget:
       
  1046                 repo.dirstate.forget(f)
       
  1047 
       
  1048             if not msg:
       
  1049                 if not message:
       
  1050                     message = "[mq]: %s\n" % patchfn
       
  1051                 else:
       
  1052                     message = "\n".join(message)
       
  1053             else:
       
  1054                 message = msg
       
  1055 
       
  1056             self.strip(repo, top, update=False, backup='strip', wlock=wlock)
       
  1057             n = repo.commit(filelist, message, changes[1], match=matchfn,
       
  1058                             force=1, wlock=wlock)
       
  1059             self.applied[-1] = statusentry(revlog.hex(n), patchfn)
       
  1060             self.applied_dirty = 1
       
  1061             self.removeundo(repo)
       
  1062         else:
       
  1063             self.printdiff(repo, patchparent, fp=patchf)
       
  1064             patchf.close()
       
  1065             added = repo.status()[1]
       
  1066             for a in added:
       
  1067                 f = repo.wjoin(a)
       
  1068                 try:
       
  1069                     os.unlink(f)
       
  1070                 except OSError, e:
       
  1071                     if e.errno != errno.ENOENT:
       
  1072                         raise
       
  1073                 try: os.removedirs(os.path.dirname(f))
       
  1074                 except: pass
       
  1075                 # forget the file copies in the dirstate
       
  1076                 # push should readd the files later on
       
  1077                 repo.dirstate.forget(a)
       
  1078             self.pop(repo, force=True, wlock=wlock)
       
  1079             self.push(repo, force=True, wlock=wlock)
       
  1080 
  1104 
  1081     def init(self, repo, create=False):
  1105     def init(self, repo, create=False):
  1082         if not create and os.path.isdir(self.path):
  1106         if not create and os.path.isdir(self.path):
  1083             raise util.Abort(_("patch queue directory already exists"))
  1107             raise util.Abort(_("patch queue directory already exists"))
  1084         try:
  1108         try:
  1870 
  1894 
  1871     util.rename(q.join(patch), absdest)
  1895     util.rename(q.join(patch), absdest)
  1872     r = q.qrepo()
  1896     r = q.qrepo()
  1873     if r:
  1897     if r:
  1874         wlock = r.wlock()
  1898         wlock = r.wlock()
  1875         if r.dirstate[name] == 'r':
  1899         try:
  1876             r.undelete([name], wlock)
  1900             if r.dirstate[name] == 'r':
  1877         r.copy(patch, name, wlock)
  1901                 r.undelete([name], wlock)
  1878         r.remove([patch], False, wlock)
  1902             r.copy(patch, name, wlock)
       
  1903             r.remove([patch], False, wlock)
       
  1904         finally:
       
  1905             del wlock
  1879 
  1906 
  1880     q.save_dirty()
  1907     q.save_dirty()
  1881 
  1908 
  1882 def restore(ui, repo, rev, **opts):
  1909 def restore(ui, repo, rev, **opts):
  1883     """restore the queue state saved by a rev"""
  1910     """restore the queue state saved by a rev"""