#!/usr/bin/env python # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this file, # You can obtain one at http://mozilla.org/MPL/2.0/. """ Mozilla universal manifest parser """ import os import sys from optparse import OptionParser from .logger import Logger from .manifestparser import ManifestParser, convert class ParserError(Exception): """error for exceptions while parsing the command line""" def parse_args(_args): """ parse and return: --keys=value (or --key value) -tags args """ # return values _dict = {} tags = [] args = [] # parse the arguments key = None for arg in _args: if arg.startswith("---"): raise ParserError("arguments should start with '-' or '--' only") elif arg.startswith("--"): if key: raise ParserError("Key %s still open" % key) key = arg[2:] if "=" in key: key, value = key.split("=", 1) _dict[key] = value key = None continue elif arg.startswith("-"): if key: raise ParserError("Key %s still open" % key) tags.append(arg[1:]) continue else: if key: _dict[key] = arg continue args.append(arg) # return values return (_dict, tags, args) class CLICommand(object): usage = "%prog [options] command" def __init__(self, parser): self._parser = parser # master parser self.logger = Logger() def parser(self): return OptionParser( usage=self.usage, description=self.__doc__, add_help_option=False ) class CopyCLI(CLICommand): """ To copy tests and manifests from a source """ usage = "%prog [options] copy manifest directory -tag1 -tag2 --key1=value1 --key2=value2 ..." def __call__(self, global_options, args): # parse the arguments try: kwargs, tags, args = parse_args(args) except ParserError as e: self._parser.error(str(e)) # make sure we have some manifests, otherwise it will # be quite boring if not len(args) == 2: self.logger.error("missing arguments: manifest directory") HelpCLI(self._parser)(global_options, ["copy"]) return 1 # read the manifests # TODO: should probably ensure these exist here manifests = ManifestParser() manifests.read(args[0]) # print the resultant query manifests.copy(args[1], None, *tags, **kwargs) return 0 class CreateCLI(CLICommand): """ create a manifest from a list of directories """ usage = "%prog [options] create directory <...>" def parser(self): parser = CLICommand.parser(self) parser.add_option( "-p", "--pattern", dest="pattern", help="glob pattern for files" ) parser.add_option( "-i", "--ignore", dest="ignore", default=[], action="append", help="directories to ignore", ) parser.add_option( "-w", "--in-place", dest="in_place", help="Write .ini files in place; filename to write to", ) return parser def __call__(self, global_options, args): parser = self.parser() options, args = parser.parse_args(args) # need some directories if not len(args): self.logger.error("missing arguments: directory ...") parser.print_usage() return 1 # add the directories to the manifest for arg in args: assert os.path.exists(arg) assert os.path.isdir(arg) manifest = convert( args, pattern=options.pattern, ignore=options.ignore, write=options.in_place, ) if manifest: print(manifest) return 0 class HelpCLI(CLICommand): """ get help on a command """ usage = "%prog [options] help [command]" def __call__(self, global_options, args): if len(args) == 1 and args[0] in commands: commands[args[0]](self._parser).parser().print_help() else: self._parser.print_help() print("\nCommands:") for command in sorted(commands): print(" %s : %s" % (command, commands[command].__doc__.strip())) class UpdateCLI(CLICommand): """ update the tests as listed in a manifest from a directory """ usage = "%prog [options] update manifest directory -tag1 -tag2 --key1=value1 --key2=value2 ..." def __call__(self, options, args): # parse the arguments try: kwargs, tags, args = parse_args(args) except ParserError as e: self._parser.error(str(e)) # make sure we have some manifests, otherwise it will # be quite boring if not len(args) == 2: self.logger.error("missing arguments: manifest directory") HelpCLI(self._parser)(options, ["update"]) return 1 # read the manifests # TODO: should probably ensure these exist here manifests = ManifestParser() manifests.read(args[0]) # print the resultant query manifests.update(args[1], None, *tags, **kwargs) return 0 class WriteCLI(CLICommand): """ write a manifest based on a query """ usage = "%prog [options] write manifest -tag1 -tag2 --key1=value1 --key2=value2 ..." def __call__(self, options, args): # parse the arguments try: kwargs, tags, args = parse_args(args) except ParserError as e: self._parser.error(str(e)) # make sure we have some manifests, otherwise it will # be quite boring if not args: self.logger.error("missing arguments: manifest ...") HelpCLI(self._parser)(options, ["write"]) return 1 # read the manifests # TODO: should probably ensure these exist here manifests = ManifestParser() manifests.read(*args) # print the resultant query manifests.write(global_tags=tags, global_kwargs=kwargs) return 0 # command -> class mapping commands = { "copy": CopyCLI, "create": CreateCLI, "help": HelpCLI, "update": UpdateCLI, "write": WriteCLI, } def main(args=sys.argv[1:]): """console_script entry point""" # set up an option parser usage = "%prog [options] [command] ..." description = "%s. Use `help` to display commands" % __doc__.strip() parser = OptionParser(usage=usage, description=description) parser.add_option( "-s", "--strict", dest="strict", action="store_true", default=False, help="adhere strictly to errors", ) parser.disable_interspersed_args() global_options, args = parser.parse_args(args) if not args: HelpCLI(parser)(global_options, args) parser.exit() # get the command command = args[0] if command not in commands: parser.error( "Command must be one of %s (you gave '%s')" % (", ".join(sorted(commands.keys())), command) ) return 1 handler = commands[command](parser) return handler(global_options, args[1:]) if __name__ == "__main__": sys.exit(main())