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 relocate_package(workdir, spec, allow_root): """ Relocate the given package """ buildinfo = read_buildinfo_file(workdir) new_path = spack.store.layout.root new_prefix = spack.paths.prefix old_path = buildinfo['buildpath'] old_prefix = 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 not rel: 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 rewire_node(spec, explicit): """This function rewires a single node, worrying only about references to its subgraph. Binaries, text, and links are all changed in accordance with the splice. The resulting package is then 'installed.'""" tempdir = tempfile.mkdtemp() # copy anything installed to a temporary directory shutil.copytree(spec.build_spec.prefix, os.path.join(tempdir, spec.dag_hash())) spack.hooks.pre_install(spec) # compute prefix-to-prefix for every node from the build spec to the spliced # spec prefix_to_prefix = OrderedDict({spec.build_spec.prefix: spec.prefix}) for build_dep in spec.build_spec.traverse(root=False): prefix_to_prefix[build_dep.prefix] = spec[build_dep.name].prefix manifest = bindist.get_buildfile_manifest(spec.build_spec) platform = spack.platforms.by_name(spec.platform) text_to_relocate = [ os.path.join(tempdir, spec.dag_hash(), rel_path) for rel_path in manifest.get('text_to_relocate', []) ] if text_to_relocate: relocate.relocate_text(files=text_to_relocate, prefixes=prefix_to_prefix) bins_to_relocate = [ os.path.join(tempdir, spec.dag_hash(), rel_path) for rel_path in manifest.get('binary_to_relocate', []) ] if bins_to_relocate: if 'macho' in platform.binary_formats: relocate.relocate_macho_binaries(bins_to_relocate, str(spack.store.layout.root), str(spack.store.layout.root), prefix_to_prefix, False, spec.build_spec.prefix, spec.prefix) if 'elf' in platform.binary_formats: relocate.relocate_elf_binaries(bins_to_relocate, str(spack.store.layout.root), str(spack.store.layout.root), prefix_to_prefix, False, spec.build_spec.prefix, spec.prefix) relocate.relocate_text_bin(binaries=bins_to_relocate, prefixes=prefix_to_prefix) # Copy package into place, except for spec.json (because spec.json # describes the old spec and not the new spliced spec). shutil.copytree(os.path.join(tempdir, spec.dag_hash()), spec.prefix, ignore=shutil.ignore_patterns('spec.json', 'install_manifest.json')) if manifest.get('link_to_relocate'): _relocate_spliced_links(manifest.get('link_to_relocate'), spec.build_spec.prefix, spec.prefix) shutil.rmtree(tempdir) # Above, we did not copy spec.json: instead, here we write the new # (spliced) spec into spec.json, without this, Database.add would fail on # the next line (because it checks the spec.json in the prefix against the # spec being added to look for mismatches) spack.store.layout.write_spec(spec, spack.store.layout.spec_file_path(spec)) # add to database, not sure about explicit spack.store.db.add(spec, spack.store.layout, explicit=explicit) # run post install hooks spack.hooks.post_install(spec)
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)