Created
March 31, 2019 02:21
-
-
Save LiuVII/733bc113d072397eae8bf04417762375 to your computer and use it in GitHub Desktop.
Files for "must set an options_scope class-level property" issue
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# coding=utf-8 | |
# Copyright 2015 Foursquare Labs Inc. All Rights Reserved. | |
from __future__ import absolute_import, division, print_function, unicode_literals | |
from collections import namedtuple | |
import os | |
import shutil | |
import subprocess | |
from pants.base.build_environment import get_buildroot | |
from pants.base.exceptions import TaskError | |
from pants.base.workunit import WorkUnitLabel | |
from pants.util.memo import memoized_property | |
from fsqio.pants.spindle.tasks.spindle_task import SpindleTask | |
class BuildSpindle(SpindleTask): | |
"""Build spindle in a shelled pants invocation before using it for limited codegen. | |
This task is specialized to build just one target - the spindle codegen binary. The spindle binary requires | |
spindle to do codegen for itself in order to build. This self-dependency has required this hijack of | |
the round engine by shelling into a separate pants invocation. | |
This task should have as few side-effects as possible! | |
It allows a sane workflow when modifying the Spindle source, by forcing the circular dependency to point to the | |
frozen checkout of the binary source. | |
This task should only be installed if you intend to modify Spindle source code or ssp files. If so, make sure your | |
build has access to the the frozen checkout at src/jvm/io/fsq/spindle/codegen/__shaded_for_spindle_bootstrap__ in | |
addition to the Spindle source code that you will be changing. | |
""" | |
options_scope = "build-spindle" | |
PANTS_SCRIPT_NAME = 'pants' | |
PantsResult = namedtuple('PantsResult', ['command', 'returncode']) | |
def __init__(self, *args, **kwargs): | |
print("type(self): {}".format(type(self))) | |
print("type(self).options_scope: {}".format(type(self).options_scope)) | |
print(isinstance(b"test", str)) | |
print(isinstance(u"test", str)) | |
print("isinstance(type(self).options_scope, str): {}".format(isinstance(type(self).options_scope, str))) | |
super(BuildSpindle, self).__init__(*args, **kwargs) | |
@property | |
def cache_target_dirs(self): | |
return True | |
def run_pants_no_lock(self, command, workunit_name=None, **kwargs): | |
global_args = ['--quiet'] if self.get_options().quiet else [] | |
if self.get_options().level == 'debug': | |
global_args.append('-ldebug') | |
global_args.extend([ | |
'--no-pantsrc', | |
'--no-lock', | |
]) | |
pants_script = os.path.join(get_buildroot(), self.PANTS_SCRIPT_NAME) | |
pants_command = [pants_script] + global_args + command | |
with self.context.new_workunit(name=workunit_name, labels=[WorkUnitLabel.RUN]) as workunit: | |
proc = subprocess.Popen( | |
pants_command, | |
stdout=workunit.output('stdout'), | |
stderr=workunit.output('stderr'), | |
**kwargs | |
) | |
proc.communicate() | |
return self.PantsResult(pants_command, proc.returncode) | |
@classmethod | |
def register_options(cls, register): | |
super(BuildSpindle, cls).register_options(register) | |
register( | |
'--shelled', | |
fingerprint=True, | |
advanced=True, | |
type=bool, | |
default=False, | |
help="Don't pass this flag, internal use only!", | |
) | |
@classmethod | |
def product_types(cls): | |
return ['spindle_binary'] | |
@classmethod | |
def implementation_version(cls): | |
return super(BuildSpindle, cls).implementation_version() + [('BuildSpindle', 1)] | |
@memoized_property | |
def spindle_bundle_out(self): | |
# NOTE(omer): Not sure why this is necessary, but our bundle gets written to a different path from what's expected in Fsqio | |
# return os.path.join(self.get_options().pants_distdir, 'spindle-bundle', 'spindle.jar') | |
return os.path.join(self.get_options().pants_distdir, 'src.jvm.io.fsq.spindle.codegen.spindle-bundle', 'spindle.jar') | |
def execute(self): | |
# The 'shelled' option is only passed by this execute method and indicates a shelled run of pants. | |
if not self.get_options().shelled: | |
# This task is specialized to build just one target - the spindle source. | |
targets = [self.spindle_target] | |
# TODO: This invalidation is incomplete and should do the stuff done by the jvm_compile fingerprint | |
# strategy. But since this task is scheduled to complete before the classpath is resolved, this is tricky. | |
with self.invalidated(targets, invalidate_dependents=True) as invalidation_check: | |
targets = invalidation_check.all_vts | |
if targets and len(targets) != 1: | |
raise TaskError("There should only be one versioned target for the build_spindle task!" | |
"(was: {})".format(targets)) | |
vt = targets[0] | |
invalid_vts_by_target = {vt.target: vt} | |
if not vt.valid: | |
args = [ | |
'--no-cache-read', '--build-spindle-shelled', 'bundle', '--bundle-jvm-deployjar', | |
'--cache-bundle-jvm-read-from=[]', '--cache-bundle-jvm-write-to=[]', | |
] | |
args.append(self.get_options().spindle_codegen_binary) | |
results = self.run_pants_no_lock(args, workunit_name='spindle-build') | |
if results.returncode != 0: | |
# Purposefully not returning a message so the error from the shelled run can be surfaced. | |
raise TaskError() | |
spindle_bundle = self.spindle_bundle_out | |
spindle_binary = os.path.join(vt.results_dir, 'spindle-bundle.jar') | |
try: | |
shutil.copy(spindle_bundle, spindle_binary) | |
except Exception as e: | |
raise TaskError("Could not copy the spindle binary at {}:\n{}".format(spindle_bundle, e)) | |
self.context.products.get('spindle_binary').add(vt.target, vt.results_dir).append('spindle-bundle.jar') |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# coding=utf-8 | |
# Copyright 2015 Foursquare Labs Inc. All Rights Reserved. | |
from __future__ import absolute_import, division, print_function, unicode_literals | |
import os | |
from pants.backend.jvm.targets.jvm_binary import JvmBinary | |
from pants.backend.jvm.tasks.nailgun_task import NailgunTask | |
from pants.base.exceptions import TaskError | |
from pants.build_graph.address import Address | |
from pants.option.custom_types import target_option | |
from pants.util.memo import memoized_property | |
from fsqio.pants.spindle.targets.ssp_template import SspTemplate | |
class SpindleTask(NailgunTask): | |
"""A base class to declare and verify options for spindle tasks.""" | |
options_scope = "spindle-task" | |
def __init__(self, *args, **kwargs): | |
print("type(self): {}".format(type(self))) | |
print("type(self).options_scope: {}".format(type(self).options_scope)) | |
print("isinstance(type(self).options_scope, str): {}".format(isinstance(type(self).options_scope, str))) | |
super(SpindleTask, self).__init__(*args, **kwargs) | |
class BadDependency(TaskError): | |
"""Raise when spindle will error due to missing dependencies.""" | |
@classmethod | |
def register_options(cls, register): | |
super(SpindleTask, cls).register_options(register) | |
register( | |
'--spindle-codegen-binary', | |
fingerprint=True, | |
advanced=True, | |
type=target_option, | |
help='Use this Spindle source to generate code.', | |
) | |
@classmethod | |
def implementation_version(cls): | |
return super(SpindleTask, cls).implementation_version() + [('SpindleTask', 3)] | |
@property | |
def cache_target_dirs(self): | |
return True | |
@memoized_property | |
def spindle_target(self): | |
return self.get_spindle_target( | |
'spindle_codegen_binary', | |
self.get_options().spindle_codegen_binary, | |
JvmBinary, | |
) | |
def get_ssp_templates(self, template_target): | |
if not isinstance(template_target, SspTemplate): | |
raise TaskError( | |
'Spindle codegen requires being passed templates as SspTemplate targets (was: {})'.format(template_target) | |
) | |
return os.path.join(template_target.address.spec_path, template_target.entry_point) | |
def get_spindle_target(self, option_name, option_value, target_type): | |
return self.resolve_target(option_value, target_type) | |
def resolve_target(self, spec, target_type): | |
build_graph = self.context.build_graph | |
address = Address.parse(spec) | |
build_graph.inject_address_closure(address) | |
target = build_graph.get_target(address) | |
if not isinstance(target, target_type): | |
raise self.BadDependency( | |
'{} must point to a {} target: (was: {})'.format(spec, target_type, target), | |
) | |
return target |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment