feat: add Perl to development environment and enhance toolchain accessibility

This commit is contained in:
maksyuki committed 2026-09-23 07:40:17 +08:00
1 parent b209ccedfe
commit 448d639d0e
6 files changed
+59 -2

No files matched your search

+1
View File
@@ -23,6 +23,7 @@ RUN apt-get update -qq \
mold \
numactl \
openjdk-17-jre-headless \
perl \
python3 \
python3-pip \
python3-venv \
+5 -1
View File
@@ -11,7 +11,8 @@ remote-bitbang debug acceptance flow. Docker, Nix, and manual Ubuntu installs
provide Java 17 for SBT. Docker and Nix use Python 3.10 to match the
hash-pinned Ubuntu 22.04 requirement sets. The environment also installs the
locked Python build and quality dependencies, clang-format-14, GNU Make,
C/C++ build tools, and runtime libraries required by those binaries.
C/C++ build tools, Perl for Verilator, and runtime libraries required by those
binaries.
The environment intentionally does not include PDK repositories, managed RTL,
application archives, build output, or compiler caches. These inputs are
@@ -33,6 +34,9 @@ Python requirements, and writes:
Bootstrap is idempotent. It reinstalls tools or Python packages when the
dependency lock, selected tool set, or Python requirement hashes change.
Installed public tool archives are made readable and their directories
traversable by all users. This is required when Docker builds the image as root
and runs regressions with the caller's user ID.
~~~sh
python3 scripts/development_environment.py bootstrap
+1
View File
@@ -65,6 +65,7 @@
ncurses5
numactl
jdk17_headless
perl
python310Full
unzip
which
+1
View File
@@ -60,6 +60,7 @@ SYSTEM_EXECUTABLES = (
"make",
"mold",
"numactl",
"perl",
)
STAMP_NAME = "development-environment.json"
ACTIVATE_NAME = "activate.sh"
+20
View File
@@ -6,9 +6,11 @@ import argparse
import os
import posixpath
import shutil
import stat
import sys
import tarfile
import tempfile
from itertools import chain
from pathlib import Path, PurePosixPath
from typing import Any
@@ -38,6 +40,22 @@ def safe_extract(archive: Path, destination: Path) -> None:
bundle.extractall(destination)
def make_tree_world_readable(root: Path) -> None:
"""Make a public tool archive usable by accounts other than its installer."""
for path in chain((root,), root.rglob("*")):
if path.is_symlink():
continue
mode = stat.S_IMODE(path.stat().st_mode)
if path.is_dir():
path.chmod(mode | 0o555)
elif path.is_file():
shared_mode = mode | 0o444
if mode & 0o111:
shared_mode |= 0o111
path.chmod(shared_mode)
def install(name: str, spec: dict[str, Any], cache: Path, update: bool) -> Path:
downloads = cache / "downloads"
archive = downloads / spec["archive"]
@@ -53,6 +71,7 @@ def install(name: str, spec: dict[str, Any], cache: Path, update: bool) -> Path:
destination = cache / "toolchains" / f"{name}-{spec['version']}"
marker = destination / ".complete"
if marker.is_file() and marker.read_text(encoding="utf-8").strip() == spec["sha256"]:
make_tree_world_readable(destination)
return destination / spec["path"]
destination.parent.mkdir(parents=True, exist_ok=True)
@@ -61,6 +80,7 @@ def install(name: str, spec: dict[str, Any], cache: Path, update: bool) -> Path:
extracted.mkdir()
safe_extract(archive, extracted)
atomic_write(extracted / ".complete", spec["sha256"] + "\n")
make_tree_world_readable(extracted)
if destination.exists():
shutil.rmtree(destination)
os.replace(extracted, destination)
+31 -1
View File
@@ -40,7 +40,7 @@ from scripts.development_environment import ( # noqa: E402
write_activation,
)
from scripts.generate_mpw import render_active_manifest, validate_extension_bindings # noqa: E402
from scripts.install_toolchain import safe_extract # noqa: E402
from scripts.install_toolchain import make_tree_world_readable, safe_extract # noqa: E402
from scripts.package import make_sbom # noqa: E402
from scripts.prepare_mpw import patch_serv # noqa: E402
from scripts import regress # noqa: E402
@@ -1193,10 +1193,12 @@ def test_container_and_nix_environment_files_use_locked_inputs() -> None:
assert f"ubuntu@{lock['container_images']['ubuntu_22_04']['digest']}" in dockerfile
assert "openjdk-17-jre-headless" in dockerfile
assert " perl \\\n" in dockerfile
assert "scripts/development_environment.py" in dockerfile
assert "scripts/development_environment.py" in flake
assert "buildFHSEnv" in flake
assert "jdk17_headless" in flake
assert " perl\n" in flake
assert "python310Full" in flake
assert "python3Full" not in flake
assert "retrosoc-development retrosoc-dev" in flake
@@ -2317,6 +2319,34 @@ def test_safe_extract_rejects_parent_traversal(tmp_path: Path) -> None:
assert not (tmp_path / "outside").exists()
def test_toolchain_tree_is_accessible_to_runtime_users(tmp_path: Path) -> None:
toolchain = tmp_path / "toolchain"
binary_directory = toolchain / "bundle/bin"
binary_directory.mkdir(parents=True)
executable = binary_directory / "tool"
executable.write_text("#!/bin/sh\n", encoding="utf-8")
data = toolchain / "bundle/data"
data.write_text("public tool data\n", encoding="utf-8")
marker = toolchain / ".complete"
marker.write_text("digest\n", encoding="utf-8")
toolchain.chmod(0o700)
(toolchain / "bundle").chmod(0o700)
binary_directory.chmod(0o700)
executable.chmod(0o700)
data.chmod(0o600)
marker.chmod(0o600)
make_tree_world_readable(toolchain)
assert toolchain.stat().st_mode & 0o777 == 0o755
assert (toolchain / "bundle").stat().st_mode & 0o777 == 0o755
assert binary_directory.stat().st_mode & 0o777 == 0o755
assert executable.stat().st_mode & 0o777 == 0o755
assert data.stat().st_mode & 0o777 == 0o644
assert marker.stat().st_mode & 0o777 == 0o644
def test_fatfs_update_reextracts_downloaded_archive(tmp_path: Path) -> None:
module_path = ROOT / "app/setup.py"
spec = importlib.util.spec_from_file_location("retrosoc_app_setup", module_path)