hgext/mq.py
changeset 10397 8cb81d75730c
parent 10382 e54e3f6e6789
child 10401 6252852b4332
equal deleted inserted replaced
10396:65a90c8e11ee 10397:8cb81d75730c
    66 
    66 
    67     def __str__(self):
    67     def __str__(self):
    68         return self.rev + ':' + self.name
    68         return self.rev + ':' + self.name
    69 
    69 
    70 class patchheader(object):
    70 class patchheader(object):
    71     def __init__(self, pf):
    71     def __init__(self, pf, plainmode=False):
    72         def eatdiff(lines):
    72         def eatdiff(lines):
    73             while lines:
    73             while lines:
    74                 l = lines[-1]
    74                 l = lines[-1]
    75                 if (l.startswith("diff -") or
    75                 if (l.startswith("diff -") or
    76                     l.startswith("Index:") or
    76                     l.startswith("Index:") or
    88 
    88 
    89         message = []
    89         message = []
    90         comments = []
    90         comments = []
    91         user = None
    91         user = None
    92         date = None
    92         date = None
       
    93         parent = None
    93         format = None
    94         format = None
    94         subject = None
    95         subject = None
    95         diffstart = 0
    96         diffstart = 0
    96 
    97 
    97         for line in file(pf):
    98         for line in file(pf):
   110                 # parse values when importing the result of an hg export
   111                 # parse values when importing the result of an hg export
   111                 if line.startswith("# User "):
   112                 if line.startswith("# User "):
   112                     user = line[7:]
   113                     user = line[7:]
   113                 elif line.startswith("# Date "):
   114                 elif line.startswith("# Date "):
   114                     date = line[7:]
   115                     date = line[7:]
       
   116                 elif line.startswith("# Parent "):
       
   117                     parent = line[9:]
   115                 elif not line.startswith("# ") and line:
   118                 elif not line.startswith("# ") and line:
   116                     message.append(line)
   119                     message.append(line)
   117                     format = None
   120                     format = None
   118             elif line == '# HG changeset patch':
   121             elif line == '# HG changeset patch':
   119                 message = []
   122                 message = []
   124                 format = "tag"
   127                 format = "tag"
   125             elif (format != "tagdone" and (line.startswith("From: ") or
   128             elif (format != "tagdone" and (line.startswith("From: ") or
   126                                            line.startswith("from: "))):
   129                                            line.startswith("from: "))):
   127                 user = line[6:]
   130                 user = line[6:]
   128                 format = "tag"
   131                 format = "tag"
       
   132             elif (format != "tagdone" and (line.startswith("Date: ") or
       
   133                                            line.startswith("date: "))):
       
   134                 date = line[6:]
       
   135                 format = "tag"
   129             elif format == "tag" and line == "":
   136             elif format == "tag" and line == "":
   130                 # when looking for tags (subject: from: etc) they
   137                 # when looking for tags (subject: from: etc) they
   131                 # end once you find a blank line in the source
   138                 # end once you find a blank line in the source
   132                 format = "tagdone"
   139                 format = "tagdone"
   133             elif message or line:
   140             elif message or line:
   146 
   153 
   147         self.message = message
   154         self.message = message
   148         self.comments = comments
   155         self.comments = comments
   149         self.user = user
   156         self.user = user
   150         self.date = date
   157         self.date = date
       
   158         self.parent = parent
   151         self.haspatch = diffstart > 1
   159         self.haspatch = diffstart > 1
       
   160         self.plainmode = plainmode
   152 
   161 
   153     def setuser(self, user):
   162     def setuser(self, user):
   154         if not self.updateheader(['From: ', '# User '], user):
   163         if not self.updateheader(['From: ', '# User '], user):
   155             try:
   164             try:
   156                 patchheaderat = self.comments.index('# HG changeset patch')
   165                 patchheaderat = self.comments.index('# HG changeset patch')
   157                 self.comments.insert(patchheaderat + 1, '# User ' + user)
   166                 self.comments.insert(patchheaderat + 1, '# User ' + user)
   158             except ValueError:
   167             except ValueError:
   159                 if self._hasheader(['Date: ']):
   168                 if self.plainmode or self._hasheader(['Date: ']):
   160                     self.comments = ['From: ' + user] + self.comments
   169                     self.comments = ['From: ' + user] + self.comments
   161                 else:
   170                 else:
   162                     tmp = ['# HG changeset patch', '# User ' + user, '']
   171                     tmp = ['# HG changeset patch', '# User ' + user, '']
   163                     self.comments = tmp + self.comments
   172                     self.comments = tmp + self.comments
   164         self.user = user
   173         self.user = user
   167         if not self.updateheader(['Date: ', '# Date '], date):
   176         if not self.updateheader(['Date: ', '# Date '], date):
   168             try:
   177             try:
   169                 patchheaderat = self.comments.index('# HG changeset patch')
   178                 patchheaderat = self.comments.index('# HG changeset patch')
   170                 self.comments.insert(patchheaderat + 1, '# Date ' + date)
   179                 self.comments.insert(patchheaderat + 1, '# Date ' + date)
   171             except ValueError:
   180             except ValueError:
   172                 if self._hasheader(['From: ']):
   181                 if self.plainmode or self._hasheader(['From: ']):
   173                     self.comments = ['Date: ' + date] + self.comments
   182                     self.comments = ['Date: ' + date] + self.comments
   174                 else:
   183                 else:
   175                     tmp = ['# HG changeset patch', '# Date ' + date, '']
   184                     tmp = ['# HG changeset patch', '# Date ' + date, '']
   176                     self.comments = tmp + self.comments
   185                     self.comments = tmp + self.comments
   177         self.date = date
   186         self.date = date
       
   187 
       
   188     def setparent(self, parent):
       
   189         if not self.updateheader(['# Parent '], parent):
       
   190             try:
       
   191                 patchheaderat = self.comments.index('# HG changeset patch')
       
   192                 self.comments.insert(patchheaderat + 1, '# Parent ' + parent)
       
   193             except ValueError:
       
   194                 pass
       
   195         self.parent = parent
   178 
   196 
   179     def setmessage(self, message):
   197     def setmessage(self, message):
   180         if self.comments:
   198         if self.comments:
   181             self._delmsg()
   199             self._delmsg()
   182         self.message = [message]
   200         self.message = [message]
   243             if gitmode is None:
   261             if gitmode is None:
   244                 raise error.ConfigError()
   262                 raise error.ConfigError()
   245             self.gitmode = gitmode and 'yes' or 'no'
   263             self.gitmode = gitmode and 'yes' or 'no'
   246         except error.ConfigError:
   264         except error.ConfigError:
   247             self.gitmode = ui.config('mq', 'git', 'auto').lower()
   265             self.gitmode = ui.config('mq', 'git', 'auto').lower()
       
   266         self.plainmode = ui.configbool('mq', 'plain', False)
   248 
   267 
   249     @util.propertycache
   268     @util.propertycache
   250     def applied(self):
   269     def applied(self):
   251         if os.path.exists(self.join(self.status_path)):
   270         if os.path.exists(self.join(self.status_path)):
   252             lines = self.opener(self.status_path).read().splitlines()
   271             lines = self.opener(self.status_path).read().splitlines()
   507             raise util.Abort(_("update returned %d") % ret)
   526             raise util.Abort(_("update returned %d") % ret)
   508         n = repo.commit(ctx.description(), ctx.user(), force=True)
   527         n = repo.commit(ctx.description(), ctx.user(), force=True)
   509         if n is None:
   528         if n is None:
   510             raise util.Abort(_("repo commit failed"))
   529             raise util.Abort(_("repo commit failed"))
   511         try:
   530         try:
   512             ph = patchheader(mergeq.join(patch))
   531             ph = patchheader(mergeq.join(patch), self.plainmode)
   513         except:
   532         except:
   514             raise util.Abort(_("unable to read %s") % patch)
   533             raise util.Abort(_("unable to read %s") % patch)
   515 
   534 
   516         diffopts = self.patchopts(diffopts, patch)
   535         diffopts = self.patchopts(diffopts, patch)
   517         patchf = self.opener(patch, "w")
   536         patchf = self.opener(patch, "w")
   637                 continue
   656                 continue
   638             self.ui.status(_("applying %s\n") % patchname)
   657             self.ui.status(_("applying %s\n") % patchname)
   639             pf = os.path.join(patchdir, patchname)
   658             pf = os.path.join(patchdir, patchname)
   640 
   659 
   641             try:
   660             try:
   642                 ph = patchheader(self.join(patchname))
   661                 ph = patchheader(self.join(patchname), self.plainmode)
   643             except:
   662             except:
   644                 self.ui.warn(_("unable to read %s\n") % patchname)
   663                 self.ui.warn(_("unable to read %s\n") % patchname)
   645                 err = 1
   664                 err = 1
   646                 break
   665                 break
   647 
   666 
   829         wlock = repo.wlock()
   848         wlock = repo.wlock()
   830         try:
   849         try:
   831             # if patch file write fails, abort early
   850             # if patch file write fails, abort early
   832             p = self.opener(patchfn, "w")
   851             p = self.opener(patchfn, "w")
   833             try:
   852             try:
   834                 if date:
   853                 if self.plainmode:
       
   854                     if user:
       
   855                         p.write("From: " + user + "\n")
       
   856                         if not date:
       
   857                             p.write("\n")
       
   858                     if date:
       
   859                         p.write("Date: %d %d\n\n" % date)
       
   860                 else:
   835                     p.write("# HG changeset patch\n")
   861                     p.write("# HG changeset patch\n")
       
   862                     p.write("# Parent " + hex(repo[None].parents()[0].node()) + "\n")
   836                     if user:
   863                     if user:
   837                         p.write("# User " + user + "\n")
   864                         p.write("# User " + user + "\n")
   838                     p.write("# Date %d %d\n\n" % date)
   865                     if date:
   839                 elif user:
   866                         p.write("# Date %s %s\n\n" % date)
   840                     p.write("From: " + user + "\n\n")
       
   841 
       
   842                 if hasattr(msg, '__call__'):
   867                 if hasattr(msg, '__call__'):
   843                     msg = msg()
   868                     msg = msg()
   844                 commitmsg = msg and msg or ("[mq]: %s" % patchfn)
   869                 commitmsg = msg and msg or ("[mq]: %s" % patchfn)
   845                 n = repo.commit(commitmsg, user, date, match=match, force=True)
   870                 n = repo.commit(commitmsg, user, date, match=match, force=True)
   846                 if n is None:
   871                 if n is None:
  1212             if repo.changelog.heads(top) != [top]:
  1237             if repo.changelog.heads(top) != [top]:
  1213                 raise util.Abort(_("cannot refresh a revision with children"))
  1238                 raise util.Abort(_("cannot refresh a revision with children"))
  1214 
  1239 
  1215             cparents = repo.changelog.parents(top)
  1240             cparents = repo.changelog.parents(top)
  1216             patchparent = self.qparents(repo, top)
  1241             patchparent = self.qparents(repo, top)
  1217             ph = patchheader(self.join(patchfn))
  1242             ph = patchheader(self.join(patchfn), self.plainmode)
  1218             diffopts = self.diffopts({'git': opts.get('git')}, patchfn)
  1243             diffopts = self.diffopts({'git': opts.get('git')}, patchfn)
  1219             if msg:
  1244             if msg:
  1220                 ph.setmessage(msg)
  1245                 ph.setmessage(msg)
  1221             if newuser:
  1246             if newuser:
  1222                 ph.setuser(newuser)
  1247                 ph.setuser(newuser)
  1223             if newdate:
  1248             if newdate:
  1224                 ph.setdate(newdate)
  1249                 ph.setdate(newdate)
       
  1250             ph.setparent(hex(patchparent))
  1225 
  1251 
  1226             # only commit new patch when write is complete
  1252             # only commit new patch when write is complete
  1227             patchf = self.opener(patchfn, 'w', atomictemp=True)
  1253             patchf = self.opener(patchfn, 'w', atomictemp=True)
  1228 
  1254 
  1229             comments = str(ph)
  1255             comments = str(ph)
  1404 
  1430 
  1405     def qseries(self, repo, missing=None, start=0, length=None, status=None,
  1431     def qseries(self, repo, missing=None, start=0, length=None, status=None,
  1406                 summary=False):
  1432                 summary=False):
  1407         def displayname(pfx, patchname):
  1433         def displayname(pfx, patchname):
  1408             if summary:
  1434             if summary:
  1409                 ph = patchheader(self.join(patchname))
  1435                 ph = patchheader(self.join(patchname), self.plainmode)
  1410                 msg = ph.message and ph.message[0] or ''
  1436                 msg = ph.message and ph.message[0] or ''
  1411                 if self.ui.interactive():
  1437                 if self.ui.interactive():
  1412                     width = util.termwidth() - len(pfx) - len(patchname) - 2
  1438                     width = util.termwidth() - len(pfx) - len(patchname) - 2
  1413                     if width > 0:
  1439                     if width > 0:
  1414                         msg = util.ellipsis(msg, width)
  1440                         msg = util.ellipsis(msg, width)
  2010             ui.write(_("no patches applied\n"))
  2036             ui.write(_("no patches applied\n"))
  2011             return 1
  2037             return 1
  2012         if message:
  2038         if message:
  2013             raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
  2039             raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
  2014         patch = q.applied[-1].name
  2040         patch = q.applied[-1].name
  2015         ph = patchheader(q.join(patch))
  2041         ph = patchheader(q.join(patch), q.plainmode)
  2016         message = ui.edit('\n'.join(ph.message), ph.user or ui.username())
  2042         message = ui.edit('\n'.join(ph.message), ph.user or ui.username())
  2017     setupheaderopts(ui, opts)
  2043     setupheaderopts(ui, opts)
  2018     ret = q.refresh(repo, pats, msg=message, **opts)
  2044     ret = q.refresh(repo, pats, msg=message, **opts)
  2019     q.save_dirty()
  2045     q.save_dirty()
  2020     return ret
  2046     return ret
  2072             raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
  2098             raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
  2073         patches.append(p)
  2099         patches.append(p)
  2074 
  2100 
  2075     for p in patches:
  2101     for p in patches:
  2076         if not message:
  2102         if not message:
  2077             ph = patchheader(q.join(p))
  2103             ph = patchheader(q.join(p), q.plainmode)
  2078             if ph.message:
  2104             if ph.message:
  2079                 messages.append(ph.message)
  2105                 messages.append(ph.message)
  2080         pf = q.join(p)
  2106         pf = q.join(p)
  2081         (patchsuccess, files, fuzz) = q.patch(repo, pf)
  2107         (patchsuccess, files, fuzz) = q.patch(repo, pf)
  2082         if not patchsuccess:
  2108         if not patchsuccess:
  2083             raise util.Abort(_('Error folding patch %s') % p)
  2109             raise util.Abort(_('Error folding patch %s') % p)
  2084         patch.updatedir(ui, repo, files)
  2110         patch.updatedir(ui, repo, files)
  2085 
  2111 
  2086     if not message:
  2112     if not message:
  2087         ph = patchheader(q.join(parent))
  2113         ph = patchheader(q.join(parent), q.plainmode)
  2088         message, user = ph.message, ph.user
  2114         message, user = ph.message, ph.user
  2089         for msg in messages:
  2115         for msg in messages:
  2090             message.append('* * *')
  2116             message.append('* * *')
  2091             message.extend(msg)
  2117             message.extend(msg)
  2092         message = '\n'.join(message)
  2118         message = '\n'.join(message)
  2165     else:
  2191     else:
  2166         if not q.applied:
  2192         if not q.applied:
  2167             ui.write('no patches applied\n')
  2193             ui.write('no patches applied\n')
  2168             return 1
  2194             return 1
  2169         patch = q.lookup('qtip')
  2195         patch = q.lookup('qtip')
  2170     ph = patchheader(repo.mq.join(patch))
  2196     ph = patchheader(q.join(patch), q.plainmode)
  2171 
  2197 
  2172     ui.write('\n'.join(ph.message) + '\n')
  2198     ui.write('\n'.join(ph.message) + '\n')
  2173 
  2199 
  2174 def lastsavename(path):
  2200 def lastsavename(path):
  2175     (directory, base) = os.path.split(path)
  2201     (directory, base) = os.path.split(path)