def test_dir_dest(self, stage):
        """Test using a directory as the destination."""

        with fs.working_dir(str(stage)):
            fs.copy('source/1', 'dest')

            assert os.path.exists('dest/1')
Exemple #2
0
    def test_dir_dest(self, stage):
        """Test using a directory as the destination."""

        with fs.working_dir(str(stage)):
            fs.copy('source/1', 'dest')

            assert os.path.exists('dest/1')
    def test_multiple_src_file_dest(self, stage):
        """Test a glob that matches multiple source files and a dest
        that is not a directory."""

        with fs.working_dir(str(stage)):
            match = '.* matches multiple files but .* is not a directory'
            with pytest.raises(ValueError, match=match):
                fs.copy('source/a/*/*', 'dest/1')
    def test_glob_src(self, stage):
        """Test using a glob as the source."""

        with fs.working_dir(str(stage)):
            fs.copy('source/a/*/*', 'dest')

            assert os.path.exists('dest/2')
            assert os.path.exists('dest/3')
    def test_non_existing_src(self, stage):
        """Test using a non-existing source."""

        with fs.working_dir(str(stage)):
            with pytest.raises(IOError, match='No such file or directory'):
                fs.copy('source/none', 'dest')
Exemple #6
0
    def _do_patch_config_files(self):
        """Some packages ship with older config.guess/config.sub files and
        need to have these updated when installed on a newer architecture.
        In particular, config.guess fails for PPC64LE for version prior
        to a 2013-06-10 build date (automake 1.13.4) and for ARM (aarch64).
        """
        if not self.patch_config_files or (
                not self.spec.satisfies('target=ppc64le:')
                and not self.spec.satisfies('target=aarch64:')):
            return

        # TODO: Expand this to select the 'config.sub'-compatible architecture
        # for each platform (e.g. 'config.sub' doesn't accept 'power9le', but
        # does accept 'ppc64le').
        if self.spec.satisfies('target=ppc64le:'):
            config_arch = 'ppc64le'
        elif self.spec.satisfies('target=aarch64:'):
            config_arch = 'aarch64'
        else:
            config_arch = 'local'

        def runs_ok(script_abs_path):
            # Construct the list of arguments for the call
            additional_args = {'config.sub': [config_arch]}
            script_name = os.path.basename(script_abs_path)
            args = [script_abs_path] + additional_args.get(script_name, [])

            try:
                check_call(args, stdout=PIPE, stderr=PIPE)
            except Exception as e:
                tty.debug(e)
                return False

            return True

        # Compute the list of files that needs to be patched
        search_dir = self.stage.path
        to_be_patched = fs.find(search_dir,
                                files=['config.sub', 'config.guess'],
                                recursive=True)
        to_be_patched = [f for f in to_be_patched if not runs_ok(f)]

        # If there are no files to be patched, return early
        if not to_be_patched:
            return

        # Directories where to search for files to be copied
        # over the failing ones
        good_file_dirs = ['/usr/share']
        if 'automake' in self.spec:
            good_file_dirs.insert(0, self.spec['automake'].prefix)

        # List of files to be found in the directories above
        to_be_found = list(set(os.path.basename(f) for f in to_be_patched))
        substitutes = {}
        for directory in good_file_dirs:
            candidates = fs.find(directory, files=to_be_found, recursive=True)
            candidates = [f for f in candidates if runs_ok(f)]
            for name, good_files in itertools.groupby(candidates,
                                                      key=os.path.basename):
                substitutes[name] = next(good_files)
                to_be_found.remove(name)

        # Check that we found everything we needed
        if to_be_found:
            msg = 'Failed to find suitable substitutes for {0}'
            raise RuntimeError(msg.format(', '.join(to_be_found)))

        # Copy the good files over the bad ones
        for abs_path in to_be_patched:
            name = os.path.basename(abs_path)
            mode = os.stat(abs_path).st_mode
            os.chmod(abs_path, stat.S_IWUSR)
            fs.copy(substitutes[name], abs_path)
            os.chmod(abs_path, mode)
