Skip to content

Commit

Permalink
Validation and option default inversion.
Browse files Browse the repository at this point in the history
  • Loading branch information
kwlzn committed Nov 4, 2017
1 parent 6115528 commit 53f1141
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 56 deletions.
1 change: 1 addition & 0 deletions src/python/pants/option/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def __init__(self, scope, option, **msg_format_args):
'on any of its inner scopes.')
ImplicitValIsNone = mk_registration_error('Implicit value cannot be None.')
InvalidKwarg = mk_registration_error('Invalid registration kwarg {kwarg}.')
InvalidKwargNonGlobalScope = mk_registration_error('Invalid registration kwarg {kwarg} on non-global scope.')
InvalidMemberType = mk_registration_error('member_type {member_type} not allowed.')
MemberTypeNotAllowed = mk_registration_error('member_type not allowed on option with type {type_}. '
'It may only be specified if type=list.')
Expand Down
85 changes: 40 additions & 45 deletions src/python/pants/option/global_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,28 +50,28 @@ def register_bootstrap_options(cls, register):
# setup a 'WARN' logging level name that maps to 'WARNING'.
logging.addLevelName(logging.WARNING, 'WARN')
register('-l', '--level', choices=['debug', 'info', 'warn'], default='info', recursive=True,
daemon=True, help='Set the logging level.')
register('-q', '--quiet', type=bool, recursive=True,
help='Set the logging level.')
register('-q', '--quiet', type=bool, recursive=True, daemon=False,
help='Squelches most console output. NOTE: Some tasks default to behaving quietly: '
'inverting this option supports making them noisier than they would be otherwise.')
# Not really needed in bootstrap options, but putting it here means it displays right
# after -l and -q in help output, which is conveniently contextual.
register('--colors', type=bool, default=sys.stdout.isatty(), recursive=True,
register('--colors', type=bool, default=sys.stdout.isatty(), recursive=True, daemon=False,
help='Set whether log messages are displayed in color.')

# Pants code uses this only to verify that we are of the requested version. However
# setup scripts, runner scripts, IDE plugins, etc., may grep this out of pants.ini
# and use it to select the right version.
# Note that to print the version of the pants instance you're running, use -v, -V or --version.
register('--pants-version', advanced=True, default=pants_version(), daemon=True,
register('--pants-version', advanced=True, default=pants_version(),
help='Use this pants version.')

register('--plugins', advanced=True, type=list, daemon=True, help='Load these plugins.')
register('--plugin-cache-dir', advanced=True, daemon=True,
register('--plugins', advanced=True, type=list, help='Load these plugins.')
register('--plugin-cache-dir', advanced=True,
default=os.path.join(get_pants_cachedir(), 'plugins'),
help='Cache resolved plugin requirements here.')

register('--backend-packages', advanced=True, type=list, daemon=True,
register('--backend-packages', advanced=True, type=list,
default=['pants.backend.graph_info',
'pants.backend.python',
'pants.backend.jvm',
Expand All @@ -88,136 +88,131 @@ def register_bootstrap_options(cls, register):
'Add contrib and custom backends to this list.')

register('--pants-bootstrapdir', advanced=True, metavar='<dir>', default=get_pants_cachedir(),
daemon=True, help='Use this dir for global cache.')
help='Use this dir for global cache.')
register('--pants-configdir', advanced=True, metavar='<dir>', default=get_pants_configdir(),
daemon=True, help='Use this dir for global config files.')
register('--pants-workdir', advanced=True, metavar='<dir>', daemon=True,
help='Use this dir for global config files.')
register('--pants-workdir', advanced=True, metavar='<dir>',
default=os.path.join(buildroot, '.pants.d'),
help='Write intermediate output files to this dir.')
register('--pants-supportdir', advanced=True, metavar='<dir>', daemon=True,
register('--pants-supportdir', advanced=True, metavar='<dir>',
default=os.path.join(buildroot, 'build-support'),
help='Use support files from this dir.')
register('--pants-distdir', advanced=True, metavar='<dir>', daemon=True,
register('--pants-distdir', advanced=True, metavar='<dir>',
default=default_distdir,
help='Write end-product artifacts to this dir. If you modify this path, you '
'should also update --build-ignore and --pants-ignore to include the '
'custom dist dir path as well.')
register('--pants-subprocessdir', advanced=True, default=os.path.join(buildroot, '.pids'),
daemon=True,
help='The directory to use for tracking subprocess metadata, if any. This should '
'live outside of the dir used by `--pants-workdir` to allow for tracking '
'subprocesses that outlive the workdir data (e.g. `./pants server`).')
register('--pants-config-files', advanced=True, type=list, daemon=True,
register('--pants-config-files', advanced=True, type=list,
default=[get_default_pants_config_file()], help='Paths to Pants config files.')
# TODO: Deprecate the --pantsrc/--pantsrc-files options? This would require being able
# to set extra config file locations in an initial bootstrap config file.
register('--config-override', advanced=True, type=list, metavar='<path>', daemon=True,
register('--config-override', advanced=True, type=list, metavar='<path>',
removal_version='1.6.0.dev0',
removal_hint='Use --pants-config-files=<second config file path> instead.',
help='A second config file, to override pants.ini.')
register('--pantsrc', advanced=True, type=bool, default=True, daemon=True,
register('--pantsrc', advanced=True, type=bool, default=True,
help='Use pantsrc files.')
register('--pantsrc-files', advanced=True, type=list, metavar='<path>', daemon=True,
register('--pantsrc-files', advanced=True, type=list, metavar='<path>',
default=['/etc/pantsrc', '~/.pants.rc'],
help='Override config with values from these files. '
'Later files override earlier ones.')
register('--pythonpath', advanced=True, type=list, daemon=True,
register('--pythonpath', advanced=True, type=list,
help='Add these directories to PYTHONPATH to search for plugins.')
register('--target-spec-file', type=list, dest='target_spec_files',
register('--target-spec-file', type=list, dest='target_spec_files', daemon=False,
help='Read additional specs from this file, one per line')
register('--verify-config', type=bool, default=True,
register('--verify-config', type=bool, default=True, daemon=False,
help='Verify that all config file values correspond to known options.')
register('--build-ignore', advanced=True, type=list, fromfile=True, daemon=True,
register('--build-ignore', advanced=True, type=list, fromfile=True,
default=['.*/', default_rel_distdir, 'bower_components/',
'node_modules/', '*.egg-info/'],
help='Paths to ignore when identifying BUILD files. '
'This does not affect any other filesystem operations. '
'Patterns use the gitignore pattern syntax (https://git-scm.com/docs/gitignore).')
register('--pants-ignore', advanced=True, type=list, fromfile=True, daemon=True,
register('--pants-ignore', advanced=True, type=list, fromfile=True,
default=['.*/', default_rel_distdir],
help='Paths to ignore for all filesystem operations performed by pants '
'(e.g. BUILD file scanning, glob matching, etc). '
'Patterns use the gitignore syntax (https://git-scm.com/docs/gitignore). '
'This currently only affects the v2 engine. '
'To experiment with v2 engine, try --enable-v2-engine option.')
register('--exclude-target-regexp', advanced=True, type=list, default=[],
register('--exclude-target-regexp', advanced=True, type=list, default=[], daemon=False,
metavar='<regexp>', help='Exclude target roots that match these regexes.')
register('--subproject-roots', type=list, advanced=True, fromfile=True, default=[],
daemon=True,
help='Paths that correspond with build roots for any subproject that this '
'project depends on.')

# These logging options are registered in the bootstrap phase so that plugins can log during
# registration and not so that their values can be interpolated in configs.
register('-d', '--logdir', advanced=True, metavar='<dir>', daemon=True,
register('-d', '--logdir', advanced=True, metavar='<dir>',
help='Write logs to files under this directory.')

# This facilitates bootstrap-time configuration of pantsd usage such that we can
# determine whether or not to use the Pailgun client to invoke a given pants run
# without resorting to heavier options parsing.
register('--enable-pantsd', advanced=True, type=bool, default=False, daemon=True,
register('--enable-pantsd', advanced=True, type=bool, default=False,
help='Enables use of the pants daemon (and implicitly, the v2 engine). (Beta)')

# This facilitates use of the v2 engine, sans daemon.
# TODO: Add removal_version='1.5.0.dev0' before 1.4 lands.
register('--enable-v2-engine', advanced=True, type=bool, default=True, daemon=True,
register('--enable-v2-engine', advanced=True, type=bool, default=True,
help='Enables use of the v2 engine.')

# These facilitate configuring the native engine.
register('--native-engine-version', advanced=True, default='DEPRECATED', daemon=True,
register('--native-engine-version', advanced=True, default='DEPRECATED',
removal_version='1.6.0.dev0',
removal_hint='Unused, the native engine is now embedded in the pantsbuild.pants wheel',
help='Native engine version.')
register('--native-engine-supportdir', advanced=True, default='DEPRECATED', daemon=True,
register('--native-engine-supportdir', advanced=True, default='DEPRECATED',
removal_version='1.6.0.dev0',
removal_hint='Unused, the native engine is now embedded in the pantsbuild.pants wheel',
help='Find native engine binaries under this dir. Used as part of the path to '
'lookup the binary with --binary-util-baseurls and --pants-bootstrapdir.')
register('--native-engine-visualize-to', advanced=True, default=None, type=dir_option,
register('--native-engine-visualize-to', advanced=True, default=None, type=dir_option, daemon=False,
help='A directory to write execution and rule graphs to as `dot` files. The contents '
'of the directory will be overwritten if any filenames collide.')

# BinaryUtil options.
register('--binaries-baseurls', type=list, advanced=True, daemon=True,
register('--binaries-baseurls', type=list, advanced=True,
default=['https://binaries.pantsbuild.org'],
help='List of URLs from which binary tools are downloaded. URLs are '
'searched in order until the requested path is found.')
register('--binaries-fetch-timeout-secs', type=int, default=30, advanced=True,
daemon=True,
register('--binaries-fetch-timeout-secs', type=int, default=30, advanced=True, daemon=False,
help='Timeout in seconds for URL reads when fetching binary tools from the '
'repos specified by --baseurls.')
register('--binaries-path-by-id', type=dict, advanced=True, daemon=True,
register('--binaries-path-by-id', type=dict, advanced=True,
help=('Maps output of uname for a machine to a binary search path. e.g. '
'{("darwin", "15"): ["mac", "10.11"]), ("linux", "arm32"): ["linux"'
', "arm32"]}'))

# Pants Daemon options.
register('--pantsd-pailgun-host', advanced=True, default='127.0.0.1', daemon=True,
register('--pantsd-pailgun-host', advanced=True, default='127.0.0.1',
help='The host to bind the pants nailgun server to.')
register('--pantsd-pailgun-port', advanced=True, type=int, default=0, daemon=True,
register('--pantsd-pailgun-port', advanced=True, type=int, default=0,
help='The port to bind the pants nailgun server to. Defaults to a random port.')
register('--pantsd-log-dir', advanced=True, default=None, daemon=True,
register('--pantsd-log-dir', advanced=True, default=None,
help='The directory to log pantsd output to.')
register('--pantsd-fs-event-detection', advanced=True, type=bool, daemon=True,
register('--pantsd-fs-event-detection', advanced=True, type=bool,
removal_version='1.5.0.dev0',
removal_hint='This option is now implied by `--enable-pantsd`.',
help='Whether or not to use filesystem event detection.')
register('--pantsd-fs-event-workers', advanced=True, type=int, default=4, daemon=True,
register('--pantsd-fs-event-workers', advanced=True, type=int, default=4,
help='The number of workers to use for the filesystem event service executor pool.')

# Watchman options.
register('--watchman-version', advanced=True, default='4.5.0', daemon=True,
help='Watchman version.')
register('--watchman-supportdir', advanced=True, default='bin/watchman', daemon=True,
register('--watchman-version', advanced=True, default='4.5.0', help='Watchman version.')
register('--watchman-supportdir', advanced=True, default='bin/watchman',
help='Find watchman binaries under this dir. Used as part of the path to lookup '
'the binary with --binary-util-baseurls and --pants-bootstrapdir.')
register('--watchman-startup-timeout', type=float, advanced=True, default=30.0,
daemon=True,
help='The watchman socket timeout (in seconds) for the initial `watch-project` command. '
'This may need to be set higher for larger repos due to watchman startup cost.')
register('--watchman-socket-timeout', type=float, advanced=True, default=5.0, daemon=True,
register('--watchman-socket-timeout', type=float, advanced=True, default=5.0,
help='The watchman client socket timeout in seconds.')
register('--watchman-socket-path', type=str, advanced=True, default=None, daemon=True,
register('--watchman-socket-path', type=str, advanced=True, default=None,
help='The path to the watchman UNIX socket. This can be overridden if the default '
'absolute path length exceeds the maximum allowed by the OS.')

Expand Down
6 changes: 4 additions & 2 deletions src/python/pants/option/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,8 @@ def for_scope(self, scope, inherit_from_enclosing_scope=True):

return values

def get_fingerprintable_for_scope(self, scope, include_passthru=False, fingerprint_key=None):
def get_fingerprintable_for_scope(self, scope, include_passthru=False, fingerprint_key=None,
invert=False):
"""Returns a list of fingerprintable (option type, option value) pairs for the given scope.
Fingerprintable options are options registered via a "fingerprint=True" kwarg. This flag
Expand All @@ -322,6 +323,7 @@ def get_fingerprintable_for_scope(self, scope, include_passthru=False, fingerpri
:param bool include_passthru: Whether to include passthru args captured by `scope` in the
fingerprintable options.
:param string fingerprint_key: The option kwarg to match against (defaults to 'fingerprint').
:param bool invert: Whether or not to invert the boolean check for the fingerprint_key value.
:API: public
"""
Expand All @@ -344,7 +346,7 @@ def get_fingerprintable_for_scope(self, scope, include_passthru=False, fingerpri
for (_, kwargs) in sorted(parser.option_registrations_iter()):
if kwargs.get('recursive') and not kwargs.get('recursive_root'):
continue # We only need to fprint recursive options once.
if kwargs.get(fingerprint_key) is not True:
if kwargs.get(fingerprint_key) is not (False if invert else True):
continue
# Note that we read the value from scope, even if the registration was on an enclosing
# scope, to get the right value for recursive options (and because this mirrors what
Expand Down
11 changes: 7 additions & 4 deletions src/python/pants/option/options_fingerprinter.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,23 @@ class OptionsFingerprinter(object):

@classmethod
def combined_options_fingerprint_for_scope(cls, scope, options, fingerprint_key=None,
build_graph=None):
invert=None, build_graph=None):
"""Given options and a scope, compute a combined fingerprint for the scope.
:param string scope: The scope to fingerprint.
:param Options options: The `Options` object to fingerprint.
:param string fingerprint_key: The options kwarg to filter against.
:param bool invert: Whether or not to invert the boolean check for the fingerprint_key value.
:param BuildGraph build_graph: A `BuildGraph` instance, only needed if fingerprinting
target options.
"""
fingerprinter = cls(build_graph)
hasher = sha1()
for (
option_type, option_value
) in options.get_fingerprintable_for_scope(scope, fingerprint_key=fingerprint_key):
for (option_type, option_value) in options.get_fingerprintable_for_scope(
scope,
fingerprint_key=fingerprint_key,
invert=invert
):
hasher.update(
# N.B. `OptionsFingerprinter.fingerprint()` can return `None`,
# so we always cast to bytes here.
Expand Down
12 changes: 8 additions & 4 deletions src/python/pants/option/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@
dict_option, dir_option, file_option, list_option,
target_option)
from pants.option.errors import (BooleanOptionNameWithNo, FrozenRegistration, ImplicitValIsNone,
InvalidKwarg, InvalidMemberType, MemberTypeNotAllowed,
NoOptionNames, OptionAlreadyRegistered, OptionNameDash,
OptionNameDoubleDash, ParseError, RecursiveSubsystemOption,
Shadowing)
InvalidKwarg, InvalidKwargNonGlobalScope, InvalidMemberType,
MemberTypeNotAllowed, NoOptionNames, OptionAlreadyRegistered,
OptionNameDash, OptionNameDoubleDash, ParseError,
RecursiveSubsystemOption, Shadowing)
from pants.option.option_util import is_dict_option, is_list_option
from pants.option.ranked_value import RankedValue
from pants.option.scope import ScopeInfo
Expand Down Expand Up @@ -382,6 +382,10 @@ def error(exception_type, arg_name=None, **msg_kwargs):
if kwarg not in self._allowed_registration_kwargs:
error(InvalidKwarg, kwarg=kwarg)

# Ensure `daemon=True` can't be passed on non-global scopes (except for `recursive=True`).
if (kwarg == 'daemon' and self._scope != GLOBAL_SCOPE and kwargs.get('recursive') is False):
error(InvalidKwargNonGlobalScope, kwarg=kwarg)

removal_version = kwargs.get('removal_version')
if removal_version is not None:
validate_removal_semver(removal_version)
Expand Down
3 changes: 2 additions & 1 deletion src/python/pants/pantsd/pants_daemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,8 @@ def options_fingerprint(self):
return OptionsFingerprinter.combined_options_fingerprint_for_scope(
GLOBAL_SCOPE,
self._bootstrap_options,
fingerprint_key='daemon'
fingerprint_key='daemon',
invert=True
)

def shutdown(self, service_thread_map):
Expand Down

0 comments on commit 53f1141

Please sign in to comment.