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()) |