Exemple #7
0
    def _do_patch_config_files(self):
        """Some packages ship with older config.guess/config.sub files and
        need to have these updated when installed on a newer architecture.
        In particular, config.guess fails for PPC64LE for version prior
        to a 2013-06-10 build date (automake 1.13.4) and for ARM (aarch64) and
        RISC-V (riscv64).
        """
        if not self.patch_config_files:
            return

        # TODO: Expand this to select the 'config.sub'-compatible architecture
        # for each platform (e.g. 'config.sub' doesn't accept 'power9le', but
        # does accept 'ppc64le').
        if self.spec.satisfies('target=ppc64le:'):
            config_arch = 'ppc64le'
        elif self.spec.satisfies('target=aarch64:'):
            config_arch = 'aarch64'
        elif self.spec.satisfies('target=riscv64:'):
            config_arch = 'riscv64'
        else:
            config_arch = 'local'

        def runs_ok(script_abs_path):
            # Construct the list of arguments for the call
            additional_args = {'config.sub': [config_arch]}
            script_name = os.path.basename(script_abs_path)
            args = [script_abs_path] + additional_args.get(script_name, [])

            try:
                check_call(args, stdout=PIPE, stderr=PIPE)
            except Exception as e:
                tty.debug(e)
                return False

            return True

        # Get the list of files that needs to be patched
        to_be_patched = fs.find(self.stage.path,
                                files=['config.sub', 'config.guess'])
        to_be_patched = [f for f in to_be_patched if not runs_ok(f)]

        # If there are no files to be patched, return early
        if not to_be_patched:
            return

        # Otherwise, require `gnuconfig` to be a build dependency
        self._require_build_deps(pkgs=['gnuconfig'],
                                 spec=self.spec,
                                 err="Cannot patch config files")

        # Get the config files we need to patch (config.sub / config.guess).
        to_be_found = list(set(os.path.basename(f) for f in to_be_patched))
        gnuconfig = self.spec['gnuconfig']
        gnuconfig_dir = gnuconfig.prefix

        # An external gnuconfig may not not have a prefix.
        if gnuconfig_dir is None:
            raise InstallError(
                "Spack could not find substitutes for GNU config "
                "files because no prefix is available for the "
                "`gnuconfig` package. Make sure you set a prefix "
                "path instead of modules for external `gnuconfig`.")

        candidates = fs.find(gnuconfig_dir, files=to_be_found, recursive=False)

        # For external packages the user may have specified an incorrect prefix.
        # otherwise the installation is just corrupt.
        if not candidates:
            msg = ("Spack could not find `config.guess` and `config.sub` "
                   "files in the `gnuconfig` prefix `{0}`. This means the "
                   "`gnuconfig` package is broken").format(gnuconfig_dir)
            if gnuconfig.external:
                msg += (
                    " or the `gnuconfig` package prefix is misconfigured as"
                    " an external package")
            raise InstallError(msg)

        # Filter working substitutes
        candidates = [f for f in candidates if runs_ok(f)]
        substitutes = {}
        for candidate in candidates:
            config_file = os.path.basename(candidate)
            substitutes[config_file] = candidate
            to_be_found.remove(config_file)

        # Check that we found everything we needed
        if to_be_found:
            msg = """\
Spack could not find working replacements for the following autotools config
files: {0}.

To resolve this problem, please try the following:
1. Try to rebuild with `patch_config_files = False` in the package `{1}`, to
   rule out that Spack tries to replace config files not used by the build.
2. Verify that the `gnuconfig` package is up-to-date.
3. On some systems you need to use system-provided `config.guess` and `config.sub`
   files. In this case, mark `gnuconfig` as an non-buildable external package,
   and set the prefix to the directory containing the `config.guess` and
   `config.sub` files.
"""
            raise InstallError(msg.format(', '.join(to_be_found), self.name))

        # Copy the good files over the bad ones
        for abs_path in to_be_patched:
            name = os.path.basename(abs_path)
            mode = os.stat(abs_path).st_mode
            os.chmod(abs_path, stat.S_IWUSR)
            fs.copy(substitutes[name], abs_path)
            os.chmod(abs_path, mode)