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')
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)
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)