hgext/qsync.py
changeset 220 ff3158d0d7e8
parent 216 9400e234b3d7
child 228 5a17c0d41a00
equal deleted inserted replaced
219:cfdab01ca8a0 220:ff3158d0d7e8
     1 
     1 
     2 import re
     2 import re
     3 
       
     4 from cStringIO import StringIO
     3 from cStringIO import StringIO
       
     4 import json
     5 
     5 
     6 from mercurial.i18n import _
     6 from mercurial.i18n import _
     7 from mercurial import commands
     7 from mercurial import commands
     8 from mercurial import patch
     8 from mercurial import patch
     9 from mercurial import util
     9 from mercurial import util
    11 from mercurial import cmdutil
    11 from mercurial import cmdutil
    12 from mercurial import hg
    12 from mercurial import hg
    13 from mercurial import scmutil
    13 from mercurial import scmutil
    14 from mercurial import error
    14 from mercurial import error
    15 from mercurial import extensions
    15 from mercurial import extensions
    16 
    16 from mercurial import phases
    17 
       
    18 import re
       
    19 
       
    20 import json
       
    21 
       
    22 
    17 
    23 ### old compat code
    18 ### old compat code
    24 #############################
    19 #############################
    25 
    20 
    26 BRANCHNAME="qsubmit2"
    21 BRANCHNAME="qsubmit2"
    27 OLDBRANCHNAME="pyves-qsubmit"
       
    28 
    22 
    29 ### new command
    23 ### new command
    30 #############################
    24 #############################
    31 cmdtable = {}
    25 cmdtable = {}
    32 command = cmdutil.command(cmdtable)
    26 command = cmdutil.command(cmdtable)
    57 
    51 
    58     .. warning:: Series files is ordered topologically. So two series with
    52     .. warning:: Series files is ordered topologically. So two series with
    59                  interleaved changeset will appear interleaved.
    53                  interleaved changeset will appear interleaved.
    60     '''
    54     '''
    61 
    55 
    62     review = None
       
    63     review = 'edit'
    56     review = 'edit'
    64     if opts['review_all']:
    57     if opts['review_all']:
    65         review = 'all'
    58         review = 'all'
    66     mqrepo = repo.mq.qrepo()
    59     mqrepo = repo.mq.qrepo()
    67     try:
    60     try:
    68         parent = mqrepo[BRANCHNAME]
    61         parent = mqrepo[BRANCHNAME]
    69     except error.RepoLookupError:
    62     except error.RepoLookupError:
    70         try:
    63         parent = initqsubmit(mqrepo)
    71             parent =  mqrepo[OLDBRANCHNAME]
       
    72         except error.RepoLookupError:
       
    73             parent = initqsubmit(mqrepo)
       
    74     store, data, touched = fillstore(repo, parent)
    64     store, data, touched = fillstore(repo, parent)
    75     if not touched:
    65     if not touched:
    76         raise util.Abort('Nothing changed')
    66         raise util.Abort('Nothing changed')
    77     files = ['qsubmitdata', 'series'] + touched
    67     files = ['qsubmitdata', 'series'] + touched
    78     # mark some as ready for review
    68     # mark some as ready for review
    79     message = 'qsubmit commit\n\n'
    69     message = 'qsubmit commit\n\n'
    80     review_list = []
    70     review_list = []
       
    71     applied_list = []
    81     if review:
    72     if review:
       
    73         olddata = get_old_data(parent)
       
    74         oldfiles = dict([(name, ctxhex) for ctxhex, name in olddata])
       
    75 
    82         for patch_name in touched:
    76         for patch_name in touched:
    83             try:
    77             try:
    84                 store.getfile(patch_name)
    78                 store.getfile(patch_name)
    85                 review_list.append(patch_name)
    79                 review_list.append(patch_name)
    86             except IOError:
    80             except IOError:
    87                 pass
    81                 oldnode = oldfiles[patch_name]
       
    82                 obsolete = extensions.find('obsolete')
       
    83                 newnodes = obsolete.newerversion(repo, oldnode)
       
    84                 if newnodes:
       
    85                     newnodes = [n for n in newnodes if n] # remove killing
       
    86                 if not newnodes:
       
    87                     # changeset has been killed (eg. reject)
       
    88                     pass
       
    89                 else:
       
    90                     assert len(newnodes) == 1 # conflict!!!
       
    91                     newnode = newnodes[0]
       
    92                     assert len(newnode) == 1 # split unsupported for now
       
    93                     newnode = list(newnode)[0]
       
    94                     # XXX unmanaged case where a cs is obsoleted by an unavailable one
       
    95                     #if newnode.node() not in repo.changelog.nodemap:
       
    96                     #    raise util.Abort('%s is obsoleted by an unknown node %s'% (oldnode, newnode))
       
    97                     ctx = repo[newnode]
       
    98                     if ctx.phase() == phases.public:
       
    99                         # applied
       
   100                         applied_list.append(patch_name)
       
   101                     elif ctx.phase() == phases.secret:
       
   102                         # already exported changeset is now secret
       
   103                         repo.ui.warn("An already exported changeset is now secret!!!")
       
   104                     else:
       
   105                         # draft
       
   106                         assert False, "Should be exported"
    88 
   107 
    89     if review:
   108     if review:
       
   109         message += '\n'.join('* applied %s' % x for x in applied_list)
    90         message += '\n'.join('* %s ready for review' % x for x in review_list)
   110         message += '\n'.join('* %s ready for review' % x for x in review_list)
    91     memctx = patch.makememctx(mqrepo, (parent.node(), nullid),
   111     memctx = patch.makememctx(mqrepo, (parent.node(), nullid),
    92                               message,
   112                               message,
    93                               None,
   113                               None,
    94                               None,
   114                               None,
   120         return json.loads(old_data.data())
   140         return json.loads(old_data.data())
   121     except error.LookupError:
   141     except error.LookupError:
   122         return []
   142         return []
   123 
   143 
   124 def get_current_data(repo):
   144 def get_current_data(repo):
   125     """Return what would be exported if not previous data exists"""
   145     """Return what would be exported if no previous data exists"""
   126     data = []
   146     data = []
   127     for ctx in repo.set('draft() - (obsolete() + merge())'):
   147     for ctx in repo.set('draft() - (obsolete() + merge())'):
   128         name = makename(ctx)
   148         name = makename(ctx)
   129         data.append([ctx.hex(), makename(ctx)])
   149         data.append([ctx.hex(), makename(ctx)])
   130     merges = repo.revs('draft() and merge()')
   150     merges = repo.revs('draft() and merge()')
   186         touched.add(newname)
   206         touched.add(newname)
   187     # sort by branchrev number
   207     # sort by branchrev number
   188     finaldata.sort(key=lambda x: sort_key(repo[x[0]]))
   208     finaldata.sort(key=lambda x: sort_key(repo[x[0]]))
   189     # sort touched too (ease review list)
   209     # sort touched too (ease review list)
   190     stouched = [f[1] for f in finaldata if f[1] in touched]
   210     stouched = [f[1] for f in finaldata if f[1] in touched]
       
   211     stouched += [x for x in touched if x not in stouched]
   191     return finaldata, stouched
   212     return finaldata, stouched
   192 
   213 
   193 def sort_key(ctx):
   214 def sort_key(ctx):
   194     """ctx sort key: (branch, rev)"""
   215     """ctx sort key: (branch, rev)"""
   195     return (ctx.branch(), ctx.rev())
   216     return (ctx.branch(), ctx.rev())
   196 
   217 
   197 
   218 
   198 def fillstore(repo, basemqctx):
   219 def fillstore(repo, basemqctx):
   199     """file store with patch data"""
   220     """fill store with patch data"""
   200     olddata = get_old_data(basemqctx)
   221     olddata = get_old_data(basemqctx)
   201     newdata = get_current_data(repo)
   222     newdata = get_current_data(repo)
   202     store = patch.filestore()
   223     store = patch.filestore()
   203     try:
   224     try:
   204         data, touched = patchmq(repo, store, olddata, newdata)
   225         data, touched = patchmq(repo, store, olddata, newdata)
   205         # put all name in the series
   226         # put all name in the series
   206         series ='\n'.join(d[1] for d in data) + '\n'
   227         series ='\n'.join(d[1] for d in data) + '\n'
   207         store.setfile('series', series, (False, False))
   228         store.setfile('series', series, (False, False))
   208 
   229 
   209         # export data to ease futur work
   230         # export data to ease futur work
   210         series ='\n'.join(d[1] for d in data) + '\n'
       
   211         store.setfile('qsubmitdata', json.dumps(data, indent=True),
   231         store.setfile('qsubmitdata', json.dumps(data, indent=True),
   212                       (False, False))
   232                       (False, False))
   213     finally:
   233     finally:
   214         store.close()
   234         store.close()
   215     return store, data, touched
   235     return store, data, touched