Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 27 additions & 5 deletions src/bootstrap/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -926,6 +926,15 @@ def get_toml(self, key, section=None):
>>> rb.get_toml('key', 'c') is None
True

A dotted key is treated as belonging to the table named by its prefix,
so the section must match for the key to be found:

>>> rb.config_toml = 'build.cargo = "/path/to/cargo"'
>>> rb.get_toml('cargo', 'build')
'/path/to/cargo'
>>> rb.get_toml('cargo', 'other') is None
True

>>> rb.config_toml = 'key1 = true'
>>> rb.get_toml("key1")
'true'
Expand All @@ -940,10 +949,20 @@ def get_toml_static(config_toml, key, section=None):
if section_match is not None:
cur_section = section_match.group(1)

match = re.match(r"^{}\s*=(.*)$".format(key), line)
# Match the key, optionally preceded by a dotted-table prefix such as
# the `build.` in `build.cargo = "..."`. When present, that prefix
# names the table the key belongs to, mirroring how configure.py
# strips the `section.` part when writing bootstrap.toml. This is not
# a full TOML parser, only the subset bootstrap.toml uses.
match = re.match(
r"^\s*(?:([\w.-]+)\.)?{}\s*=(.*)$".format(re.escape(key)), line
)
if match is not None:
value = match.group(1)
if section is None or section == cur_section:
line_section = (
match.group(1) if match.group(1) is not None else cur_section
)
value = match.group(2)
if section is None or section == line_section:
return RustBuild.get_string(value) or value.strip()
return None

Expand All @@ -959,7 +978,10 @@ def program_config(self, program):
"""Return config path for the given program at the given stage

>>> rb = RustBuild()
>>> rb.config_toml = 'rustc = "rustc"\\n'
>>> rb.config_toml = 'build.rustc = "rustc"\\n'
>>> rb.program_config('rustc')
'rustc'
>>> rb.config_toml = '[build]\\nrustc = "rustc"\\n'
>>> rb.program_config('rustc')
'rustc'
>>> rb.config_toml = ''
Expand All @@ -968,7 +990,7 @@ def program_config(self, program):
... "bin", "cargo")
True
"""
config = self.get_toml(program)
config = self.get_toml(program, "build")
if config:
return os.path.expanduser(config)
return os.path.join(self.bin_root(), "bin", "{}{}".format(program, EXE_SUFFIX))
Expand Down
48 changes: 48 additions & 0 deletions src/bootstrap/bootstrap_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,54 @@ def test_set_codegen_backends(self):
self.assertNotEqual(build.config_toml.find("codegen-backends = ['llvm']"), -1)


class GetTomlDottedKeys(unittest.TestCase):
"""Test that get_toml understands the dotted-table key syntax that a
hand-written bootstrap.toml may use (e.g. `build.cargo = "..."`), and that
it checks the table a key belongs to. See issue #156948."""

def parse(self, config_toml):
return bootstrap.RustBuild(config_toml=config_toml, args=bootstrap.FakeArgs())

def test_dotted_key(self):
build = self.parse('build.cargo = "/path/to/cargo"')
self.assertEqual(build.get_toml("cargo", "build"), "/path/to/cargo")

def test_dotted_key_matches_section_form(self):
dotted = self.parse('build.cargo = "/path/to/cargo"')
section = self.parse('[build]\ncargo = "/path/to/cargo"')
self.assertEqual(
dotted.get_toml("cargo", "build"), section.get_toml("cargo", "build")
)

def test_dotted_key_wrong_section(self):
# A `cargo` key in some other table must not be picked up for `build`.
build = self.parse('[foo]\ncargo = "false"')
self.assertIsNone(build.get_toml("cargo", "build"))

def test_program_config_requires_build_table(self):
# A cargo/rustc key outside [build] must be ignored; program_config
# falls back to the stage0 default path rather than the misplaced value.
wrong = self.parse('[foo]\ncargo = "/wrong/cargo"')
cargo_default = os.path.join(
wrong.bin_root(), "bin", "cargo" + bootstrap.EXE_SUFFIX
)
self.assertEqual(wrong.cargo(), cargo_default)

wrong_rustc = self.parse('[foo]\nrustc = "/wrong/rustc"')
rustc_default = os.path.join(
wrong_rustc.bin_root(), "bin", "rustc" + bootstrap.EXE_SUFFIX
)
self.assertEqual(wrong_rustc.rustc(), rustc_default)

# A dotted key in the build table is honored.
right = self.parse('build.cargo = "/path/to/cargo"')
self.assertEqual(right.cargo(), "/path/to/cargo")

def test_dotted_target_key(self):
build = self.parse('target.x86_64-unknown-linux-gnu.cc = "gcc"')
self.assertEqual(build.get_toml("cc", "target.x86_64-unknown-linux-gnu"), "gcc")


class BuildBootstrap(unittest.TestCase):
"""Test that we generate the appropriate arguments when building bootstrap"""

Expand Down
Loading