mercurial/state.py
changeset 42532 12243f15d53e
parent 42531 5bddd2244814
child 42533 0231032729c4
equal deleted inserted replaced
42531:5bddd2244814 42532: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())