[Pkg-bazaar-commits] ./bzr/unstable r422: - External-command patch from mpe

Martin Pool mbp at sourcefrog.net
Fri Apr 10 07:52:14 UTC 2009


------------------------------------------------------------
revno: 422
committer: Martin Pool <mbp at sourcefrog.net>
timestamp: Tue 2005-05-10 13:50:45 +1000
message:
  - External-command patch from mpe
modified:
  NEWS
  bzrlib/commands.py
-------------- next part --------------
=== modified file 'NEWS'
--- a/NEWS	2005-05-10 00:47:18 +0000
+++ b/NEWS	2005-05-10 03:50:45 +0000
@@ -30,6 +30,9 @@
     * ``bzr log`` and ``bzr root`` can be given an http URL instead of
       a filename.
 
+    * Commands can now be defined by external programs or scripts
+      in a directory on $BZRPATH.
+
 
   TESTING:
 

=== modified file 'bzrlib/commands.py'
--- a/bzrlib/commands.py	2005-05-10 03:28:52 +0000
+++ b/bzrlib/commands.py	2005-05-10 03:50:45 +0000
@@ -58,8 +58,12 @@
     for cmdname, cmdclass in get_all_cmds():
         if cmd in cmdclass.aliases:
             return cmdname, cmdclass
-    else:
-        raise BzrCommandError("unknown command %r" % cmd)
+
+    cmdclass = ExternalCommand.find_command(cmd)
+    if cmdclass:
+        return cmd, cmdclass
+
+    raise BzrCommandError("unknown command %r" % cmd)
 
 
 class Command:
@@ -111,6 +115,73 @@
         return 0
 
 
+class ExternalCommand(Command):
+    """Class to wrap external commands.
+
+    We cheat a little here, when get_cmd_class() calls us we actually give it back
+    an object we construct that has the appropriate path, help, options etc for the
+    specified command.
+
+    When run_bzr() tries to instantiate that 'class' it gets caught by the __call__
+    method, which we override to call the Command.__init__ method. That then calls
+    our run method which is pretty straight forward.
+
+    The only wrinkle is that we have to map bzr's dictionary of options and arguments
+    back into command line options and arguments for the script.
+    """
+
+    def find_command(cls, cmd):
+        bzrpath = os.environ.get('BZRPATH', '')
+
+        for dir in bzrpath.split(':'):
+            path = os.path.join(dir, cmd)
+            if os.path.isfile(path):
+                return ExternalCommand(path)
+
+        return None
+
+    find_command = classmethod(find_command)
+
+    def __init__(self, path):
+        self.path = path
+
+        pipe = os.popen('%s --bzr-usage' % path, 'r')
+        self.takes_options = pipe.readline().split()
+        self.takes_args = pipe.readline().split()
+        pipe.close()
+
+        pipe = os.popen('%s --bzr-help' % path, 'r')
+        self.__doc__ = pipe.read()
+        pipe.close()
+
+    def __call__(self, options, arguments):
+        Command.__init__(self, options, arguments)
+        return self
+
+    def run(self, **kargs):
+        opts = []
+        args = []
+
+        keys = kargs.keys()
+        keys.sort()
+        for name in keys:
+            value = kargs[name]
+            if OPTIONS.has_key(name):
+                # it's an option
+                opts.append('--%s' % name)
+                if value is not None and value is not True:
+                    opts.append(str(value))
+            else:
+                # it's an arg, or arg list
+                if type(value) is not list:
+                    value = [value]
+                for v in value:
+                    if v is not None:
+                        args.append(str(v))
+
+        self.status = os.spawnv(os.P_WAIT, self.path, [self.path] + opts + args)
+        return self.status
+
 
 class cmd_status(Command):
     """Display status summary.



More information about the Pkg-bazaar-commits mailing list