comparison mercurial/state.py @ 42539:12243f15d53e

statecheck: added support for STATES This removes `STATES` from `state.py` and adds support to `statecheck` class to handle its features. `getrepostate()` function is modified accordingly. This adds a method 'cmdutil.addunfinished()' for appending to the unfinishedstate list so as to keep 'merge' and 'bisect' at the last. This also makes two separate message formats for `checkunfinished()` and `getrepostate()` as there were previously present. Results of test changed are shown. Differential Revision: https://phab.mercurial-scm.org/D6503
author Taapas Agrawal <taapas2897@gmail.com>
date Sun, 09 Jun 2019 02:12:58 +0530
parents 5bddd2244814
children 0231032729c4
comparison
equal deleted inserted replaced
42538:5bddd2244814 42539:12243f15d53e
96 It also has the ability to register and determine the states of any new 96 It also has the ability to register and determine the states of any new
97 multistep operation or multistep command extension. 97 multistep operation or multistep command extension.
98 """ 98 """
99 99
100 def __init__(self, opname, fname, clearable=False, allowcommit=False, 100 def __init__(self, opname, fname, clearable=False, allowcommit=False,
101 cmdmsg="", cmdhint=""): 101 reportonly=False, stopflag=False, cmdmsg="", cmdhint="",
102 statushint=""):
102 """opname is the name the command or operation 103 """opname is the name the command or operation
103 fname is the file name in which data should be stored in .hg directory. 104 fname is the file name in which data should be stored in .hg directory.
104 It is None for merge command. 105 It is None for merge command.
105 clearable boolean determines whether or not interrupted states can be 106 clearable boolean determines whether or not interrupted states can be
106 cleared by running `hg update -C .` which in turn deletes the 107 cleared by running `hg update -C .` which in turn deletes the
107 state file. 108 state file.
108 allowcommit boolean decides whether commit is allowed during interrupted 109 allowcommit boolean decides whether commit is allowed during interrupted
109 state or not. 110 state or not.
111 reportonly flag is used for operations like bisect where we just
112 need to detect the operation using 'hg status --verbose'
113 stopflag is a boolean that determines whether or not a command supports
114 --stop flag
110 cmdmsg is used to pass a different status message in case standard 115 cmdmsg is used to pass a different status message in case standard
111 message of the format "abort: cmdname in progress" is not desired. 116 message of the format "abort: cmdname in progress" is not desired.
112 cmdhint is used to pass a different hint message in case standard 117 cmdhint is used to pass a different hint message in case standard
113 message of the format use 'hg cmdname --continue' or 118 message of the format "To continue: hg cmdname --continue
114 'hg cmdname --abort'" is not desired. 119 To abort: hg cmdname --abort" is not desired.
120 statushint is used to pass a different status message in case standard
121 message of the format ('To continue: hg cmdname --continue'
122 'To abort: hg cmdname --abort') is not desired
115 """ 123 """
116 self._opname = opname 124 self._opname = opname
117 self._fname = fname 125 self._fname = fname
118 self._clearable = clearable 126 self._clearable = clearable
119 self._allowcommit = allowcommit 127 self._allowcommit = allowcommit
120 self._cmdhint = cmdhint 128 self._cmdhint = cmdhint
129 self._statushint = statushint
121 self._cmdmsg = cmdmsg 130 self._cmdmsg = cmdmsg
131 self._stopflag = stopflag
132 self._reportonly = reportonly
133
134 def statusmsg(self):
135 """returns the hint message corresponding to the command for
136 hg status --verbose
137 """
138 if not self._statushint:
139 hint = (_('To continue: hg %s --continue\n'
140 'To abort: hg %s --abort') % (self._opname,
141 self._opname))
142 if self._stopflag:
143 hint = hint + (_('\nTo stop: hg %s --stop') %
144 (self._opname))
145 return hint
146 return self._statushint
122 147
123 def hint(self): 148 def hint(self):
124 """returns the hint message corresponding to the command""" 149 """returns the hint message corresponding to an interrupted
150 operation
151 """
125 if not self._cmdhint: 152 if not self._cmdhint:
126 return (_("use 'hg %s --continue' or 'hg %s --abort'") % 153 return (_("use 'hg %s --continue' or 'hg %s --abort'") %
127 (self._opname, self._opname)) 154 (self._opname, self._opname))
128 return self._cmdhint 155 return self._cmdhint
129 156
132 if not self._cmdmsg: 159 if not self._cmdmsg:
133 return _('%s in progress') % (self._opname) 160 return _('%s in progress') % (self._opname)
134 return self._cmdmsg 161 return self._cmdmsg
135 162
136 def isunfinished(self, repo): 163 def isunfinished(self, repo):
137 """determines whether a multi-step operation is in progress or not""" 164 """determines whether a multi-step operation is in progress
138 return repo.vfs.exists(self._fname) 165 or not
166 """
167 if self._opname == 'merge':
168 return len(repo[None].parents()) > 1
169 else:
170 return repo.vfs.exists(self._fname)
139 171
140 # A list of statecheck objects for multistep operations like graft. 172 # A list of statecheck objects for multistep operations like graft.
141 _unfinishedstates = [] 173 _unfinishedstates = []
142 174
143 def addunfinished(opname, **kwargs): 175 def addunfinished(opname, **kwargs):
144 """this registers a new command or operation to unfinishedstates 176 """this registers a new command or operation to unfinishedstates
145 """ 177 """
146 statecheckobj = _statecheck(opname, **kwargs) 178 statecheckobj = _statecheck(opname, **kwargs)
147 _unfinishedstates.append(statecheckobj) 179 if opname == 'merge':
148 180 _unfinishedstates.append(statecheckobj)
149 addunfinished( 181 else:
150 'graft', fname='graftstate', clearable=True, 182 _unfinishedstates.insert(0, statecheckobj)
151 cmdhint=_("use 'hg graft --continue' or 'hg graft --stop' to stop") 183
184 addunfinished(
185 'graft', fname='graftstate', clearable=True, stopflag=True,
186 cmdhint=_("use 'hg graft --continue' or 'hg graft --stop' to stop"),
152 ) 187 )
153 addunfinished( 188 addunfinished(
154 'update', fname='updatestate', clearable=True, 189 'update', fname='updatestate', clearable=True,
155 cmdmsg=_('last update was interrupted'), 190 cmdmsg=_('last update was interrupted'),
156 cmdhint=_("use 'hg update' to get a consistent checkout") 191 cmdhint=_("use 'hg update' to get a consistent checkout"),
157 ) 192 statushint=_("To continue: hg update")
158 193 )
159 def _commentlines(raw): 194 addunfinished(
160 '''Surround lineswith a comment char and a new line''' 195 'bisect', fname='bisect.state', allowcommit=True, reportonly=True,
161 lines = raw.splitlines() 196 statushint=_('To mark the changeset good: hg bisect --good\n'
162 commentedlines = ['# %s' % line for line in lines] 197 'To mark the changeset bad: hg bisect --bad\n'
163 return '\n'.join(commentedlines) + '\n' 198 'To abort: hg bisect --reset\n')
164 199 )
165 def _helpmessage(continuecmd, abortcmd): 200 addunfinished(
166 msg = _('To continue: %s\n' 201 'merge', fname=None, clearable=True, allowcommit=True,
167 'To abort: %s') % (continuecmd, abortcmd) 202 cmdmsg=_('outstanding uncommitted merge'),
168 return _commentlines(msg) 203 statushint=_('To continue: hg commit\n'
169 204 'To abort: hg merge --abort'),
170 def _rebasemsg(): 205 cmdhint=_("use 'hg commit' or 'hg merge --abort'")
171 return _helpmessage('hg rebase --continue', 'hg rebase --abort')
172
173 def _histeditmsg():
174 return _helpmessage('hg histedit --continue', 'hg histedit --abort')
175
176 def _unshelvemsg():
177 return _helpmessage('hg unshelve --continue', 'hg unshelve --abort')
178
179 def _graftmsg():
180 return _helpmessage('hg graft --continue', 'hg graft --abort')
181
182 def _mergemsg():
183 return _helpmessage('hg commit', 'hg merge --abort')
184
185 def _bisectmsg():
186 msg = _('To mark the changeset good: hg bisect --good\n'
187 'To mark the changeset bad: hg bisect --bad\n'
188 'To abort: hg bisect --reset\n')
189 return _commentlines(msg)
190
191 def fileexistspredicate(filename):
192 return lambda repo: repo.vfs.exists(filename)
193
194 def _mergepredicate(repo):
195 return len(repo[None].parents()) > 1
196
197 STATES = (
198 # (state, predicate to detect states, helpful message function)
199 ('histedit', fileexistspredicate('histedit-state'), _histeditmsg),
200 ('bisect', fileexistspredicate('bisect.state'), _bisectmsg),
201 ('graft', fileexistspredicate('graftstate'), _graftmsg),
202 ('unshelve', fileexistspredicate('shelvedstate'), _unshelvemsg),
203 ('rebase', fileexistspredicate('rebasestate'), _rebasemsg),
204 # The merge state is part of a list that will be iterated over.
205 # They need to be last because some of the other unfinished states may also
206 # be in a merge or update state (eg. rebase, histedit, graft, etc).
207 # We want those to have priority.
208 ('merge', _mergepredicate, _mergemsg),
209 ) 206 )
210 207
211 def getrepostate(repo): 208 def getrepostate(repo):
212 # experimental config: commands.status.skipstates 209 # experimental config: commands.status.skipstates
213 skip = set(repo.ui.configlist('commands', 'status.skipstates')) 210 skip = set(repo.ui.configlist('commands', 'status.skipstates'))
214 for state, statedetectionpredicate, msgfn in STATES: 211 for state in _unfinishedstates:
215 if state in skip: 212 if state._opname in skip:
216 continue 213 continue
217 if statedetectionpredicate(repo): 214 if state.isunfinished(repo):
218 return (state, statedetectionpredicate, msgfn) 215 return (state._opname, state.statusmsg())