diff --git a/amaranth/build/run.py b/amaranth/build/run.py index 39d5ed5..0784b48 100644 --- a/amaranth/build/run.py +++ b/amaranth/build/run.py @@ -64,15 +64,10 @@ class BuildPlan: for filename in sorted(self.files): archive.writestr(zipfile.ZipInfo(filename), self.files[filename]) - def execute_local(self, root="build", *, run_script=True, env=None): - """ - Execute build plan using the local strategy. Files from the build plan are placed in - the build root directory ``root``, and, if ``run_script`` is ``True``, the script - appropriate for the platform (``{script}.bat`` on Windows, ``{script}.sh`` elsewhere) - is executed in the build root. If ``env`` is not ``None``, the environment is replaced - with ``env``. + def extract(self, root="build"): + """Extracts the files from the build plan into the local build directory ``root``. - Returns :class:`LocalBuildProducts`. + Returns :class:`pathlib.Path` """ os.makedirs(root, exist_ok=True) cwd = os.getcwd() @@ -92,23 +87,34 @@ class BuildPlan: content = content.encode("utf-8") with open(filename, "wb") as f: f.write(content) - - if run_script: - if sys.platform.startswith("win32"): - # Without "call", "cmd /c {}.bat" will return 0. - # See https://stackoverflow.com/a/30736987 for a detailed explanation of why. - # Running the script manually from a command prompt is unaffected. - subprocess.check_call(["cmd", "/c", f"call {self.script}.bat"], - env=os.environ if env is None else env) - else: - subprocess.check_call(["sh", f"{self.script}.sh"], - env=os.environ if env is None else env) - - return LocalBuildProducts(os.getcwd()) - + return pathlib.Path(os.getcwd()) finally: os.chdir(cwd) + def execute_local(self, root="build", *, run_script=True, env=None): + """ + Execute build plan using the local strategy. Files from the build plan are placed in + the build root directory ``root``, and, if ``run_script`` is ``True``, the script + appropriate for the platform (``{script}.bat`` on Windows, ``{script}.sh`` elsewhere) + is executed in the build root. If ``env`` is not ``None``, the environment is replaced + with ``env``. + + Returns :class:`LocalBuildProducts`. + """ + build_dir = self.extract(root) + if run_script: + if sys.platform.startswith("win32"): + # Without "call", "cmd /c {}.bat" will return 0. + # See https://stackoverflow.com/a/30736987 for a detailed explanation of why. + # Running the script manually from a command prompt is unaffected. + subprocess.check_call(["cmd", "/c", f"call {self.script}.bat"], + env=os.environ if env is None else env) + else: + subprocess.check_call(["sh", f"{self.script}.sh"], + env=os.environ if env is None else env) + + return LocalBuildProducts(build_dir) + def execute_remote_ssh(self, *, connect_to={}, root, run_script=True): """ Execute build plan using the remote SSH strategy. Files from the build diff --git a/docs/changes.rst b/docs/changes.rst index 8dbb71a..16229cd 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -35,6 +35,7 @@ Platform integration changes .. currentmodule:: amaranth.vendor +* Added: :meth:`BuildPlan.extract`. * Added: ``build.sh`` begins with ``#!/bin/sh``. * Removed: (deprecated in 0.4) :mod:`vendor.intel`, :mod:`vendor.lattice_ecp5`, :mod:`vendor.lattice_ice40`, :mod:`vendor.lattice_machxo2_3l`, :mod:`vendor.quicklogic`, :mod:`vendor.xilinx`. (`RFC 18`_)