[Patch] Updated support for external command handlers
Michael Ellerman
michael+bazaar at ellerman.id.au
Tue May 10 00:11:35 BST 2005
Before anyone picks me up on it .. I didn't add support for external commands
in 'bzr help commands', because that would require blindly running everything
in the $BZRPATH, which could be dangerous, eg.
$ export BZRPATH=~/bin
$ cat ~/bin/delete-home-directory
#!/bin/bash
rm -rf ~
$ bzr help commands
...
calls ~/bin/delete-home-directory --bzr-description
ouch!
If anyone can think of a nice way around this let me know.
cheers
On Tue, 10 May 2005 01:37, Michael Ellerman wrote:
> Hi Martin,
>
> Here's an updated patch for external command handlers.
>
> Rusty will write you some test cases in the morning =D
>
> External scripts need to handle two special options, here's an example.
>
> 8<---------------------
> #!/bin/bash
>
> if [[ $1 == '--bzr-usage' ]]; then
> # Options we accept, these are the bzr names as found in OPTIONS in
> commands.py echo "verbose message"
> # And arguments we accept, same format as for other commands, space
> seperated echo "file*"
> exit 0
> elif [[ $1 == '--bzr-help' ]]; then
> echo "This is an external bzr script."
> echo ""
> echo "More help about this command"
> exit 0
> fi
>
> # do stuff
> exit 0
> 8<---------------------
>
> The script will get called with the appropriate arguments, bzr does all the
> parsing and so on. The script is always called with long options. Options
> and arguments will always be passed in alphabetical order of the
> option/argument name.
>
> And the patch ..
>
> cheers
>
> *** modified file 'bzrlib/commands.py'
> --- bzrlib/commands.py
> +++ bzrlib/commands.py
> @@ -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:
> @@ -110,6 +114,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):
--
Michael Ellerman
IBM OzLabs
email: michael:ellerman.id.au
inmsg: mpe:jabber.org
wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)
We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person
More information about the bazaar
mailing list