1 # Copyright (C) 2008-2010 Alberto Gomez-Casado
2 # Massimo Sandal <devicerandom@gmail.com>
3 # W. Trevor King <wking@drexel.edu>
5 # This file is part of Hooke.
7 # Hooke is free software: you can redistribute it and/or modify it
8 # under the terms of the GNU Lesser General Public License as
9 # published by the Free Software Foundation, either version 3 of the
10 # License, or (at your option) any later version.
12 # Hooke is distributed in the hope that it will be useful, but WITHOUT
13 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
15 # Public License for more details.
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with Hooke. If not, see
19 # <http://www.gnu.org/licenses/>.
21 """The ``command_stack`` module provides :class:`CommandStackPlugin`
22 and several associated :class:`~hooke.command.Command`\s exposing
23 :mod`hooke.command_stack`'s functionality.
27 from Queue import Queue
29 from ..command import Command, Argument, Success, Failure
30 from ..command_stack import CommandStack
31 from ..engine import CloseEngine, CommandMessage
35 # Define useful command subclasses
37 class CommandStackCommand (Command):
38 """Subclass to avoid pushing control commands to the stack.
40 def _set_state(self, state):
42 self.plugin.set_state(state)
44 self.plugin.log('raising error: %s' % e)
45 raise Failure('invalid state change: %s' % e.state_change)
48 class CaptureCommand (CommandStackCommand):
49 """Run a mock-engine and save the incoming commands.
53 Due to limitations in the --script and --command option
54 implementations in ./bin/hooke, capture sessions will die at the
55 end of the script and command execution before entering
56 --persist's interactive session.
58 def __init__(self, name, plugin):
59 super(CaptureCommand, self).__init__(
60 name=name, help=self.__doc__, plugin=plugin)
62 def _run(self, hooke, inqueue, outqueue, params):
63 # TODO: possibly merge code with CommandEngine.run()
65 # Fake successful completion so UI continues sending commands.
66 outqueue.put(Success())
70 if isinstance(msg, CloseEngine):
71 outqueue.put('CloseEngine')
72 inqueue.put(msg) # Put CloseEngine back for CommandEngine.
73 self._set_state('inactive')
75 assert isinstance(msg, CommandMessage), type(msg)
76 cmd = hooke.command_by_name[msg.command]
77 if isinstance(cmd, CommandStackCommand):
78 if isinstance(cmd, StopCaptureCommand):
79 outqueue = Queue() # Grab StopCaptureCommand's completion.
80 cmd.run(hooke, inqueue, outqueue, **msg.arguments)
81 if isinstance(cmd, StopCaptureCommand):
82 assert self.plugin.state == 'inactive', self.plugin.state
83 # Return the stolen completion as our own.
84 raise outqueue.get(block=False)
86 self.plugin.log('appending %s' % msg)
87 self.plugin.command_stack.append(msg)
88 # Fake successful completion so UI continues sending commands.
89 outqueue.put(Success())
94 class CommandStackPlugin (Builtin):
96 super(CommandStackPlugin, self).__init__(name='command_stack')
98 StartCaptureCommand(self), StopCaptureCommand(self),
99 ReStartCaptureCommand(self),
100 PopCommand(self), GetCommand(self), GetStateCommand(self),
101 SaveCommand(self), LoadCommand(self),
103 self.command_stack = CommandStack()
105 self.state = 'inactive'
106 # inactive <-> active.
107 self._valid_transitions = {
108 'inactive': ['active'],
109 'active': ['inactive'],
113 log = logging.getLogger('hooke')
114 log.debug('%s %s' % (self.name, msg))
116 def set_state(self, state):
117 state_change = '%s -> %s' % (self.state, state)
118 self.log('changing state: %s' % state_change)
119 if state not in self._valid_transitions[self.state]:
120 e = ValueError(state)
121 e.state_change = state_change
128 class StartCaptureCommand (CaptureCommand):
129 """Clear any previous stack and run the mock-engine.
131 def __init__(self, plugin):
132 super(StartCaptureCommand, self).__init__(
133 name='start command capture', plugin=plugin)
135 def _run(self, hooke, inqueue, outqueue, params):
136 self._set_state('active')
137 self.plugin.command_stack = CommandStack() # clear command stack
138 super(StartCaptureCommand, self)._run(hooke, inqueue, outqueue, params)
141 class ReStartCaptureCommand (CaptureCommand):
142 """Run the mock-engine.
144 def __init__(self, plugin):
145 super(ReStartCaptureCommand, self).__init__(
146 name='restart command capture', plugin=plugin)
148 def _run(self, hooke, inqueue, outqueue, params):
149 self._set_state('active')
150 super(ReStartCaptureCommand, self)._run(hooke, inqueue, outqueue, params)
153 class StopCaptureCommand (CommandStackCommand):
154 """Stop the mock-engine.
156 def __init__(self, plugin):
157 super(StopCaptureCommand, self).__init__(
158 name='stop command capture', help=self.__doc__, plugin=plugin)
160 def _run(self, hooke, inqueue, outqueue, params):
161 self._set_state('inactive')
164 class PopCommand (CommandStackCommand):
165 """Pop the top command off the stack.
167 def __init__(self, plugin):
168 super(PopCommand, self).__init__(
169 name='pop command from stack', help=self.__doc__, plugin=plugin)
171 def _run(self, hooke, inqueue, outqueue, params):
172 outqueue.put(self.plugin.command_stack.pop())
175 class GetCommand (CommandStackCommand):
176 """Return the command stack.
178 def __init__(self, plugin):
179 super(GetCommand, self).__init__(
180 name='get command stack', help=self.__doc__, plugin=plugin)
182 def _run(self, hooke, inqueue, outqueue, params):
183 outqueue.put(self.plugin.command_stack)
185 class GetStateCommand (CommandStackCommand):
186 """Return the mock-engine state.
188 def __init__(self, plugin):
189 super(GetStateCommand, self).__init__(
190 name='get command capture state', help=self.__doc__, plugin=plugin)
192 def _run(self, hooke, inqueue, outqueue, params):
193 outqueue.put(self.plugin.state)
196 class SaveCommand (CommandStackCommand):
197 """Save the command stack.
199 def __init__(self, plugin):
200 super(SaveCommand, self).__init__(
201 name='save command stack', help=self.__doc__, plugin=plugin)
203 def _run(self, hooke, inqueue, outqueue, params):
207 class LoadCommand (CommandStackCommand):
208 """Load the command stack.
210 def __init__(self, plugin):
211 super(LoadCommand, self).__init__(
212 name='load command stack', help=self.__doc__, plugin=plugin)
214 def _run(self, hooke, inqueue, outqueue, params):