Repository URL to install this package:
|
Version:
1.26.0.dev0+gite506aa5f ▾
|
# Copyright 2014 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).
import errno
import os
from contextlib import contextmanager
from pants.base.deprecated import deprecated_conditional
from pants.base.exceptions import TaskError
from pants.task.task import QuietTaskMixin, Task
from pants.util.dirutil import safe_open
from pants.util.meta import classproperty
class ConsoleTask(QuietTaskMixin, Task):
"""A task whose only job is to print information to the console.
ConsoleTasks are not intended to modify build state.
"""
@classproperty
def _register_console_transitivity_option(cls):
"""Some tasks register their own --transitive option, which act differently."""
return True
@classmethod
def register_options(cls, register):
super().register_options(register)
register(
"--sep", default="\\n", metavar="<separator>", help="String to use to separate results."
)
register(
"--output-file", metavar="<path>", help="Write the console output to this file instead."
)
if cls._register_console_transitivity_option:
register(
"--transitive",
type=bool,
default=True,
fingerprint=True,
help="If True, use all targets in the build graph, else use only target roots.",
)
@property
def act_transitively(self):
if self._register_console_transitivity_option:
deprecated_conditional(
lambda: self.get_options().is_default("transitive"),
entity_description=f"Pants defaulting to `--transitive` for `{self.options_scope}`",
removal_version="1.27.0.dev0",
hint_message="Currently, Pants defaults to `--transitive`, which means that it "
"will run against transitive dependencies for the targets you specify on the "
"command line, rather than only the targets you specify. This is often useful, "
"such as running `./pants dependencies --transitive`, but it is surprising "
"to have this behavior by default.\n\nTo prepare for this change to the default "
f"value, set in `pants.ini` under the section `{self.options_scope}` the value "
"`transitive: False`. In Pants 1.27.0, you can safely remove the setting.",
)
return self.get_options().transitive
# `Task` defaults to returning `True` in `act_transitively`, so we keep that default value.
return self.get_options().get("transitive", True)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._console_separator = self.get_options().sep.encode().decode("unicode_escape")
if self.get_options().output_file:
try:
self._outstream = safe_open(os.path.abspath(self.get_options().output_file), "wb")
except IOError as e:
raise TaskError(
"Error opening stream {out_file} due to"
" {error_str}".format(out_file=self.get_options().output_file, error_str=e)
)
else:
self._outstream = self.context.console_outstream
@contextmanager
def _guard_sigpipe(self):
try:
yield
except IOError as e:
# If the pipeline only wants to read so much, that's fine; otherwise, this error is probably
# legitimate.
if e.errno != errno.EPIPE:
raise e
def execute(self):
with self._guard_sigpipe():
try:
targets = self.get_targets() if self.act_transitively else self.context.target_roots
for value in self.console_output(targets) or tuple():
self._outstream.write(value.encode())
self._outstream.write(self._console_separator.encode())
finally:
self._outstream.flush()
if self.get_options().output_file:
self._outstream.close()
def console_output(self, targets):
raise NotImplementedError("console_output must be implemented by subclasses of ConsoleTask")