Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / commands / history.py @ 16d7b9ff

History | View | Annotate | Download (7.3 kB)

1 73e0914d Stavros Sachtouris
#!/usr/bin/env python
2 73e0914d Stavros Sachtouris
3 e3f01d64 Stavros Sachtouris
# Copyright 2012-2013 GRNET S.A. All rights reserved.
4 73e0914d Stavros Sachtouris
#
5 73e0914d Stavros Sachtouris
# Redistribution and use in source and binary forms, with or
6 73e0914d Stavros Sachtouris
# without modification, are permitted provided that the following
7 73e0914d Stavros Sachtouris
# conditions are met:
8 73e0914d Stavros Sachtouris
#
9 73e0914d Stavros Sachtouris
#   1. Redistributions of source code must retain the above
10 73e0914d Stavros Sachtouris
#      copyright notice, this list of conditions and the following
11 73e0914d Stavros Sachtouris
#      disclaimer.
12 73e0914d Stavros Sachtouris
#
13 73e0914d Stavros Sachtouris
#   2. Redistributions in binary form must reproduce the above
14 73e0914d Stavros Sachtouris
#      copyright notice, this list of conditions and the following
15 73e0914d Stavros Sachtouris
#      disclaimer in the documentation and/or other materials
16 73e0914d Stavros Sachtouris
#      provided with the distribution.
17 73e0914d Stavros Sachtouris
#
18 73e0914d Stavros Sachtouris
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
19 73e0914d Stavros Sachtouris
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 73e0914d Stavros Sachtouris
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 73e0914d Stavros Sachtouris
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
22 73e0914d Stavros Sachtouris
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 73e0914d Stavros Sachtouris
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 73e0914d Stavros Sachtouris
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
25 73e0914d Stavros Sachtouris
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 73e0914d Stavros Sachtouris
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 73e0914d Stavros Sachtouris
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 73e0914d Stavros Sachtouris
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 73e0914d Stavros Sachtouris
# POSSIBILITY OF SUCH DAMAGE.
30 73e0914d Stavros Sachtouris
#
31 73e0914d Stavros Sachtouris
# The views and conclusions contained in the software and
32 73e0914d Stavros Sachtouris
# documentation are those of the authors and should not be
33 73e0914d Stavros Sachtouris
# interpreted as representing official policies, either expressed
34 73e0914d Stavros Sachtouris
# or implied, of GRNET S.A.
35 73e0914d Stavros Sachtouris
36 d486baec Stavros Sachtouris
from kamaki.cli.command_tree import CommandTree
37 234954d1 Stavros Sachtouris
from kamaki.cli.argument import IntArgument, ValueArgument
38 fce93ff6 Stavros Sachtouris
from kamaki.cli.argument import ArgumentParseManager
39 73e0914d Stavros Sachtouris
from kamaki.cli.history import History
40 73e0914d Stavros Sachtouris
from kamaki.cli import command
41 dc6fc88e Stavros Sachtouris
from kamaki.cli.commands import _command_init, errors
42 b6a99832 Stavros Sachtouris
from kamaki.cli import exec_cmd, print_error_message
43 dc6fc88e Stavros Sachtouris
from kamaki.cli.errors import CLIError, raiseCLIError
44 76f58e2e Stavros Sachtouris
from kamaki.cli.utils import split_input
45 fce93ff6 Stavros Sachtouris
from kamaki.clients import ClientError
46 73e0914d Stavros Sachtouris
47 234954d1 Stavros Sachtouris
48 a29d2f88 Stavros Sachtouris
history_cmds = CommandTree('history', 'Kamaki command history')
49 db950b10 Stavros Sachtouris
_commands = [history_cmds]
50 234954d1 Stavros Sachtouris
51 234954d1 Stavros Sachtouris
52 00ef4ab6 Stavros Sachtouris
def _get_num_list(num_str):
53 00ef4ab6 Stavros Sachtouris
    if num_str.startswith('-'):
54 00ef4ab6 Stavros Sachtouris
        num1, sep, num2 = num_str[1:].partition('-')
55 00ef4ab6 Stavros Sachtouris
        num1 = '-%s' % num1
56 00ef4ab6 Stavros Sachtouris
    else:
