[Pkg-bazaar-commits] ./bzr/unstable r641: - improved external-command patch from john

Martin Pool mbp at sourcefrog.net
Fri Apr 10 08:20:33 UTC 2009


------------------------------------------------------------
revno: 641
committer: Martin Pool <mbp at sourcefrog.net>
timestamp: Fri 2005-06-10 12:21:14 +1000
message:
  - improved external-command patch from john
modified:
  bzrlib/commands.py
  testbzr
-------------- next part --------------
=== modified file 'bzrlib/commands.py'
--- a/bzrlib/commands.py	2005-06-10 01:48:19 +0000
+++ b/bzrlib/commands.py	2005-06-10 02:21:14 +0000
@@ -68,25 +68,107 @@
         revs = int(revstr)
     return revs
 
-def get_all_cmds():
-    """Return canonical name and class for all registered commands."""
+def _find_plugins():
+    """Find all python files which are plugins, and load their commands
+    to add to the list of "all commands"
+
+    The environment variable BZRPATH is considered a delimited set of
+    paths to look through. Each entry is searched for *.py files.
+    If a directory is found, it is also searched, but they are 
+    not searched recursively. This allows you to revctl the plugins.
+    
+    Inside the plugin should be a series of cmd_* function, which inherit from
+    the bzrlib.commands.Command class.
+    """
+    bzrpath = os.environ.get('BZRPLUGINPATH', '')
+
+    plugin_cmds = {} 
+    if not bzrpath:
+        return plugin_cmds
+    _platform_extensions = {
+        'win32':'.pyd',
+        'cygwin':'.dll',
+        'darwin':'.dylib',
+        'linux2':'.so'
+        }
+    if _platform_extensions.has_key(sys.platform):
+        platform_extension = _platform_extensions[sys.platform]
+    else:
+        platform_extension = None
+    for d in bzrpath.split(os.pathsep):
+        plugin_names = {} # This should really be a set rather than a dict
+        for f in os.listdir(d):
+            if f.endswith('.py'):
+                f = f[:-3]
+            elif f.endswith('.pyc') or f.endswith('.pyo'):
+                f = f[:-4]
+            elif platform_extension and f.endswith(platform_extension):
+                f = f[:-len(platform_extension)]
+                if f.endswidth('module'):
+                    f = f[:-len('module')]
+            else:
+                continue
+            if not plugin_names.has_key(f):
+                plugin_names[f] = True
+
+        plugin_names = plugin_names.keys()
+        plugin_names.sort()
+        try:
+            sys.path.insert(0, d)
+            for name in plugin_names:
+                try:
+                    old_module = None
+                    try:
+                        if sys.modules.has_key(name):
+                            old_module = sys.modules[name]
+                            del sys.modules[name]
+                        plugin = __import__(name, locals())
+                        for k in dir(plugin):
+                            if k.startswith('cmd_'):
+                                k_unsquished = _unsquish_command_name(k)
+                                if not plugin_cmds.has_key(k_unsquished):
+                                    plugin_cmds[k_unsquished] = getattr(plugin, k)
+                                else:
+                                    log_error('Two plugins defined the same command: %r' % k)
+                                    log_error('Not loading the one in %r in dir %r' % (name, d))
+                    finally:
+                        if old_module:
+                            sys.modules[name] = old_module
+                except ImportError, e:
+                    log_error('Unable to load plugin: %r from %r\n%s' % (name, d, e))
+        finally:
+            sys.path.pop(0)
+    return plugin_cmds
+
+def _get_cmd_dict(include_plugins=True):
+    d = {}
     for k, v in globals().iteritems():
         if k.startswith("cmd_"):
-            yield _unsquish_command_name(k), v
-
-def get_cmd_class(cmd):
+            d[_unsquish_command_name(k)] = v
+    if include_plugins:
+        d.update(_find_plugins())
+    return d
+    
+def get_all_cmds(include_plugins=True):
+    """Return canonical name and class for all registered commands."""
+    for k, v in _get_cmd_dict(include_plugins=include_plugins).iteritems():
+        yield k,v
+
+
+def get_cmd_class(cmd,include_plugins=True):
     """Return the canonical name and command class for a command.
     """
     cmd = str(cmd)                      # not unicode
 
     # first look up this command under the specified name
