/
global_options.py
297 lines (258 loc) · 16.9 KB
/
global_options.py
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
# coding=utf-8
# Copyright 2014 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).
from __future__ import (absolute_import, division, generators, nested_scopes, print_function,
unicode_literals, with_statement)
import logging
import os
import sys
from pants.base.build_environment import (get_buildroot, get_default_pants_config_file,
get_pants_cachedir, get_pants_configdir, pants_version)
from pants.option.arg_splitter import GLOBAL_SCOPE
from pants.option.custom_types import dir_option
from pants.option.optionable import Optionable
from pants.option.scope import ScopeInfo
from pants.subsystem.subsystem_client_mixin import SubsystemClientMixin
from pants.util.memo import memoized_method
from pants.util.objects import datatype
class GlobMatchErrorBehavior(datatype(['failure_behavior'])):
"""Describe the action to perform when matching globs in BUILD files to source files.
NB: this object is interpreted from within Snapshot::lift_path_globs() -- that method will need to
be aware of any changes to this object's definition.
"""
IGNORE = 'ignore'
WARN = 'warn'
ERROR = 'error'
allowed_values = [IGNORE, WARN, ERROR]
default_value = IGNORE
default_option_value = WARN
# FIXME(cosmicexplorer): add helpers in pants.util.memo for class properties and memoized class
# properties!
@classmethod
@memoized_method
def _singletons(cls):
return { behavior: cls(behavior) for behavior in cls.allowed_values }
@classmethod
def create(cls, value=None):
if isinstance(value, cls):
return value
if not value:
value = cls.default_value
return cls._singletons()[value]
def __new__(cls, *args, **kwargs):
this_object = super(GlobMatchErrorBehavior, cls).__new__(cls, *args, **kwargs)
if this_object.failure_behavior not in cls.allowed_values:
raise cls.make_type_error("Value {!r} for failure_behavior must be one of: {!r}."
.format(this_object.failure_behavior, cls.allowed_values))
return this_object
class GlobalOptionsRegistrar(SubsystemClientMixin, Optionable):
options_scope = GLOBAL_SCOPE
options_scope_category = ScopeInfo.GLOBAL
@classmethod
def register_bootstrap_options(cls, register):
"""Register bootstrap options.
"Bootstrap options" are a small set of options whose values are useful when registering other
options. Therefore we must bootstrap them early, before other options are registered, let
alone parsed.
Bootstrap option values can be interpolated into the config file, and can be referenced
programatically in registration code, e.g., as register.bootstrap.pants_workdir.
Note that regular code can also access these options as normal global-scope options. Their
status as "bootstrap options" is only pertinent during option registration.
"""
buildroot = get_buildroot()
default_distdir_name = 'dist'
default_distdir = os.path.join(buildroot, default_distdir_name)
default_rel_distdir = '/{}/'.format(default_distdir_name)
# Although logging supports the WARN level, its not documented and could conceivably be yanked.
# Since pants has supported 'warn' since inception, leave the 'warn' choice as-is but explicitly
# 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,
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, 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(),
help='Use this pants version.')
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,
default=['pants.backend.graph_info',
'pants.backend.python',
'pants.backend.jvm',
'pants.backend.native',
'pants.backend.codegen.antlr.java',
'pants.backend.codegen.antlr.python',
'pants.backend.codegen.jaxb',
'pants.backend.codegen.protobuf.java',
'pants.backend.codegen.ragel.java',
'pants.backend.codegen.thrift.java',
'pants.backend.codegen.thrift.python',
'pants.backend.codegen.wire.java',
'pants.backend.project_info'],
help='Load backends from these packages that are already on the path. '
'Add contrib and custom backends to this list.')
register('--pants-bootstrapdir', advanced=True, metavar='<dir>', default=get_pants_cachedir(),
help='Use this dir for global cache.')
register('--pants-configdir', advanced=True, metavar='<dir>', default=get_pants_configdir(),
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>',
default=os.path.join(buildroot, 'build-support'),
help='Use support files from this dir.')
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'),
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=False,
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('--pantsrc', advanced=True, type=bool, default=True,
help='Use pantsrc files.')
register('--pantsrc-files', advanced=True, type=list, metavar='<path>', daemon=False,
default=['/etc/pantsrc', '~/.pants.rc'],
help='Override config with values from these files. '
'Later files override earlier ones.')
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', daemon=False,
help='Read additional specs from this file, one per line')
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,
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,
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).')
register('--glob-expansion-failure', type=str,
choices=GlobMatchErrorBehavior.allowed_values,
default=GlobMatchErrorBehavior.default_option_value,
help="Raise an exception if any targets declaring source files "
"fail to match any glob provided in the 'sources' argument.")
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=[],
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>',
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,
help='Enables use of the pants daemon (and implicitly, the v2 engine). (Beta)')
# These facilitate configuring the native engine.
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.')
register('--print-exception-stacktrace', advanced=True, type=bool,
help='Print to console the full exception stack trace if encountered.')
# BinaryUtil options.
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=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,
help=("Maps output of uname for a machine to a binary search path: "
"(sysname, id) -> (os, arch), e.g. {('darwin', '15'): ('mac', '10.11'), "
"('linux', 'arm32'): ('linux', 'arm32')}."))
register('--allow-external-binary-tool-downloads', type=bool, default=True, advanced=True,
help="If False, require BinaryTool subclasses to download their contents from urls "
"generated from --binaries-baseurls, even if the tool has an external url "
"generator. This can be necessary if using Pants in an environment which cannot "
"contact the wider Internet.")
# Pants Daemon options.
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,
help='The port to bind the pants nailgun server to. Defaults to a random port.')
register('--pantsd-log-dir', advanced=True, default=None,
help='The directory to log pantsd output to.')
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.')
register('--pantsd-invalidation-globs', advanced=True, type=list, fromfile=True, default=[],
help='Filesystem events matching any of these globs will trigger a daemon restart.')
# Watchman options.
register('--watchman-version', advanced=True, default='4.9.0-pants1', 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 --binaries-baseurls and --pants-bootstrapdir.')
register('--watchman-startup-timeout', type=float, advanced=True, default=30.0,
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,
help='The watchman client socket timeout in seconds.')
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.')
# This option changes the parser behavior in a fundamental way (which currently invalidates
# all caches), and needs to be parsed out early, so we make it a bootstrap option.
register('--build-file-imports', choices=['allow', 'warn', 'error'], default='warn',
help='Whether to allow import statements in BUILD files')
register('--remote-store-server',
help='host:port of grpc server to use as remote execution file store')
register('--remote-execution-server',
help='host:port of grpc server to use as remote execution scheduler')
@classmethod
def register_options(cls, register):
"""Register options not tied to any particular task or subsystem."""
# The bootstrap options need to be registered on the post-bootstrap Options instance, so it
# won't choke on them on the command line, and also so we can access their values as regular
# global-scope options, for convenience.
cls.register_bootstrap_options(register)
register('-x', '--time', type=bool,
help='Output a timing report at the end of the run.')
register('-e', '--explain', type=bool,
help='Explain the execution of goals.')
register('--tag', type=list, metavar='[+-]tag1,tag2,...',
help="Include only targets with these tags (optional '+' prefix) or without these "
"tags ('-' prefix). Useful with ::, to find subsets of targets "
"(e.g., integration tests.)")
register('-t', '--timeout', advanced=True, type=int, metavar='<seconds>',
help='Number of seconds to wait for http connections.')
# TODO: After moving to the new options system these abstraction leaks can go away.
register('-k', '--kill-nailguns', advanced=True, type=bool,
help='Kill nailguns before exiting')
register('--fail-fast', advanced=True, type=bool, recursive=True,
help='Exit as quickly as possible on error, rather than attempting to continue '
'to process the non-erroneous subset of the input.')
register('--cache-key-gen-version', advanced=True, default='200', recursive=True,
help='The cache key generation. Bump this to invalidate every artifact for a scope.')
register('--workdir-max-build-entries', advanced=True, type=int, default=8,
help='Maximum number of previous builds to keep per task target pair in workdir. '
'If set, minimum 2 will always be kept to support incremental compilation.')
register('--max-subprocess-args', advanced=True, type=int, default=100, recursive=True,
help='Used to limit the number of arguments passed to some subprocesses by breaking '
'the command up into multiple invocations.')
register('--lock', advanced=True, type=bool, default=True,
help='Use a global lock to exclude other versions of pants from running during '
'critical operations.')