57 00ef4ab6 Stavros Sachtouris
        num1, sep, num2 = num_str.partition('-')
58 00ef4ab6 Stavros Sachtouris
    (num1, num2) = (num1.strip(), num2.strip())
59 00ef4ab6 Stavros Sachtouris
    try:
60 00ef4ab6 Stavros Sachtouris
        num1 = (-int(num1[1:])) if num1.startswith('-') else int(num1)
61 00ef4ab6 Stavros Sachtouris
    except ValueError as e:
62 00ef4ab6 Stavros Sachtouris
        raiseCLIError(e, 'Invalid id %s' % num1)
63 00ef4ab6 Stavros Sachtouris
    if sep:
64 00ef4ab6 Stavros Sachtouris
        try:
65 00ef4ab6 Stavros Sachtouris
            num2 = (-int(num2[1:])) if num2.startswith('-') else int(num2)
66 519d8639 Stavros Sachtouris
            num2 += 1 if num2 > 0 else 0
67 00ef4ab6 Stavros Sachtouris
        except ValueError as e:
68 00ef4ab6 Stavros Sachtouris
            raiseCLIError(e, 'Invalid id %s' % num2)
69 00ef4ab6 Stavros Sachtouris
    else:
70 00ef4ab6 Stavros Sachtouris
        num2 = (1 + num1) if num1 else 0
71 00ef4ab6 Stavros Sachtouris
    return [i for i in range(num1, num2)]
72 00ef4ab6 Stavros Sachtouris
73 00ef4ab6 Stavros Sachtouris
74 5eae854d Stavros Sachtouris
class _init_history(_command_init):
75 a03ade9e Stavros Sachtouris
    @errors.generic.all
76 dc6fc88e Stavros Sachtouris
    @errors.history.init
77 dc6fc88e Stavros Sachtouris
    def _run(self):
78 99085b30 Stavros Sachtouris
        self.history = History(self.config.get_global('history_file'))
79 234954d1 Stavros Sachtouris
80 dc6fc88e Stavros Sachtouris
    def main(self):
81 dc6fc88e Stavros Sachtouris
        self._run()
82 dc6fc88e Stavros Sachtouris
83 73e0914d Stavros Sachtouris
84 d486baec Stavros Sachtouris
@command(history_cmds)
85 d53062bd Stavros Sachtouris
class history_show(_init_history):
86 c5bcc3e3 Stavros Sachtouris
    """Show intersession command history
87 c5bcc3e3 Stavros Sachtouris
    ---
88 439826ec Stavros Sachtouris
    - With no parameters : pick all commands in history records
89 439826ec Stavros Sachtouris
    - With:
90 439826ec Stavros Sachtouris
    .   1.  <order-id> : pick the <order-id>th command
91 439826ec Stavros Sachtouris
    .   2.  <order-id-1>-<order-id-2> : pick all commands ordered in the range
92 439826ec Stavros Sachtouris
    .       [<order-id-1> - <order-id-2>]
93 439826ec Stavros Sachtouris
    .   - the above can be mixed and repeated freely, separated by spaces
94 16d7b9ff Stavros Sachtouris
    .       e.g., pick 2 4-7 -3
95 16d7b9ff Stavros Sachtouris
    .   - Use negative integers to count from the end of the list, e.g.,:
96 439826ec Stavros Sachtouris
    .       -2 means : the command before the last one
97 439826ec Stavros Sachtouris
    .       -2-5 means : last 2 commands + the first 5
98 439826ec Stavros Sachtouris
    .       -5--2 means : the last 5 commands except the last 2
99 c5bcc3e3 Stavros Sachtouris
    """
100 234954d1 Stavros Sachtouris
101 746bd77f Stavros Sachtouris
    arguments = dict(
102 f40f0cb7 Stavros Sachtouris
        limit=IntArgument(
103 f40f0cb7 Stavros Sachtouris
            'number of lines to show',
104 f40f0cb7 Stavros Sachtouris
            ('-n', '--numner'),
105 f40f0cb7 Stavros Sachtouris
            default=0),
106 746bd77f Stavros Sachtouris
        match=ValueArgument('show lines that match given terms', '--match')
107 746bd77f Stavros Sachtouris
    )
