Cleaning the whitespaces in code.
[AurShell.git] / pyshell.py
bloba7f9e2de3021818798c53c479282a66999f8e5b4
1 #!/usr/bin/python
2 # -*- coding: utf-8-*-
4 """
5 Aur Shell is simple shell framework.
7 To use it, write some plugins that Aur Shell would use.
8 """
10 import cmd
11 import string
12 import sys
13 import os
14 #import os.path
15 #import types
16 import readline
18 import conf
19 from showinfo import Put
21 __version__ = "0.1"
24 class AurShell(cmd.Cmd):
25 """Interactive shell framework.
26 To use it, write some modules, becouse by default it's very poor shell.
27 """
28 def __init__(self):
29 cmd.Cmd.__init__(self)
30 # use it instead of plain `print`
31 self.put = Put()
32 self.conf = conf
33 # prefix for method callable by shell
34 self.cmdprefix = "do_"
35 self.prompt = conf.shell_prompt
36 # plugins dict
37 self.commands = self.load_plugins(conf.modules_path)
38 # intro message
39 self.intro = "\n\tWelcome to aurShell v%(__version__)s\n" % globals()
40 # load history, create empty file if history doesn't exist
41 if not os.path.isfile(conf.history_file):
42 open(conf.history_file, "w").close()
43 readline.read_history_file(conf.history_file)
44 readline.set_history_length(conf.history_length)
45 # create build_dir if doesn't exist
46 if not os.path.isdir(conf.build_dir):
47 os.mkdir(conf.build_dir)
49 def load_plugins(self, modules_path):
50 """Load all commands modules from modules_path direcotory."""
51 command_modules = []
52 # adding plugins path to sys.path
53 if modules_path not in sys.path:
54 sys.path.append(modules_path)
55 # importing all modules from modules_path
56 for module_name in os.listdir(modules_path):
57 module_path = os.path.abspath(
58 string.join(modules_path, module_name))
59 (module_name, module_extension) = os.path.splitext(module_name)
60 # if it shouldn't be load
61 if os.path.islink(module_path) or \
62 module_path == __file__ or \
63 module_extension != ".py":
64 continue
65 for key in sys.modules.keys():
66 if key == module_name:
67 del sys.modules[key]
68 module = __import__(module_name)
69 command_modules.append({"obj": module_name, "name": module,})
70 # search for class in each module
71 module_objs = {}
72 for module in command_modules:
73 for obj in dir(module["name"]):
74 # TODO
75 # better class serch 2008-01-27 16:56:42
76 if not obj.startswith("_"):
77 try:
78 # check if it's method
79 x = getattr(module['name'], obj)(self.put, conf)
80 # create instance for each class
81 # as agrument give it Put() class instance
82 module_objs[obj] = \
83 getattr(module['name'], obj)(self.put, conf)
84 except TypeError:
85 pass
86 return module_objs
88 def precmd(self, cmd):
89 # check if alias exists and if so, replace command
90 for alias in conf.alias.keys():
91 # command should start with alias, but:
92 # - next char should be white space, or
93 # - there's no next char
94 if cmd.startswith(alias) and \
95 (len(cmd) <= len(alias) or cmd[len(alias)] == " "):
96 cmd = cmd.replace(alias, conf.alias[alias], 1)
97 return cmd
99 def do_shell(self, cmd):
100 """System shell command, for commads which starts with !"""
101 os.system(cmd)
103 def default(self, cmd=None):
104 """Run commands.
106 cmd = (<class>, [method], [arg1], [arg2], ...)
108 # cmd[0] should be class name
109 # cmd[1] should be method name (or arugmet if class is callable)
110 # cmd[1] can be empty
111 # cmd[2:] should be method argumments, can be empty
112 cmd = cmd.split()
113 # operations for single command with no arguments
114 if len(cmd) == 1:
115 # if there's no such command (or plugin class)
116 if not cmd[0] in self.commands.keys():
117 self.put("%s : command not found." % cmd[0])
118 # for only one argument, try to run __call__() method with
119 # no arguments
120 elif "__call__" in dir(self.commands[cmd[0]]):
121 getattr(self.commands[cmd[0]], "__call__")()
122 else:
123 self.put("%s : bad usege. Try to run help." % cmd[0])
124 # if command was called with arguments
125 elif len(cmd) > 1:
126 cmd[1] = self.cmdprefix + cmd[1]
127 if not cmd[0] in self.commands.keys():
128 self.put("%s : command not found." % cmd[0])
129 # if method named arg[1] exist in class arg[0], try to run it
130 elif cmd[1] in dir(self.commands[cmd[0]]):
131 #print dir(self.commands[cmd[0]])
132 try:
133 getattr(self.commands[cmd[0]], cmd[1])(*cmd[2:])
134 except TypeError:
135 # show __doc__ if exist
136 doc = getattr(self.commands[cmd[0]], cmd[1])
137 if doc.__doc__:
138 self.put(doc.__doc__)
139 else:
140 self.put("%s : bad usage" % cmd[1][3:])
141 # if there's no such method arg[1] in class arg[0],
142 # try to run class.__call__(args..)
143 else:
144 try:
145 self.commands[cmd[0]](*cmd[1:])
146 except TypeError:
147 # object is not callable
148 self.put("%s : bad usage" % cmd[0])
150 def completenames(self, text, *ignored):
151 """Complete commands"""
152 dotext = self.cmdprefix + text
153 # local methods
154 local_cmd_list = \
155 [a[3:] + " " for a in self.get_names() if a.startswith(dotext)]
156 # + all metrods from modules
157 module_cmd_list = \
158 [a + " " for a in self.commands.keys() if a.startswith(text)]
159 # + all aliases
160 aliases_cmd_list = \
161 [a + " " for a in self.conf.alias.keys() if a.startswith(text)]
162 return local_cmd_list + module_cmd_list + aliases_cmd_list
164 def completedefault(self, text, line, begidx, endidx):
165 """Complete commands argument"""
166 dotext = self.cmdprefix + text
167 line = line.split()
168 # if only commands was given
169 if len(line) == 1:
170 cmds = [a[3:] + " " for a in dir(self.commands[line[0]]) \
171 if a.startswith(dotext)]
172 elif len(line) == 2:
173 cmds = [a[3:] + " " for a in dir(self.commands[line[0]]) \
174 if a.startswith(dotext)]
175 # else don't complete (or should I?)
176 else:
177 cmds = []
178 return cmds
180 def do_help(self, arg):
181 """Show help for commands"""
182 arg = arg.split()
183 if not arg:
184 self.put("Usage: help <command>")
185 elif len(arg) == 1:
186 # first - build-in methods
187 if self.cmdprefix + arg[0] in dir(self):
188 doc = getattr(self, self.cmdprefix + arg[0]).__doc__
189 if doc:
190 self.put(doc)
191 # modules help
192 else:
193 try:
194 # try to run help() method
195 self.put(getattr(self.commands[arg[0]], "help")())
196 except AttributeError:
197 # try to show __doc__
198 if self.commands[arg[0]].__doc__:
199 self.put(self.commands[arg[0]].__doc__)
200 else:
201 self.put("No help found.")
202 except KeyError:
203 self.put("No help found.")
205 elif len(arg) == 2:
206 try:
207 if arg[0] in self.commands.keys():
208 arg[1] = self.cmdprefix + arg[1]
209 doc = getattr(self.commands[arg[0]], arg[1]).__doc__
210 self.put(doc)
211 except AttributeError:
212 self.put("%s : no help found" % arg[1][3:])
213 else:
214 self.put("Try to do something else.\nThis option doesn't work well now.")
216 def do_clear(self, *ignored):
217 """Clear the screen"""
218 # TODO 2008-02-09 20:44:50
219 self.put("Todo, sorry")
221 def do_history(self, hnumb=None, *ignored):
222 """Show the history"""
223 # TODO better history listing
224 # 2008-01-27 18:51:22
225 # print whole history
226 if not hnumb:
227 for number in range(1, conf.history_length):
228 cmd = readline.get_history_item(number)
229 if not cmd:
230 break
231 self.put("%6d %s" % (number, cmd))
232 # for history range 12-22 or -22 or 22-
233 else:
234 try:
235 if "-" in hnumb:
236 if hnumb[-1] == "-" or hnumb[0] == "-":
237 start = int(hnumb.replace("-", " "))
238 end = conf.history_length
239 else:
240 start, end = hnumb.split("-")
241 start = int(start)
242 end = int(end) + 1
243 for number in range(start, end):
244 cmd = readline.get_history_item(number)
245 if not cmd:
246 break
247 self.put("%6d %s" % (number, cmd))
248 else:
249 hnumb = int(hnumb)
250 self.put(readline.get_history_item(hnumb))
251 except ValueError:
252 self.put("""Bad value.
253 Usage: history <number or range>
254 history 11-20 -> from 11 to 20
255 history 22- -> from 22 fo the end of history file
256 history -22 -> same as 22-""")
258 def do_quit(self, *ignored):
259 """Quit from shell"""
260 if conf.history_length:
261 readline.write_history_file(conf.history_file)
262 print ""
263 sys.exit(1)
265 # function aliases
266 do_EOF = do_quit
267 do_exit = do_quit
270 if __name__ == "__main__":
271 shell = AurShell()
272 try:
273 shell.cmdloop()
274 except KeyboardInterrupt:
275 # TODO 2008-01-27 16:56:31
276 sys.exit(shell.do_quit())