| # repoman: Argument parser |
| # Copyright 2007-2017 Gentoo Foundation |
| # Distributed under the terms of the GNU General Public License v2 |
| |
| """This module contains functions used in Repoman to parse CLI arguments.""" |
| |
| import argparse |
| import logging |
| import sys |
| |
| # import our initialized portage instance |
| from repoman._portage import portage |
| |
| from portage import _unicode_decode |
| from portage import util |
| |
| |
| def parse_args(argv, qahelp, repoman_default_opts): |
| """Use a customized optionParser to parse command line arguments for repoman |
| Args: |
| argv - a sequence of command line arguments |
| qahelp - a dict of qa warning to help message |
| Returns: |
| (opts, args), just like a call to parser.parse_args() |
| """ |
| |
| argv = portage._decode_argv(argv) |
| |
| modes = { |
| 'commit': 'Run a scan then commit changes', |
| 'ci': 'Run a scan then commit changes', |
| 'fix': 'Fix simple QA issues (stray digests, missing digests)', |
| 'full': 'Scan directory tree and print all issues (not a summary)', |
| 'help': 'Show this screen', |
| 'manifest': 'Generate a Manifest (fetches files if necessary)', |
| 'manifest-check': 'Check Manifests for missing or incorrect digests', |
| 'scan': 'Scan directory tree for QA issues' |
| } |
| |
| output_choices = { |
| 'default': 'The normal output format', |
| 'column': 'Columnar output suitable for use with grep' |
| } |
| |
| mode_keys = list(modes) |
| mode_keys.sort() |
| |
| output_keys = sorted(output_choices) |
| |
| parser = argparse.ArgumentParser( |
| usage="repoman [options] [mode]", |
| description="Modes: %s" % " | ".join(mode_keys), |
| epilog="For more help consult the man page.") |
| |
| parser.add_argument( |
| '-a', '--ask', dest='ask', action='store_true', |
| default=False, |
| help='Request a confirmation before commiting') |
| |
| parser.add_argument( |
| '-b', '--bug', dest='bug', action='append', metavar='<BUG-NO|BUG-URL>', |
| default=[], |
| help=( |
| 'Mention a Gentoo or upstream bug in the commit footer; ' |
| 'takes either Gentoo bug number or full bug URL')) |
| |
| parser.add_argument( |
| '-c', '--closes', dest='closes', action='append', metavar='<PR-NO|PR-URL>', |
| default=[], |
| help=( |
| 'Adds a Closes footer to close GitHub pull request (or compatible); ' |
| 'takes either GitHub PR number or full PR URL')) |
| |
| parser.add_argument( |
| '-m', '--commitmsg', dest='commitmsg', |
| help='specify a commit message on the command line') |
| |
| parser.add_argument( |
| '-M', '--commitmsgfile', dest='commitmsgfile', |
| help='specify a path to a file that contains a commit message') |
| |
| parser.add_argument( |
| '--digest', choices=('y', 'n'), metavar='<y|n>', |
| help='Automatically update Manifest digests for modified files') |
| |
| parser.add_argument( |
| '-p', '--pretend', dest='pretend', default=False, |
| action='store_true', |
| help='don\'t commit or fix anything; just show what would be done') |
| |
| parser.add_argument( |
| '-q', '--quiet', dest="quiet", action="count", |
| default=0, |
| help='do not print unnecessary messages') |
| |
| parser.add_argument( |
| '--echangelog', choices=('y', 'n', 'force'), metavar="<y|n|force>", |
| help=( |
| 'for commit mode, call echangelog if ChangeLog is unmodified (or ' |
| 'regardless of modification if \'force\' is specified)')) |
| |
| parser.add_argument( |
| '--experimental-inherit', choices=('y', 'n'), metavar="<y|n>", |
| default='n', |
| help=( |
| 'Enable experimental inherit.missing checks which may misbehave' |
| ' when the internal eclass database becomes outdated')) |
| |
| parser.add_argument( |
| '-f', '--force', dest='force', action='store_true', |
| default=False, |
| help='Commit with QA violations') |
| |
| parser.add_argument( |
| '-S', '--straight-to-stable', dest='straight_to_stable', |
| default=False, action='store_true', |
| help='Allow committing straight to stable') |
| |
| parser.add_argument( |
| '--vcs', dest='vcs', |
| help='Force using specific VCS instead of autodetection') |
| |
| parser.add_argument( |
| '-v', '--verbose', dest="verbosity", action='count', |
| help='be very verbose in output', default=0) |
| |
| parser.add_argument( |
| '-V', '--version', dest='version', action='store_true', |
| help='show version info') |
| |
| parser.add_argument( |
| '-x', '--xmlparse', dest='xml_parse', action='store_true', |
| default=False, |
| help='forces the metadata.xml parse check to be carried out') |
| |
| parser.add_argument( |
| '--if-modified', choices=('y', 'n'), default='n', |
| metavar="<y|n>", |
| help='only check packages that have uncommitted modifications') |
| |
| parser.add_argument( |
| '-i', '--ignore-arches', dest='ignore_arches', action='store_true', |
| default=False, |
| help='ignore arch-specific failures (where arch != host)') |
| |
| parser.add_argument( |
| "--ignore-default-opts", |
| action="store_true", |
| help="do not use the REPOMAN_DEFAULT_OPTS environment variable") |
| |
| parser.add_argument( |
| '-I', '--ignore-masked', dest='ignore_masked', action='store_true', |
| default=False, |
| help='ignore masked packages (not allowed with commit mode)') |
| |
| parser.add_argument( |
| '--include-arches', |
| dest='include_arches', metavar='ARCHES', action='append', |
| help=( |
| 'A space separated list of arches used to ' |
| 'filter the selection of profiles for dependency checks')) |
| |
| parser.add_argument( |
| '-d', '--include-dev', dest='include_dev', action='store_true', |
| default=False, |
| help='include dev profiles in dependency checks') |
| |
| parser.add_argument( |
| '-e', '--include-exp-profiles', choices=('y', 'n'), metavar='<y|n>', |
| default=False, |
| help='include exp profiles in dependency checks') |
| |
| parser.add_argument( |
| '--unmatched-removal', dest='unmatched_removal', action='store_true', |
| default=False, |
| help=( |
| 'enable strict checking of package.mask and package.unmask files' |
| ' for unmatched removal atoms')) |
| |
| parser.add_argument( |
| '--without-mask', dest='without_mask', action='store_true', |
| default=False, |
| help=( |
| 'behave as if no package.mask entries exist' |
| ' (not allowed with commit mode)')) |
| |
| parser.add_argument( |
| '--output-style', dest='output_style', choices=output_keys, |
| help='select output type', default='default') |
| |
| parser.add_argument( |
| '--mode', dest='mode', choices=mode_keys, |
| help='specify which mode repoman will run in (default=full)') |
| |
| opts, args = parser.parse_known_args(argv[1:]) |
| |
| if not opts.ignore_default_opts: |
| default_opts = util.shlex_split(repoman_default_opts) |
| if default_opts: |
| opts, args = parser.parse_known_args(default_opts + sys.argv[1:]) |
| |
| if opts.mode == 'help': |
| parser.print_help(short=False) |
| |
| for arg in args: |
| if arg in modes: |
| if not opts.mode: |
| opts.mode = arg |
| break |
| else: |
| parser.error("invalid mode: %s" % arg) |
| |
| if not opts.mode: |
| opts.mode = 'full' |
| |
| if opts.mode == 'ci': |
| opts.mode = 'commit' # backwards compat shortcut |
| |
| # Use verbosity and quiet options to appropriately fiddle with the loglevel |
| for val in range(opts.verbosity): |
| logger = logging.getLogger() |
| logger.setLevel(logger.getEffectiveLevel() - 10) |
| |
| for val in range(opts.quiet): |
| logger = logging.getLogger() |
| logger.setLevel(logger.getEffectiveLevel() + 10) |
| |
| if opts.mode == 'commit' and opts.commitmsg: |
| opts.commitmsg = _unicode_decode(opts.commitmsg) |
| |
| if opts.mode == 'commit' and not (opts.force or opts.pretend): |
| if opts.ignore_masked: |
| opts.ignore_masked = False |
| logging.warn('Commit mode automatically disables --ignore-masked') |
| if opts.without_mask: |
| opts.without_mask = False |
| logging.warn('Commit mode automatically disables --without-mask') |
| |
| return (opts, args) |