-
-
Notifications
You must be signed in to change notification settings - Fork 612
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix RuleRunner to work without BUILD_ROOT file in pytest sandbox #21112
Changes from 5 commits
613fc8a
6ade39c
4388e1d
a162159
46189c9
bdf1d32
a54a5ac
081def4
8acc1ef
4a6fb0b
38a3418
87dbbcd
3a23a89
032c3f8
a938ca4
725e057
a84d29b
37d4ef5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,7 +24,6 @@ python_sources( | |
"pants_integration_test.py": { | ||
"dependencies": ["//BUILD_ROOT:files", "src/python/pants/__main__.py"] | ||
}, | ||
"rule_runner.py": {"dependencies": ["//BUILD_ROOT:files"]}, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the fix that makes the errors in external repos visible in the pants repo. |
||
}, | ||
) | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,6 +31,7 @@ | |
overload, | ||
) | ||
|
||
from pants.base.build_environment import get_buildroot | ||
from pants.base.build_root import BuildRoot | ||
from pants.base.specs_parser import SpecsParser | ||
from pants.build_graph.build_configuration import BuildConfiguration | ||
|
@@ -310,17 +311,23 @@ def rewrite_rule_for_inherent_environment(rule): | |
self.build_config = build_config_builder.create() | ||
|
||
self.environment = CompleteEnvironmentVars({}) | ||
self.options_bootstrapper = self.create_options_bootstrapper(args=bootstrap_args, env=None) | ||
self.extra_session_values = extra_session_values or {} | ||
self.inherent_environment = inherent_environment | ||
self.max_workunit_verbosity = max_workunit_verbosity | ||
options = self.options_bootstrapper.full_options( | ||
self.build_config, | ||
union_membership=UnionMembership.from_rules( | ||
rule for rule in self.rules if isinstance(rule, UnionRule) | ||
), | ||
) | ||
global_options = self.options_bootstrapper.bootstrap_options.for_global_scope() | ||
|
||
# Change cwd and add sentinel file (BUILDROOT) so NativeOptionParser can find build_root. | ||
with pushd(self.build_root): | ||
Path("BUILDROOT").touch() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I opted to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I didn't fully understand this comment. I'm fine with either one, but did you mean, using BUILDROOT in lieu of BUILD_ROOT so that it lines up with the other usages? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a Now, RuleRunner also adds a sentinel file to its own sandboxes. Using the variant with |
||
self.options_bootstrapper = self.create_options_bootstrapper( | ||
args=bootstrap_args, env=None | ||
) | ||
options = self.options_bootstrapper.full_options( | ||
self.build_config, | ||
union_membership=UnionMembership.from_rules( | ||
rule for rule in self.rules if isinstance(rule, UnionRule) | ||
), | ||
) | ||
global_options = self.options_bootstrapper.bootstrap_options.for_global_scope() | ||
|
||
dynamic_remote_options, _ = DynamicRemoteOptions.from_options(options, self.environment) | ||
local_store_options = LocalStoreOptions.from_options(global_options) | ||
|
@@ -398,7 +405,8 @@ def request(self, output_type: type[_O], inputs: Iterable[Any]) -> _O: | |
if self.inherent_environment | ||
else Params(*inputs) | ||
) | ||
result = assert_single_element(self.scheduler.product_request(output_type, [params])) | ||
with pushd(self.build_root): | ||
result = assert_single_element(self.scheduler.product_request(output_type, [params])) | ||
return cast(_O, result) | ||
|
||
def run_goal_rule( | ||
|
@@ -413,26 +421,28 @@ def run_goal_rule( | |
merged_args = (*(global_args or []), goal.name, *(args or [])) | ||
self.set_options(merged_args, env=env, env_inherit=env_inherit) | ||
|
||
raw_specs = self.options_bootstrapper.full_options_for_scopes( | ||
[GlobalOptions.get_scope_info(), goal.subsystem_cls.get_scope_info()], | ||
self.union_membership, | ||
).specs | ||
with pushd(self.build_root): | ||
raw_specs = self.options_bootstrapper.full_options_for_scopes( | ||
[GlobalOptions.get_scope_info(), goal.subsystem_cls.get_scope_info()], | ||
self.union_membership, | ||
).specs | ||
specs = SpecsParser(root_dir=self.build_root).parse_specs( | ||
raw_specs, description_of_origin="RuleRunner.run_goal_rule()" | ||
) | ||
|
||
stdout, stderr = StringIO(), StringIO() | ||
console = Console(stdout=stdout, stderr=stderr, use_colors=False, session=self.scheduler) | ||
|
||
exit_code = self.scheduler.run_goal_rule( | ||
goal, | ||
Params( | ||
specs, | ||
console, | ||
Workspace(self.scheduler), | ||
*([self.inherent_environment] if self.inherent_environment else []), | ||
), | ||
) | ||
with pushd(self.build_root): | ||
exit_code = self.scheduler.run_goal_rule( | ||
goal, | ||
Params( | ||
specs, | ||
console, | ||
Workspace(self.scheduler), | ||
*([self.inherent_environment] if self.inherent_environment else []), | ||
), | ||
) | ||
|
||
console.flush() | ||
return GoalRuleResult(exit_code, stdout.getvalue(), stderr.getvalue()) | ||
|
@@ -465,7 +475,8 @@ def set_options( | |
**{k: os.environ[k] for k in (env_inherit or set()) if k in os.environ}, | ||
**(env or {}), | ||
} | ||
self.options_bootstrapper = self.create_options_bootstrapper(args=args, env=env) | ||
with pushd(self.build_root): | ||
self.options_bootstrapper = self.create_options_bootstrapper(args=args, env=env) | ||
self.environment = CompleteEnvironmentVars(env) | ||
self._set_new_session(self.scheduler.scheduler) | ||
|
||
|
@@ -778,14 +789,15 @@ def mock_console( | |
*, | ||
stdin_content: bytes | str | None = None, | ||
) -> Iterator[tuple[Console, StdioReader]]: | ||
global_bootstrap_options = options_bootstrapper.bootstrap_options.for_global_scope() | ||
colors = ( | ||
options_bootstrapper.full_options_for_scopes( | ||
[GlobalOptions.get_scope_info()], UnionMembership({}), allow_unknown_options=True | ||
with pushd(get_buildroot()): | ||
global_bootstrap_options = options_bootstrapper.bootstrap_options.for_global_scope() | ||
colors = ( | ||
options_bootstrapper.full_options_for_scopes( | ||
[GlobalOptions.get_scope_info()], UnionMembership({}), allow_unknown_options=True | ||
) | ||
.for_global_scope() | ||
.colors | ||
) | ||
.for_global_scope() | ||
.colors | ||
) | ||
|
||
with initialize_stdio(global_bootstrap_options), stdin_context( | ||
stdin_content | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also tried removing the
//BUILD_ROOT:files
dependency frompants_integration_test.py
. But that didn't work, and it turned out to be a more invasive change.Fixing this will require removing or changing tmpdir creation functions in this file that call
get_buildroot()
repeatedly. We need to change that assumption so the test author can pass in the build root instead of having these functions calculate it from the current working directory, which happens to be the pytest sandbox.I suspect this issue existed before #20887 (ie it is not a new bug in 2.22.x), but
pants_integration_test
-based tests are far less common thanRuleRunner
based tests. Since this is (probably) not a new bug, we can deal with changing the assumptions in this code at some later date.