def relocate_package(workdir, spec, allow_root): """ Relocate the given package """ buildinfo = read_buildinfo_file(workdir) new_path = str(spack.store.layout.root) new_prefix = str(spack.paths.prefix) old_path = str(buildinfo['buildpath']) old_prefix = str( buildinfo.get('spackprefix', '/not/in/buildinfo/dictionary')) rel = buildinfo.get('relative_rpaths', False) if rel: return tty.msg("Relocating package from", "%s to %s." % (old_path, new_path)) path_names = set() for filename in buildinfo['relocate_textfiles']: path_name = os.path.join(workdir, filename) # Don't add backup files generated by filter_file during install step. if not path_name.endswith('~'): path_names.add(path_name) relocate.relocate_text(path_names, oldpath=old_path, newpath=new_path, oldprefix=old_prefix, newprefix=new_prefix) # If the binary files in the package were not edited to use # relative RPATHs, then the RPATHs need to be relocated if rel: if old_path != new_path: files_to_relocate = list( filter( lambda pathname: not relocate.file_is_relocatable( pathname, paths_to_relocate=[old_path, old_prefix]), map(lambda filename: os.path.join(workdir, filename), buildinfo['relocate_binaries']))) if len(old_path) < len(new_path) and files_to_relocate: tty.debug('Cannot do a binary string replacement with padding ' 'for package because %s is longer than %s.' % (new_path, old_path)) else: for path_name in files_to_relocate: relocate.replace_prefix_bin(path_name, old_path, new_path) else: path_names = set() for filename in buildinfo['relocate_binaries']: path_name = os.path.join(workdir, filename) path_names.add(path_name) if spec.architecture.platform == 'darwin': relocate.relocate_macho_binaries(path_names, old_path, new_path, allow_root) else: relocate.relocate_elf_binaries(path_names, old_path, new_path, allow_root) path_names = set() for filename in buildinfo.get('relocate_links', []): path_name = os.path.join(workdir, filename) path_names.add(path_name) relocate.relocate_links(path_names, old_path, new_path)
def test_relocate_text(tmpdir): spec = Spec('trivial-install-test-package') spec.concretize() with tmpdir.as_cwd(): # Validate the text path replacement old_dir = '/home/spack/opt/spack' filename = 'dummy.txt' with open(filename, "w") as script: script.write(old_dir) script.close() filenames = [filename] new_dir = '/opt/rh/devtoolset/' # Singleton dict doesn't matter if Ordered relocate_text(filenames, {old_dir: new_dir}) with open(filename, "r")as script: for line in script: assert(new_dir in line) assert(file_is_relocatable(os.path.realpath(filename))) # Remove cached binary specs since we deleted the mirror bindist._cached_specs = set()
def relocate_package(spec, allow_root): """ Relocate the given package """ workdir = str(spec.prefix) buildinfo = read_buildinfo_file(workdir) new_layout_root = str(spack.store.layout.root) new_prefix = str(spec.prefix) new_rel_prefix = str(os.path.relpath(new_prefix, new_layout_root)) new_spack_prefix = str(spack.paths.prefix) old_layout_root = str(buildinfo['buildpath']) old_spack_prefix = str(buildinfo.get('spackprefix')) old_rel_prefix = buildinfo.get('relative_prefix') old_prefix = os.path.join(old_layout_root, old_rel_prefix) rel = buildinfo.get('relative_rpaths') prefix_to_hash = buildinfo.get('prefix_to_hash', None) if (old_rel_prefix != new_rel_prefix and not prefix_to_hash): msg = "Package tarball was created from an install " msg += "prefix with a different directory layout and an older " msg += "buildcache create implementation. It cannot be relocated." raise NewLayoutException(msg) # older buildcaches do not have the prefix_to_hash dictionary # need to set an empty dictionary and add one entry to # prefix_to_prefix to reproduce the old behavior if not prefix_to_hash: prefix_to_hash = dict() hash_to_prefix = dict() hash_to_prefix[spec.format('{hash}')] = str(spec.package.prefix) new_deps = spack.build_environment.get_rpath_deps(spec.package) for d in new_deps: hash_to_prefix[d.format('{hash}')] = str(d.prefix) prefix_to_prefix = dict() for orig_prefix, hash in prefix_to_hash.items(): prefix_to_prefix[orig_prefix] = hash_to_prefix.get(hash, None) prefix_to_prefix[old_prefix] = new_prefix prefix_to_prefix[old_layout_root] = new_layout_root tty.debug("Relocating package from", "%s to %s." % (old_layout_root, new_layout_root)) def is_backup_file(file): return file.endswith('~') # Text files containing the prefix text text_names = list() for filename in buildinfo['relocate_textfiles']: text_name = os.path.join(workdir, filename) # Don't add backup files generated by filter_file during install step. if not is_backup_file(text_name): text_names.append(text_name) # If we are not installing back to the same install tree do the relocation if old_layout_root != new_layout_root: files_to_relocate = [ os.path.join(workdir, filename) for filename in buildinfo.get('relocate_binaries') ] # If the buildcache was not created with relativized rpaths # do the relocation of path in binaries if (spec.architecture.platform == 'darwin' or spec.architecture.platform == 'test' and platform.system().lower() == 'darwin'): relocate.relocate_macho_binaries(files_to_relocate, old_layout_root, new_layout_root, prefix_to_prefix, rel, old_prefix, new_prefix) if (spec.architecture.platform == 'linux' or spec.architecture.platform == 'test' and platform.system().lower() == 'linux'): relocate.relocate_elf_binaries(files_to_relocate, old_layout_root, new_layout_root, prefix_to_prefix, rel, old_prefix, new_prefix) # Relocate links to the new install prefix links = [link for link in buildinfo.get('relocate_links', [])] relocate.relocate_links(links, old_layout_root, old_prefix, new_prefix) # For all buildcaches # relocate the install prefixes in text files including dependencies relocate.relocate_text(text_names, old_layout_root, new_layout_root, old_prefix, new_prefix, old_spack_prefix, new_spack_prefix, prefix_to_prefix) paths_to_relocate = [old_prefix, old_layout_root] paths_to_relocate.extend(prefix_to_hash.keys()) files_to_relocate = list( filter( lambda pathname: not relocate.file_is_relocatable( pathname, paths_to_relocate=paths_to_relocate), map(lambda filename: os.path.join(workdir, filename), buildinfo['relocate_binaries']))) # relocate the install prefixes in binary files including dependencies relocate.relocate_text_bin(files_to_relocate, old_prefix, new_prefix, old_spack_prefix, new_spack_prefix, prefix_to_prefix) # If we are installing back to the same location # relocate the sbang location if the spack directory changed else: if old_spack_prefix != new_spack_prefix: relocate.relocate_text(text_names, old_layout_root, new_layout_root, old_prefix, new_prefix, old_spack_prefix, new_spack_prefix, prefix_to_prefix)