108 73e0914d Stavros Sachtouris
109 dc6fc88e Stavros Sachtouris
    @errors.generic.all
110 dc6fc88e Stavros Sachtouris
    def _run(self, *cmd_ids):
111 746bd77f Stavros Sachtouris
        ret = self.history.get(match_terms=self['match'], limit=self['limit'])
112 00ef4ab6 Stavros Sachtouris
113 00ef4ab6 Stavros Sachtouris
        if not cmd_ids:
114 76f58e2e Stavros Sachtouris
            self.print_list(ret)
115 00ef4ab6 Stavros Sachtouris
            return
116 00ef4ab6 Stavros Sachtouris
117 00ef4ab6 Stavros Sachtouris
        num_list = []
118 00ef4ab6 Stavros Sachtouris
        for num_str in cmd_ids:
119 00ef4ab6 Stavros Sachtouris
            num_list += _get_num_list(num_str)
120 00ef4ab6 Stavros Sachtouris
121 00ef4ab6 Stavros Sachtouris
        for cmd_id in num_list:
122 660a0dad Stavros Sachtouris
            try:
123 519d8639 Stavros Sachtouris
                cur_id = int(cmd_id)
124 519d8639 Stavros Sachtouris
                if cur_id:
125 3185cd6d Stavros Sachtouris
                    self.writeln(ret[cur_id - (1 if cur_id > 0 else 0)][:-1])
126 660a0dad Stavros Sachtouris
            except IndexError as e2:
127 660a0dad Stavros Sachtouris
                raiseCLIError(e2, 'Command id out of 1-%s range' % len(ret))
128 73e0914d Stavros Sachtouris
129 dc6fc88e Stavros Sachtouris
    def main(self, *cmd_ids):
130 dc6fc88e Stavros Sachtouris
        super(self.__class__, self)._run()
131 dc6fc88e Stavros Sachtouris
        self._run(*cmd_ids)
132 dc6fc88e Stavros Sachtouris
133 73e0914d Stavros Sachtouris
134 d486baec Stavros Sachtouris
@command(history_cmds)
135 73e0914d Stavros Sachtouris
class history_clean(_init_history):
136 c5bcc3e3 Stavros Sachtouris
    """Clean up history (permanent)"""
137 73e0914d Stavros Sachtouris
138 dc6fc88e Stavros Sachtouris
    @errors.generic.all
139 dc6fc88e Stavros Sachtouris
    def _run(self):
140 234954d1 Stavros Sachtouris
        self.history.clean()
141 304c90b5 Stavros Sachtouris
142 dc6fc88e Stavros Sachtouris
    def main(self):
143 dc6fc88e Stavros Sachtouris
        super(self.__class__, self)._run()
144 dc6fc88e Stavros Sachtouris
        self._run()
145 dc6fc88e Stavros Sachtouris
146 33b3595a Stavros Sachtouris
147 304c90b5 Stavros Sachtouris
@command(history_cmds)
148 519d8639 Stavros Sachtouris
class history_run(_init_history):
149 68ab0942 Stavros Sachtouris
    """Run previously executed command(s)
150 c5bcc3e3 Stavros Sachtouris
    Use with:
151 439826ec Stavros Sachtouris
    .   1.  <order-id> : pick the <order-id>th command
152 439826ec Stavros Sachtouris
    .   2.  <order-id-1>-<order-id-2> : pick all commands ordered in the range
153 439826ec Stavros Sachtouris
    .       [<order-id-1> - <order-id-2>]
154 16d7b9ff Stavros Sachtouris
    .   - Use negative integers to count from the end of the list, e.g.,:
155 439826ec Stavros Sachtouris
    .       -2 means : the command before the last one
156 439826ec Stavros Sachtouris
    .       -2-5 means : last 2 commands + the first 5
157 439826ec Stavros Sachtouris
    .       -5--2 mean
158 439826ec Stavros Sachtouris
    .   - to find order ids for commands try   /history show.
159 68ab0942 Stavros Sachtouris
    """
160 304c90b5 Stavros Sachtouris
161 33b3595a Stavros Sachtouris
    _cmd_tree = None
