omnibus
omnibus copied to clipboard
Additional command line support: argparse with cmd2
By leveraging cmd2's support for argparse we can get rid of a lot of commands and add argument support to many existing ones. For example, we'll now have support for commands like: tags --view inquest.net
, tags --add inquest.net these are my tags, https://inquest.net
, artifact --new inquest.net
, artifact --view inquest.net
, etc etc.
The parsers will go in their own library that we import into omnibus-cli so it doesn't look like garbage inside that script. lets add them to lib/parsers.py
Example of the tags parser:
# do_tags parsere
tags_parser = argparse.ArgumentParser()
id_tags = tags_parser.add_mutually_exclusive_group()
manage_tags = tags_parser.add_mutually_exclusive_group()
manage_tags.add_argument('-a', '--add', action='store_true', help='add tag')
manage_tags.add_argument('-v', '--view', action='store_true', help='view tags')
id_tags.add_argument('-l', '--last', action='store_true', help='use last created artifact')
id_tags.add_argument('-n', '--name', action='store', help='artifact name')
id_tags.add_argument('-i', '--id', action='store', help='artifact session ID')
tags_parser.add_argument('tags', nargs='?', help='comma separated tags')
and we'd port tags to look something like this:
@cmd2.with_argparser(tags_parser)
def do_tags(self, args):
"""Manage artifact tags"""
artifact = self.parse_identifier(args)
if artifact is None:
return
_type = detect_type(artifact)
if args.view:
result = self.db.get_value(_type, {'name': artifact}, 'tags')
info('%s tags: %s' % (artifact, result))
return
elif args.add:
if args.tags == '':
error('Tags not specified')
else:
tags = args.tags
new_tags = []
if ',' in tags:
for t in tags.split(','):
t = t.strip()
new_tags.append(t)
else:
new_tags = tags
if self.db.exists(_type, {'name': artifact}):
self.db.update_one(_type, {'name': artifact}, {'tags': new_tags})
success('Added tags to artifact (%s: %s)' % (artifact, new_tags))
else:
warning('Failed to find artifact in MongoDB. Run "new <artifact name>" before using the tags command')
else:
info('Run "tags --help" or "help tags" for all available commands')
Since many of the commands will accept artifacts as an argument, we'll also add a generic parser that will handle these more standard args of -l, --last
for last created artifact, -n, --name
for artifact by name, and -i, --id
for artifact by session ID like seen in the last comment for tags.
Generic parser example
def parse_identifier(self, args):
"""Parse artifact name out of argparse arguments"""
identifier = None
if args.last:
if args.name or args.id:
error('Only one argument can be specified: --last, --name, --id')
return None
identifier = self.session.receive('artifacts')
elif args.id:
is_key, value = lookup_key(self.session, args.id)
if is_key and value is None:
error('Unable to find artifact key in session (%s)' % args.id)
return None
elif is_key and value is not None:
identifier = value
elif args.name:
identifier = args.name.strip()
else:
error('Must specify one of: --last, --name, --id')
return None
return identifier