Main function.

        Parses command, load settings and dispatches accordingly.

def handle(self, argv=None):
        """
        Main function.

        Parses command, load settings and dispatches accordingly.

        """

        desc = ('Zappa - Deploy Python applications to AWS Lambda'
                ' and API Gateway.\n')
        parser = argparse.ArgumentParser(description=desc)
        parser.add_argument(
            '-v', '--version', action='version',
            version=pkg_resources.get_distribution("zappa").version,
            help='Print the zappa version'
        )
        parser.add_argument(
            '--color', default='auto', choices=['auto','never','always']
        )

        env_parser = argparse.ArgumentParser(add_help=False)
        me_group = env_parser.add_mutually_exclusive_group()
        all_help = ('Execute this command for all of our defined '
                    'Zappa stages.')
        me_group.add_argument('--all', action='store_true', help=all_help)
        me_group.add_argument('stage_env', nargs='?')

        group = env_parser.add_argument_group()
        group.add_argument(
            '-a', '--app_function', help='The WSGI application function.'
        )
        group.add_argument(
            '-s', '--settings_file', help='The path to a Zappa settings file.'
        )
        group.add_argument(
            '-q', '--quiet', action='store_true', help='Silence all output.'
        )
        # https://github.com/Miserlou/Zappa/issues/407
        # Moved when 'template' command added.
        # Fuck Terraform.
        group.add_argument(
            '-j', '--json', action='store_true', help='Make the output of this command be machine readable.'
        )
        # https://github.com/Miserlou/Zappa/issues/891
        group.add_argument(
            '--disable_progress', action='store_true', help='Disable progress bars.'
        )

        ##
        # Certify
        ##
        subparsers = parser.add_subparsers(title='subcommands', dest='command')
        cert_parser = subparsers.add_parser(
            'certify', parents=[env_parser],
            help='Create and install SSL certificate'
        )
        cert_parser.add_argument(
            '--manual', action='store_true',
            help=("Gets new Let's Encrypt certificates, but prints them to console."
                "Does not update API Gateway domains.")
        )
        cert_parser.add_argument(
            '-y', '--yes', action='store_true', help='Auto confirm yes.'
        )

        ##
        # Deploy
        ##
        deploy_parser = subparsers.add_parser(
            'deploy', parents=[env_parser], help='Deploy application.'
        )
        deploy_parser.add_argument(
            '-z', '--zip', help='Deploy Lambda with specific local or S3 hosted zip package'
        )

        ##
        # Init
        ##
        init_parser = subparsers.add_parser('init', help='Initialize Zappa app.')

        ##
        # Package
        ##
        package_parser = subparsers.add_parser(
            'package', parents=[env_parser], help='Build the application zip package locally.'
        )
        package_parser.add_argument(
            '-o', '--output', help='Name of file to output the package to.'
        )

        ##
        # Template
        ##
        template_parser = subparsers.add_parser(
            'template', parents=[env_parser], help='Create a CloudFormation template for this API Gateway.'
        )
        template_parser.add_argument(
            '-l', '--lambda-arn', required=True, help='ARN of the Lambda function to template to.'
        )
        template_parser.add_argument(
            '-r', '--role-arn', required=True, help='ARN of the Role to template with.'
        )
        template_parser.add_argument(
            '-o', '--output', help='Name of file to output the template to.'
        )

        ##
        # Invocation
        ##
        invoke_parser = subparsers.add_parser(
            'invoke', parents=[env_parser],
            help='Invoke remote function.'
        )
        invoke_parser.add_argument(
            '--raw', action='store_true',
            help=('When invoking remotely, invoke this python as a string,'
                  ' not as a modular path.')
        )
        invoke_parser.add_argument(
            '--no-color', action='store_true',
            help=("Don't color the output")
        )
        invoke_parser.add_argument('command_rest')

        ##
        # Manage
        ##
        manage_parser = subparsers.add_parser(
            'manage',
            help='Invoke remote Django manage.py commands.'
        )
        rest_help = ("Command in the form of <env> <command>. <env> is not "
                     "required if --all is specified")
        manage_parser.add_argument('--all', action='store_true', help=all_help)
        manage_parser.add_argument('command_rest', nargs='+', help=rest_help)
        manage_parser.add_argument(
            '--no-color', action='store_true',
            help=("Don't color the output")
        )
        # This is explicitly added here because this is the only subcommand that doesn't inherit from env_parser
        # https://github.com/Miserlou/Zappa/issues/1002
        manage_parser.add_argument(
            '-s', '--settings_file', help='The path to a Zappa settings file.'
        )

        ##
        # Rollback
        ##
        def positive_int(s):
            """ Ensure an arg is positive """
            i = int(s)
            if i < 0:
                msg = "This argument must be positive (got {})".format(s)
                raise argparse.ArgumentTypeError(msg)
            return i

        rollback_parser = subparsers.add_parser(
            'rollback', parents=[env_parser],
            help='Rollback deployed code to a previous version.'
        )
        rollback_parser.add_argument(
            '-n', '--num-rollback', type=positive_int, default=1,
            help='The number of versions to rollback.'
        )

        ##
        # Scheduling
        ##
        subparsers.add_parser(
            'schedule', parents=[env_parser],
            help='Schedule functions to occur at regular intervals.'
        )

        ##
        # Status
        ##
        status_parser = subparsers.add_parser(
            'status', parents=[env_parser],
            help='Show deployment status and event schedules.'
        )

        ##
        # Log Tailing
        ##
        tail_parser = subparsers.add_parser(
            'tail', parents=[env_parser], help='Tail deployment logs.'
        )
        tail_parser.add_argument(
            '--no-color', action='store_true',
            help="Don't color log tail output."
        )
        tail_parser.add_argument(
            '--http', action='store_true',
            help='Only show HTTP requests in tail output.'
        )
        tail_parser.add_argument(
            '--non-http', action='store_true',
            help='Only show non-HTTP requests in tail output.'
        )
        tail_parser.add_argument(
            '--since', type=str, default="100000s",
            help="Only show lines since a certain timeframe."
        )
        tail_parser.add_argument(
            '--filter', type=str, default="",
            help="Apply a filter pattern to the logs."
        )
        tail_parser.add_argument(
            '--force-color', action='store_true',
            help='Force coloring log tail output even if coloring support is not auto-detected. (example: piping)'
        )
        tail_parser.add_argument(
            '--disable-keep-open', action='store_true',
            help="Exit after printing the last available log, rather than keeping the log open."
        )

        ##
        # Undeploy
        ##
        undeploy_parser = subparsers.add_parser(
            'undeploy', parents=[env_parser], help='Undeploy application.'
        )
        undeploy_parser.add_argument(
            '--remove-logs', action='store_true',
            help=('Removes log groups of api gateway and lambda task'
                  ' during the undeployment.'),
        )
        undeploy_parser.add_argument(
            '-y', '--yes', action='store_true', help='Auto confirm yes.'
        )

        ##
        # Unschedule
        ##
        subparsers.add_parser('unschedule', parents=[env_parser],
                              help='Unschedule functions.')

        ##
        # Updating
        ##
        update_parser = subparsers.add_parser(
            'update', parents=[env_parser], help='Update deployed application.'
        )
        update_parser.add_argument(
            '-z', '--zip', help='Update Lambda with specific local or S3 hosted zip package'
        )
        update_parser.add_argument(
            '-n', '--no-upload', help="Update configuration where appropriate, but don't upload new code"
        )

        ##
        # Debug
        ##
        subparsers.add_parser(
            'shell', parents=[env_parser], help='A debug shell with a loaded Zappa object.'
        )

        argcomplete.autocomplete(parser)
        args = parser.parse_args(argv)
        self.vargs = vars(args)

        if args.color == 'never':
            disable_click_colors()
        elif args.color == 'always':
            #TODO: Support aggressive coloring like "--force-color" on all commands
            pass
        elif args.color == 'auto':
            pass

        # Parse the input
        # NOTE(rmoe): Special case for manage command
        # The manage command can't have both stage_env and command_rest
        # arguments. Since they are both positional arguments argparse can't
        # differentiate the two. This causes problems when used with --all.
        # (e.g. "manage --all showmigrations admin" argparse thinks --all has
        # been specified AND that stage_env='showmigrations')
        # By having command_rest collect everything but --all we can split it
        # apart here instead of relying on argparse.
        if not args.command:
            parser.print_help()
            return

        if args.command == 'manage' and not self.vargs.get('all'):
            self.stage_env = self.vargs['command_rest'].pop(0)
        else:
            self.stage_env = self.vargs.get('stage_env')

        if args.command == 'package':
            self.load_credentials = False

        self.command = args.command

        self.disable_progress = self.vargs.get('disable_progress')
        if self.vargs.get('quiet'):
            self.silence()

        # We don't have any settings yet, so make those first!
        # (Settings-based interactions will fail
        # before a project has been initialized.)
        if self.command == 'init':
            self.init()
            return

        # Make sure there isn't a new version available
        if not self.vargs.get('json'):
            self.check_for_update()

        # Load and Validate Settings File
        self.load_settings_file(self.vargs.get('settings_file'))

        # Should we execute this for all stages, or just one?
        all_stages = self.vargs.get('all')
        stages = []

        if all_stages: # All stages!
            stages = self.zappa_settings.keys()
        else: # Just one env.
            if not self.stage_env:
                # If there's only one stage defined in the settings,
                # use that as the default.
                if len(self.zappa_settings.keys()) == 1:
                    stages.append(list(self.zappa_settings.keys())[0])
                else:
                    parser.error("Please supply a stage to interact with.")
            else:
                stages.append(self.stage_env)

        for stage in stages:
            try:
                self.dispatch_command(self.command, stage)
            except ClickException as e:
                # Discussion on exit codes: https://github.com/Miserlou/Zappa/issues/407
                e.show()
                sys.exit(e.exit_code)