DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (6863f516ba38)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
# 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/.

from __future__ import absolute_import, print_function, unicode_literals

import os
import subprocess
import tempfile
from argparse import ArgumentParser

from .templates import all_templates


COMMON_ARGUMENT_GROUPS = {
    'push': [
        [['-m', '--message'],
         {'const': 'editor',
          'default': '{msg}',
          'nargs': '?',
          'help': 'Use the specified commit message, or create it in your '
                  '$EDITOR if blank. Defaults to computed message.',
          }],
        [['--no-push'],
         {'dest': 'push',
          'action': 'store_false',
          'help': 'Do not push to try as a result of running this command (if '
                  'specified this command will only print calculated try '
                  'syntax and selection info).',
          }],
        [['--closed-tree'],
         {'action': 'store_true',
          'default': False,
          'help': 'Push despite a closed try tree',
          }],
    ],
    'preset': [
        [['--save'],
         {'default': None,
          'help': 'Save selection for future use with --preset.',
          }],
        [['--preset'],
         {'default': None,
          'help': 'Load a saved selection.',
          }],
        [['--list-presets'],
         {'action': 'store_const',
          'dest': 'preset_action',
          'const': 'list',
          'default': None,
          'help': 'List available preset selections.',
          }],
        [['--edit-presets'],
         {'action': 'store_const',
          'dest': 'preset_action',
          'const': 'edit',
          'default': None,
          'help': 'Edit the preset file.',
          }],
    ],
    'task': [
        [['--full'],
         {'action': 'store_true',
          'default': False,
          'help': "Use the full set of tasks as input to fzf (instead of "
                  "target tasks).",
          }],
        [['-p', '--parameters'],
         {'default': None,
          'help': "Use the given parameters.yml to generate tasks, "
                  "defaults to a default set of parameters",
          }],
    ],
}


class BaseTryParser(ArgumentParser):
    name = 'try'
    common_groups = ['push', 'preset']
    arguments = []
    templates = []

    def __init__(self, *args, **kwargs):
        ArgumentParser.__init__(self, *args, **kwargs)

        group = self.add_argument_group("{} arguments".format(self.name))
        for cli, kwargs in self.arguments:
            group.add_argument(*cli, **kwargs)

        for name in self.common_groups:
            group = self.add_argument_group("{} arguments".format(name))
            arguments = COMMON_ARGUMENT_GROUPS[name]

            # Preset arguments are all mutually exclusive.
            if name == 'preset':
                group = group.add_mutually_exclusive_group()

            for cli, kwargs in arguments:
                group.add_argument(*cli, **kwargs)

        group = self.add_argument_group("template arguments")
        self.templates = {t: all_templates[t]() for t in self.templates}
        for template in self.templates.values():
            template.add_arguments(group)

    def validate(self, args):
        if hasattr(args, 'message'):
            if args.message == 'editor':
                if 'EDITOR' not in os.environ:
                    self.error("must set the $EDITOR environment variable to use blank --message")

                with tempfile.NamedTemporaryFile(mode='r') as fh:
                    subprocess.call([os.environ['EDITOR'], fh.name])
                    args.message = fh.read().strip()

            if '{msg}' not in args.message:
                args.message = '{}\n\n{}'.format(args.message, '{msg}')

    def parse_known_args(self, *args, **kwargs):
        args, remainder = ArgumentParser.parse_known_args(self, *args, **kwargs)
        self.validate(args)
        return args, remainder