+    cmds = _get_cmd_dict(include_plugins=include_plugins)
     try:
-        return cmd, globals()[_squish_command_name(cmd)]
+        return cmd, cmds[cmd]
     except KeyError:
         pass
 
     # look for any command which claims this as an alias
-    for cmdname, cmdclass in get_all_cmds():
+    for cmdname, cmdclass in cmds.iteritems():
         if cmd in cmdclass.aliases:
             return cmdname, cmdclass
 
@@ -165,7 +247,7 @@
         import os.path
         bzrpath = os.environ.get('BZRPATH', '')
 
-        for dir in bzrpath.split(':'):
+        for dir in bzrpath.split(os.pathsep):
             path = os.path.join(dir, cmd)
             if os.path.isfile(path):
                 return ExternalCommand(path)
@@ -1326,6 +1408,7 @@
     """
     argv = [a.decode(bzrlib.user_encoding) for a in argv]
     
+    include_plugins=True
     try:
         args, opts = parse_args(argv[1:])
         if 'help' in opts:
@@ -1338,6 +1421,9 @@
         elif 'version' in opts:
             show_version()
             return 0
+        elif args and args[0] == 'builtin':
+            include_plugins=False
+            args = args[1:]
         cmd = str(args.pop(0))
     except IndexError:
         import help
@@ -1345,7 +1431,7 @@
         return 1
           
 
-    canonical_cmd, cmd_class = get_cmd_class(cmd)
+    canonical_cmd, cmd_class = get_cmd_class(cmd,include_plugins=include_plugins)
 
     # global option
     if 'profile' in opts:

=== modified file 'testbzr'
--- a/testbzr	2005-06-06 11:53:29 +0000
+++ b/testbzr	2005-06-10 02:21:14 +0000
@@ -145,6 +145,54 @@
 
 logfile = open(LOGFILENAME, 'wt', buffering=1)
 
+def test_plugins():
+    """Run a test involving creating a plugin to load,
+    and making sure it is seen properly.
+    """
+    mkdir('plugin_test')
+    f = open(os.path.join('plugin_test', 'myplug.py'), 'wb')
+    f.write("""import bzrlib, bzrlib.commands
+class cmd_myplug(bzrlib.commands.Command):
+    '''Just a simple test plugin.'''
+    aliases = ['mplg']
+    def run(self):
+        print 'Hello from my plugin'
+""")
+    f.close()
+
+    os.environ['BZRPLUGINPATH'] = os.path.abspath('plugin_test')
+    help = backtick('bzr help commands')
+    assert help.find('myplug') != -1
+    assert help.find('Just a simple test plugin.') != -1
+
+    
+    assert backtick('bzr myplug') == 'Hello from my plugin\n'
+    assert backtick('bzr mplg') == 'Hello from my plugin\n'
+
+    f = open(os.path.join('plugin_test', 'override.py'), 'wb')
+    f.write("""import bzrlib, bzrlib.commands
+class cmd_commit(bzrlib.commands.cmd_commit):
+    '''Commit changes into a new revision.'''
+    def run(self, *args, **kwargs):
+        print "I'm sorry dave, you can't do that"
+
+class cmd_help(bzrlib.commands.cmd_help):
+    '''Show help on a command or other topic.'''
+    def run(self, *args, **kwargs):
+        print "You have been overridden"
+        bzrlib.commands.cmd_help.run(self, *args, **kwargs)
+
+""")
+    f.close()
+
+    newhelp = backtick('bzr help commands')
+    assert newhelp.startswith('You have been overridden\n')
+    # We added a line, but the rest should work
+    assert newhelp[25:] == help
+
+    assert backtick('bzr commit -m test') == "I'm sorry dave, you can't do that\n"
+    
+    shutil.rmtree('plugin_test')
 
 try:
     from getopt import getopt
@@ -456,6 +504,15 @@
 
 
 
+    # Run any function in this 
+    g = globals()
+    funcs = g.keys()
+    funcs.sort()
+    for k in funcs:
+        if k.startswith('test_') and callable(g[k]):
+            progress(k[5:].replace('_', ' '))
+            g[k]()
+
     progress("all tests passed!")
 except Exception, e:
     sys.stderr.write('*' * 50 + '\n'



More information about the Pkg-bazaar-commits mailing list