Skip to content

Commit

Permalink
Backfill existing options, by: 1) optionally add a deprecated depende…
Browse files Browse the repository at this point in the history
…ncy on a scoped `CacheSetup` instance, 2) adding a `LineOriented` mixin for `Goal`.
  • Loading branch information
stuhood committed Apr 12, 2019
1 parent db7df84 commit 7161ddd
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 18 deletions.
72 changes: 63 additions & 9 deletions src/python/pants/engine/goal.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
# coding=utf-8
# Copyright 2018 Pants project contributors (see CONTRIBUTORS.md).
# Copyright 2019 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).

from __future__ import absolute_import, division, print_function, unicode_literals

from contextlib import contextmanager

from pants.cache.cache_setup import CacheSetup
from pants.option.optionable import Optionable
from pants.option.scope import ScopeInfo
from pants.subsystem.subsystem_client_mixin import SubsystemClientMixin
from pants.util.meta import AbstractClass, classproperty


class Goal(Optionable, AbstractClass):
class Goal(SubsystemClientMixin, Optionable, AbstractClass):
"""A CLI goal whch is implemented by a `@console_rule`.
This abstract class should be subclassed and given a `Goal.name` that it will be referred to by
Expand All @@ -19,7 +23,10 @@ class Goal(Optionable, AbstractClass):
# Subclasser-defined. See the class pydoc.
name = None

options_scope_category = ScopeInfo.GOAL
# If this Goal should have an associated deprecated instance of `CacheSetup` (which was implicitly
# required by all v1 Tasks), subclasses may set this to a valid deprecation version to create
# that association.
deprecated_cache_setup_removal_version = None

@classproperty
def options_scope(cls):
Expand All @@ -29,12 +36,25 @@ def options_scope(cls):
return cls.name

@classmethod
def subsystem_dependencies_iter(cls):
# NB: `Goal` quacks like a `SubsystemClientMixin` in order to allow v1 `Tasks` to depend on
# v2 Goals for backwards compatibility purposes. But v2 Goals should _not_ have subsystem
# dependencies: instead, the @rules participating (transitively) in a Goal should directly
# declare Subsystem deps.
return iter([])
def subsystem_dependencies(cls):
# NB: `Goal` implements `SubsystemClientMixin` in order to allow v1 `Tasks` to depend on
# v2 Goals, and for `Goals` to declare a deprecated dependency on a `CacheSetup` instance for
# backwards compatibility purposes. But v2 Goals should _not_ have subsystem dependencies:
# instead, the @rules participating (transitively) in a Goal should directly declare
# Subsystem deps.
if cls.deprecated_cache_setup_removal_version:
dep = CacheSetup.scoped(
cls,
removal_version=cls.deprecated_cache_setup_removal_version,
removal_hint='Goal `{}` uses an independent caching implementation, and ignores `{}`.'.format(
cls.name,
CacheSetup.subscope(cls.name),
)
)
return (dep,)
return tuple()

options_scope_category = ScopeInfo.GOAL

def __init__(self, scope, scoped_options):
# NB: This constructor is shaped to meet the contract of `Optionable(Factory).signature`.
Expand All @@ -46,3 +66,37 @@ def __init__(self, scope, scoped_options):
def options(self):
"""Returns the option values for this Goal."""
return self._scoped_options


class LineOriented(object):
"""A mixin for Goal that adds options and a context manager for line-oriented output."""

@classmethod
def register_options(cls, register):
super(LineOriented, cls).register_options(register)
register('--sep', default='\\n', metavar='<separator>',
help='String to use to separate result lines.')
register('--output-file', metavar='<path>',
help='Write line-oriented output to this file instead.')

@contextmanager
def line_oriented(self, console):
"""Takes a Console and yields functions for writing to stdout and stderr, respectively."""

output_file = self.options.output_file
sep = self.options.sep.encode('utf-8').decode('unicode_escape')

stdout, stderr = console.stdout, console.stderr
if output_file:
stdout = open(output_file, 'w')

try:
print_stdout = lambda msg: print(msg, file=stdout, end=sep)
print_stderr = lambda msg: print(msg, file=stderr)
yield print_stdout, print_stderr
finally:
if output_file:
stdout.close()
else:
stdout.flush()
stderr.flush()
21 changes: 12 additions & 9 deletions src/python/pants/rules/core/list_targets.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
# coding=utf-8
# Copyright 2018 Pants project contributors (see CONTRIBUTORS.md).
# Copyright 2019 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).

from __future__ import absolute_import, division, print_function, unicode_literals

from pants.base.specs import Specs
from pants.engine.addressable import BuildFileAddresses
from pants.engine.console import Console
from pants.engine.goal import Goal
from pants.engine.goal import Goal, LineOriented
from pants.engine.legacy.graph import HydratedTargets
from pants.engine.rules import console_rule
from pants.engine.selectors import Get


class List(Goal):
class List(LineOriented, Goal):
"""Lists all targets matching the target specs."""

name = 'list'

deprecated_cache_setup_removal_version = '1.18.0.dev2'

@classmethod
def register_options(cls, register):
super(List, cls).register_options(register)
Expand Down Expand Up @@ -71,13 +73,14 @@ def print_documented(target):
collection = yield Get(BuildFileAddresses, Specs, specs)
print_fn = lambda address: address.spec

if not collection.dependencies:
console.print_stderr('WARNING: No targets were matched in goal `{}`.'.format('list'))
with list_goal.line_oriented(console) as (print_stdout, print_stderr):
if not collection.dependencies:
print_stderr('WARNING: No targets were matched in goal `{}`.'.format('list'))

for item in collection:
result = print_fn(item)
if result:
console.print_stdout(result)
for item in collection:
result = print_fn(item)
if result:
print_stdout(result)


def rules():
Expand Down

0 comments on commit 7161ddd

Please sign in to comment.