From 98e0b5b0db787ada2ae83e6b08818d1b1a8eab05 Mon Sep 17 00:00:00 2001 From: Greg Becker Date: Thu, 24 Jan 2019 12:10:32 -0800 Subject: Allow `spack install --overwrite` for nonexistent or multiple packages (#9201) * Allow overwrite nonexistent and multiple packages initial implementation give one prompt to users instead of a prompt per spec testing * flake * bugfix: install overwrite check each spec against installed * python3 compliance for filter/map --- lib/spack/spack/cmd/install.py | 40 +++++++++++++---------- lib/spack/spack/test/cmd/install.py | 63 ++++++++++++++++++++++++++++++++----- 2 files changed, 78 insertions(+), 25 deletions(-) (limited to 'lib') diff --git a/lib/spack/spack/cmd/install.py b/lib/spack/spack/cmd/install.py index fc79c5d689..5524324094 100644 --- a/lib/spack/spack/cmd/install.py +++ b/lib/spack/spack/cmd/install.py @@ -283,36 +283,42 @@ def install(parser, args, **kwargs): reporter.specs = specs with reporter: if args.overwrite: - # If we asked to overwrite an existing spec we must ensure that: - # 1. We have only one spec - # 2. The spec is already installed - assert len(specs) == 1, \ - "only one spec is allowed when overwriting an installation" - - spec = specs[0] - t = spack.store.db.query(spec) - assert len(t) == 1, "to overwrite a spec you must install it first" - - # Give the user a last chance to think about overwriting an already - # existing installation - if not args.yes_to_all: - tty.msg('The following package will be reinstalled:\n') + installed = list(filter(lambda x: x, + map(spack.store.db.query_one, specs))) + if not args.yes_to_all: display_args = { 'long': True, 'show_flags': True, 'variants': True } - spack.cmd.display_specs(t, **display_args) + if installed: + tty.msg('The following package specs will be ' + 'reinstalled:\n') + spack.cmd.display_specs(installed, **display_args) + + not_installed = list(filter(lambda x: x not in installed, + specs)) + if not_installed: + tty.msg('The following package specs are not installed and' + ' the --overwrite flag was given. The package spec' + ' will be newly installed:\n') + spack.cmd.display_specs(not_installed, **display_args) + + # We have some specs, so one of the above must have been true answer = tty.get_yes_or_no( 'Do you want to proceed?', default=False ) if not answer: tty.die('Reinstallation aborted.') - with fs.replace_directory_transaction(specs[0].prefix): - install_spec(args, kwargs, abstract_specs[0], specs[0]) + for abstract, concrete in zip(abstract_specs, specs): + if concrete in installed: + with fs.replace_directory_transaction(concrete.prefix): + install_spec(args, kwargs, abstract, concrete) + else: + install_spec(args, kwargs, abstract, concrete) else: for abstract, concrete in zip(abstract_specs, specs): diff --git a/lib/spack/spack/test/cmd/install.py b/lib/spack/spack/test/cmd/install.py index 12feba9555..f3e6a4d3ed 100644 --- a/lib/spack/spack/test/cmd/install.py +++ b/lib/spack/spack/test/cmd/install.py @@ -185,14 +185,6 @@ def test_show_log_on_error(mock_packages, mock_archive, mock_fetch, def test_install_overwrite( mock_packages, mock_archive, mock_fetch, config, install_mockery ): - # It's not possible to overwrite something that is not yet installed - with pytest.raises(AssertionError): - install('--overwrite', 'libdwarf') - - # --overwrite requires a single spec - with pytest.raises(AssertionError): - install('--overwrite', 'libdwarf', 'libelf') - # Try to install a spec and then to reinstall it. spec = Spec('libdwarf') spec.concretize() @@ -217,6 +209,61 @@ def test_install_overwrite( assert fs.hash_directory(spec.prefix) != bad_md5 +def test_install_overwrite_not_installed( + mock_packages, mock_archive, mock_fetch, config, install_mockery +): + # Try to install a spec and then to reinstall it. + spec = Spec('libdwarf') + spec.concretize() + + assert not os.path.exists(spec.prefix) + + install('--overwrite', '-y', 'libdwarf') + assert os.path.exists(spec.prefix) + + +def test_install_overwrite_multiple( + mock_packages, mock_archive, mock_fetch, config, install_mockery +): + # Try to install a spec and then to reinstall it. + libdwarf = Spec('libdwarf') + libdwarf.concretize() + + install('libdwarf') + + cmake = Spec('cmake') + cmake.concretize() + + install('cmake') + + assert os.path.exists(libdwarf.prefix) + expected_libdwarf_md5 = fs.hash_directory(libdwarf.prefix) + + assert os.path.exists(cmake.prefix) + expected_cmake_md5 = fs.hash_directory(cmake.prefix) + + # Modify the first installation to be sure the content is not the same + # as the one after we reinstalled + with open(os.path.join(libdwarf.prefix, 'only_in_old'), 'w') as f: + f.write('This content is here to differentiate installations.') + with open(os.path.join(cmake.prefix, 'only_in_old'), 'w') as f: + f.write('This content is here to differentiate installations.') + + bad_libdwarf_md5 = fs.hash_directory(libdwarf.prefix) + bad_cmake_md5 = fs.hash_directory(cmake.prefix) + + assert bad_libdwarf_md5 != expected_libdwarf_md5 + assert bad_cmake_md5 != expected_cmake_md5 + + install('--overwrite', '-y', 'libdwarf', 'cmake') + assert os.path.exists(libdwarf.prefix) + assert os.path.exists(cmake.prefix) + assert fs.hash_directory(libdwarf.prefix) == expected_libdwarf_md5 + assert fs.hash_directory(cmake.prefix) == expected_cmake_md5 + assert fs.hash_directory(libdwarf.prefix) != bad_libdwarf_md5 + assert fs.hash_directory(cmake.prefix) != bad_cmake_md5 + + @pytest.mark.usefixtures( 'mock_packages', 'mock_archive', 'mock_fetch', 'config', 'install_mockery', ) -- cgit v1.2.3-70-g09d2