From 00d83cd79d7aa766d841853298de37e85c0fb458 Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Tue, 28 Apr 2020 09:55:57 -0700 Subject: dev-build: stop before phase (#14699) Add `-b,--before` option to dev-build command to stop before the phase in question. --- lib/spack/spack/cmd/dev_build.py | 10 +++++++-- lib/spack/spack/installer.py | 16 ++++++++++++-- lib/spack/spack/package.py | 6 +++++- lib/spack/spack/test/cmd/dev_build.py | 39 ++++++++++++++++++++++++++++++++++- 4 files changed, 65 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/cmd/dev_build.py b/lib/spack/spack/cmd/dev_build.py index c1004f24b3..7f42492808 100644 --- a/lib/spack/spack/cmd/dev_build.py +++ b/lib/spack/spack/cmd/dev_build.py @@ -37,10 +37,15 @@ def setup_parser(subparser): subparser.add_argument( '-q', '--quiet', action='store_true', dest='quiet', help="do not display verbose build output while installing") - subparser.add_argument( + arguments.add_common_arguments(subparser, ['spec']) + + stop_group = subparser.add_mutually_exclusive_group() + stop_group.add_argument( + '-b', '--before', type=str, dest='before', default=None, + help="phase to stop before when installing (default None)") + stop_group.add_argument( '-u', '--until', type=str, dest='until', default=None, help="phase to stop after when installing (default None)") - arguments.add_common_arguments(subparser, ['spec']) cd_group = subparser.add_mutually_exclusive_group() arguments.add_common_arguments(cd_group, ['clean', 'dirty']) @@ -91,4 +96,5 @@ def dev_build(self, args): verbose=not args.quiet, keep_stage=True, # don't remove source dir for dev build. dirty=args.dirty, + stop_before=args.before, stop_at=args.until) diff --git a/lib/spack/spack/installer.py b/lib/spack/spack/installer.py index 2bad1e8818..8886f3ed06 100644 --- a/lib/spack/spack/installer.py +++ b/lib/spack/spack/installer.py @@ -562,6 +562,8 @@ install_args_docstring = """ even with exceptions. restage (bool): Force spack to restage the package source. skip_patch (bool): Skip patch stage of build if True. + stop_before (InstallPhase): stop execution before this + installation phase (or None) stop_at (InstallPhase): last installation phase to be executed (or None) tests (bool or list or set): False to run no tests, True to test @@ -779,12 +781,20 @@ class PackageInstaller(object): Ensures the package being installed has a valid last phase before proceeding with the installation. - The ``stop_at`` argument is removed from the installation arguments. + The ``stop_before`` or ``stop_at`` arguments are removed from the + installation arguments. Args: kwargs: + ``stop_before``': stop before execution of this phase (or None) ``stop_at``': last installation phase to be executed (or None) """ + self.pkg.stop_before_phase = kwargs.pop('stop_before', None) + if self.pkg.stop_before_phase is not None and \ + self.pkg.stop_before_phase not in self.pkg.phases: + tty.die('\'{0}\' is not an allowed phase for package {1}' + .format(self.pkg.stop_before_phase, self.pkg.name)) + self.pkg.last_phase = kwargs.pop('stop_at', None) if self.pkg.last_phase is not None and \ self.pkg.last_phase not in self.pkg.phases: @@ -1504,8 +1514,10 @@ class PackageInstaller(object): self._update_installed(task) # If we installed then we should keep the prefix + stop_before_phase = getattr(pkg, 'stop_before_phase', None) last_phase = getattr(pkg, 'last_phase', None) - keep_prefix = last_phase is None or keep_prefix + keep_prefix = keep_prefix or \ + (stop_before_phase is None and last_phase is None) except spack.directory_layout.InstallDirectoryAlreadyExistsError: tty.debug("Keeping existing install prefix in place.") diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index b8ded0364b..40384077ea 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -115,7 +115,11 @@ class InstallPhase(object): return phase_wrapper def _on_phase_start(self, instance): - pass + # If a phase has a matching stop_before_phase attribute, + # stop the installation process raising a StopIteration + if getattr(instance, 'stop_before_phase', None) == self.name: + raise StopIteration('Stopping before \'{0}\' phase' + .format(self.name)) def _on_phase_exit(self, instance): # If a phase has a matching last_phase attribute, diff --git a/lib/spack/spack/test/cmd/dev_build.py b/lib/spack/spack/test/cmd/dev_build.py index a007513067..6afd07d815 100644 --- a/lib/spack/spack/test/cmd/dev_build.py +++ b/lib/spack/spack/test/cmd/dev_build.py @@ -3,8 +3,9 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) import os +import pytest import spack.spec -from spack.main import SpackCommand +from spack.main import SpackCommand, SpackCommandError dev_build = SpackCommand('dev-build') @@ -23,6 +24,22 @@ def test_dev_build_basics(tmpdir, mock_packages, install_mockery): assert f.read() == spec.package.replacement_string +def test_dev_build_before(tmpdir, mock_packages, install_mockery): + spec = spack.spec.Spec('dev-build-test-install@0.0.0').concretized() + + with tmpdir.as_cwd(): + with open(spec.package.filename, 'w') as f: + f.write(spec.package.original_string) + + dev_build('-b', 'edit', 'dev-build-test-install@0.0.0') + + assert spec.package.filename in os.listdir(os.getcwd()) + with open(spec.package.filename, 'r') as f: + assert f.read() == spec.package.original_string + + assert not os.path.exists(spec.prefix) + + def test_dev_build_until(tmpdir, mock_packages, install_mockery): spec = spack.spec.Spec('dev-build-test-install@0.0.0').concretized() @@ -39,6 +56,26 @@ def test_dev_build_until(tmpdir, mock_packages, install_mockery): assert not os.path.exists(spec.prefix) +def test_dev_build_before_until(tmpdir, mock_packages, install_mockery): + spec = spack.spec.Spec('dev-build-test-install@0.0.0').concretized() + + with tmpdir.as_cwd(): + with open(spec.package.filename, 'w') as f: + f.write(spec.package.original_string) + + with pytest.raises(SystemExit): + dev_build('-u', 'edit', '-b', 'edit', + 'dev-build-test-install@0.0.0') + + with pytest.raises(SpackCommandError): + dev_build('-u', 'phase_that_does_not_exist', + 'dev-build-test-install@0.0.0') + + with pytest.raises(SpackCommandError): + dev_build('-b', 'phase_that_does_not_exist', + 'dev-build-test-install@0.0.0') + + def test_dev_build_fails_already_installed(tmpdir, mock_packages, install_mockery): spec = spack.spec.Spec('dev-build-test-install@0.0.0').concretized() -- cgit v1.2.3-70-g09d2