1
2
3
4
5
6
7
8
9
10
11
12
13
14 import os.path
15 import sys
16 import traceback
17
18 from trac.core import *
19 from trac.util.text import levenshtein_distance
20 from trac.util.translation import _
21
22
23 console_date_format = '%Y-%m-%d'
24 console_datetime_format = '%Y-%m-%d %H:%M:%S'
25 console_date_format_hint = 'YYYY-MM-DD'
26
27
29 """Extension point interface for adding panels to the web-based
30 administration interface.
31 """
32
34 """Return a list of available admin panels.
35
36 The items returned by this function must be tuples of the form
37 `(category, category_label, page, page_label)`.
38 """
39
41 """Process a request for an admin panel.
42
43 This function should return a tuple of the form `(template, data)`,
44 where `template` is the name of the template to use and `data` is the
45 data to be passed to the template.
46 """
47
48
50 """Exception raised when an admin command cannot be executed."""
51 - def __init__(self, msg, show_usage=False, cmd=None):
55
56
58 """Extension point interface for adding commands to the console
59 administration interface `trac-admin`.
60 """
61
63 """Return a list of available admin commands.
64
65 The items returned by this function must be tuples of the form
66 `(command, args, help, complete, execute)`, where `command` contains
67 the space-separated command and sub-command names, `args` is a string
68 describing the command arguments and `help` is the help text. The
69 first paragraph of the help text is taken as a short help, shown in the
70 list of commands.
71
72 `complete` is called to auto-complete the command arguments, with the
73 current list of arguments as its only argument. It should return a list
74 of relevant values for the last argument in the list.
75
76 `execute` is called to execute the command, with the command arguments
77 passed as positional arguments.
78 """
79
80
82 """trac-admin command manager."""
83
84 providers = ExtensionPoint(IAdminCommandProvider)
85
87 """Return help information for a set of commands."""
88 commands = []
89 for provider in self.providers:
90 for cmd in provider.get_admin_commands() or []:
91 parts = cmd[0].split()
92 if parts[:len(args)] == args:
93 commands.append(cmd[:3])
94 commands.sort()
95 return commands
96
98 """Perform auto-completion on the given arguments."""
99 comp = []
100 for provider in self.providers:
101 for cmd in provider.get_admin_commands() or []:
102 parts = cmd[0].split()
103 plen = min(len(parts), len(args) - 1)
104 if args[:plen] != parts[:plen]:
105 continue
106 elif len(args) <= len(parts):
107 comp.append(parts[len(args) - 1])
108 elif not cmd_only:
109 if cmd[3] is None:
110 return []
111 return cmd[3](args[len(parts):]) or []
112 return comp
113
115 """Execute a command given by a list of arguments."""
116 args = list(args)
117 for provider in self.providers:
118 for cmd in provider.get_admin_commands() or []:
119 parts = cmd[0].split()
120 if args[:len(parts)] == parts:
121 f = cmd[4]
122 fargs = args[len(parts):]
123 try:
124 return f(*fargs)
125 except AdminCommandError, e:
126 e.cmd = ' '.join(parts)
127 raise
128 except TypeError, e:
129 tb = traceback.extract_tb(sys.exc_info()[2])
130 if len(tb) == 1:
131 raise AdminCommandError(_("Invalid arguments"),
132 show_usage=True,
133 cmd=' '.join(parts))
134 raise
135 raise AdminCommandError(_("Command not found"), show_usage=True)
136
138 if not arg:
139 return []
140
141 cmds = set()
142 for provider in self.providers:
143 for cmd in provider.get_admin_commands() or []:
144 cmds.add(cmd[0].split()[0])
145
146 def score(cmd, arg):
147 if cmd.startswith(arg):
148 return 0
149 return levenshtein_distance(cmd, arg) / float(len(cmd) + len(arg))
150 similars = sorted((score(cmd, arg), cmd) for cmd in cmds)
151 similars = [cmd for val, cmd in similars if val <= 0.5]
152 return similars[:n]
153
154
156 """A list of prefixes for command argument auto-completion."""
158 return list(set(a for a in self if a.startswith(text)))
159
160
162 return os.path.normcase(path).startswith(os.path.normcase(prefix))
163
164
166 """A list of paths for command argument auto-completion."""
168 """Return the items in the list matching text."""
169 matches = list(set(a for a in self if path_startswith(a, text)))
170 if len(matches) == 1 and not os.path.isdir(matches[0]):
171 matches[0] += ' '
172 return matches
173
174
176 """Return a list of paths to filesystem entries in the same directory
177 as the given path."""
178 dname = os.path.dirname(path)
179 d = os.path.join(os.getcwd(), dname)
180 result = PathList()
181 try:
182 dlist = os.listdir(d)
183 except OSError:
184 return result
185 for entry in dlist:
186 path = os.path.normpath(os.path.join(dname, entry))
187 try:
188 if os.path.isdir(path):
189 result.append(os.path.join(path, ''))
190 elif not dirs_only:
191 result.append(path)
192 except OSError:
193 pass
194 return result
195