162 33b3595a Stavros Sachtouris
163 f724cd35 Stavros Sachtouris
    def __init__(self, arguments={}, auth_base=None, cmd_tree=None):
164 0ec19fd3 Stavros Sachtouris
        super(self.__class__, self).__init__(arguments, auth_base=auth_base)
165 33b3595a Stavros Sachtouris
        self._cmd_tree = cmd_tree
166 33b3595a Stavros Sachtouris
167 dc6fc88e Stavros Sachtouris
    @errors.generic.all
168 fce93ff6 Stavros Sachtouris
    def _run_from_line(self, line):
169 fce93ff6 Stavros Sachtouris
        terms = split_input(line)
170 fce93ff6 Stavros Sachtouris
        cmd, args = self._cmd_tree.find_best_match(terms)
171 c49188b7 Stavros Sachtouris
        if cmd.is_command:
172 c49188b7 Stavros Sachtouris
            try:
173 c49188b7 Stavros Sachtouris
                instance = cmd.cmd_class(
174 c49188b7 Stavros Sachtouris
                    self.arguments, auth_base=getattr(self, 'auth_base', None))
175 c49188b7 Stavros Sachtouris
                instance.config = self.config
176 c49188b7 Stavros Sachtouris
                prs = ArgumentParseManager(
177 c49188b7 Stavros Sachtouris
                    cmd.path.split(), dict(instance.arguments))
178 c49188b7 Stavros Sachtouris
                prs.syntax = '%s %s' % (
179 c49188b7 Stavros Sachtouris
                    cmd.path.replace('_', ' '), cmd.cmd_class.syntax)
180 c49188b7 Stavros Sachtouris
                prs.parse(args)
181 c49188b7 Stavros Sachtouris
                exec_cmd(instance, prs.unparsed, prs.parser.print_help)
182 c49188b7 Stavros Sachtouris
            except (CLIError, ClientError) as err:
183 c49188b7 Stavros Sachtouris
                print_error_message(err, self._err)
184 c49188b7 Stavros Sachtouris
            except Exception as e:
185 c49188b7 Stavros Sachtouris
                self.error('Execution of [ %s ] failed\n\t%s' % (line, e))
186 fce93ff6 Stavros Sachtouris
187 a03ade9e Stavros Sachtouris
    @errors.generic.all
188 dc6fc88e Stavros Sachtouris
    @errors.history._get_cmd_ids
189 f2e2663e Stavros Sachtouris
    def _get_cmd_ids(self, cmd_ids):
190 f2e2663e Stavros Sachtouris
        cmd_id_list = []
191 f2e2663e Stavros Sachtouris
        for cmd_str in cmd_ids:
192 00ef4ab6 Stavros Sachtouris
            cmd_id_list += _get_num_list(cmd_str)
193 f2e2663e Stavros Sachtouris
        return cmd_id_list
194 f2e2663e Stavros Sachtouris
195 dc6fc88e Stavros Sachtouris
    @errors.generic.all
196 dc6fc88e Stavros Sachtouris
    def _run(self, *command_ids):
197 f2e2663e Stavros Sachtouris
        cmd_list = self._get_cmd_ids(command_ids)
198 f2e2663e Stavros Sachtouris
        for cmd_id in cmd_list:
199 f2e2663e Stavros Sachtouris
            r = self.history.retrieve(cmd_id)
200 00ef4ab6 Stavros Sachtouris
            try:
201 3185cd6d Stavros Sachtouris
                self.writeln('< %s >' % r[:-1])
202 00ef4ab6 Stavros Sachtouris
            except (TypeError, KeyError):
203 519d8639 Stavros Sachtouris
                continue
204 f2e2663e Stavros Sachtouris
            if self._cmd_tree:
205 f2e2663e Stavros Sachtouris
                r = r[len('kamaki '):-1] if r.startswith('kamaki ') else r[:-1]
206 f2e2663e Stavros Sachtouris
                self._run_from_line(r)
207 dc6fc88e Stavros Sachtouris
208 dc6fc88e Stavros Sachtouris
    def main(self, *command_ids):
209 dc6fc88e Stavros Sachtouris
        super(self.__class__, self)._run()
210 dc6fc88e Stavros Sachtouris
        self._run(*command_ids)