Package trac :: Package admin :: Module api

Source Code for Module trac.admin.api

  1  # -*- coding: utf-8 -*- 
  2  #  
  3  # Copyright (C)2006-2009 Edgewall Software 
  4  # All rights reserved. 
  5  # 
  6  # This software is licensed as described in the file COPYING, which 
  7  # you should have received as part of this distribution. The terms 
  8  # are also available at http://trac.edgewall.org/wiki/TracLicense. 
  9  # 
 10  # This software consists of voluntary contributions made by many 
 11  # individuals. For the exact contribution history, see the revision 
 12  # history and logs, available at http://trac.edgewall.org/log/. 
 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   
28 -class IAdminPanelProvider(Interface):
29 """Extension point interface for adding panels to the web-based 30 administration interface. 31 """ 32
33 - def get_admin_panels(req):
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
40 - def render_admin_panel(req, category, page, path_info):
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
49 -class AdminCommandError(TracError):
50 """Exception raised when an admin command cannot be executed."""
51 - def __init__(self, msg, show_usage=False, cmd=None):
52 TracError.__init__(self, msg) 53 self.show_usage = show_usage 54 self.cmd = cmd
55 56
57 -class IAdminCommandProvider(Interface):
58 """Extension point interface for adding commands to the console 59 administration interface `trac-admin`. 60 """ 61
62 - def get_admin_commands():
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
81 -class AdminCommandManager(Component):
82 """trac-admin command manager.""" 83 84 providers = ExtensionPoint(IAdminCommandProvider) 85
86 - def get_command_help(self, args=[]):
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
97 - def complete_command(self, args, cmd_only=False):
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]: # Prefix doesn't match 105 continue 106 elif len(args) <= len(parts): # Command name 107 comp.append(parts[len(args) - 1]) 108 elif not cmd_only: # Arguments 109 if cmd[3] is None: 110 return [] 111 return cmd[3](args[len(parts):]) or [] 112 return comp
113
114 - def execute_command(self, *args):
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
137 - def get_similar_commands(self, arg, n=5):
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]) # use only first token 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
155 -class PrefixList(list):
156 """A list of prefixes for command argument auto-completion."""
157 - def complete(self, text):
158 return list(set(a for a in self if a.startswith(text)))
159 160
161 -def path_startswith(path, prefix):
162 return os.path.normcase(path).startswith(os.path.normcase(prefix))
163 164
165 -class PathList(list):
166 """A list of paths for command argument auto-completion."""
167 - def complete(self, text):
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
175 -def get_dir_list(path, dirs_only=False):
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