def extract_tarball()

in lib/ramble/spack/binary_distribution.py [0:0]


def extract_tarball(spec, download_result, allow_root=False, unsigned=False,
                    force=False):
    """
    extract binary tarball for given package into install area
    """
    if os.path.exists(spec.prefix):
        if force:
            shutil.rmtree(spec.prefix)
        else:
            raise NoOverwriteException(str(spec.prefix))

    specfile_path = download_result['specfile_stage'].save_filename

    with open(specfile_path, 'r') as inputfile:
        content = inputfile.read()
        if specfile_path.endswith('.json.sig'):
            spec_dict = Spec.extract_json_from_clearsig(content)
        elif specfile_path.endswith('.json'):
            spec_dict = sjson.load(content)
        else:
            spec_dict = syaml.load(content)

    bchecksum = spec_dict['binary_cache_checksum']
    filename = download_result['tarball_stage'].save_filename
    signature_verified = download_result['signature_verified']
    tmpdir = None

    if ('buildcache_layout_version' not in spec_dict or
            int(spec_dict['buildcache_layout_version']) < 1):
        # Handle the older buildcache layout where the .spack file
        # contains a spec json/yaml, maybe an .asc file (signature),
        # and another tarball containing the actual install tree.
        tmpdir = tempfile.mkdtemp()
        try:
            tarfile_path = _extract_inner_tarball(
                spec, filename, tmpdir, unsigned, bchecksum)
        except Exception as e:
            _delete_staged_downloads(download_result)
            shutil.rmtree(tmpdir)
            raise e
    else:
        # Newer buildcache layout: the .spack file contains just
        # in the install tree, the signature, if it exists, is
        # wrapped around the spec.json at the root.  If sig verify
        # was required, it was already done before downloading
        # the tarball.
        tarfile_path = filename

        if not unsigned and not signature_verified:
            raise UnsignedPackageException(
                "To install unsigned packages, use the --no-check-signature option.")

        # compute the sha256 checksum of the tarball
        local_checksum = checksum_tarball(tarfile_path)

        # if the checksums don't match don't install
        if local_checksum != bchecksum['hash']:
            _delete_staged_downloads(download_result)
            raise NoChecksumException(
                "Package tarball failed checksum verification.\n"
                "It cannot be installed.")

    new_relative_prefix = str(os.path.relpath(spec.prefix,
                                              spack.store.layout.root))
    # if the original relative prefix is in the spec file use it
    buildinfo = spec_dict.get('buildinfo', {})
    old_relative_prefix = buildinfo.get('relative_prefix', new_relative_prefix)
    rel = buildinfo.get('relative_rpaths')
    info = 'old relative prefix %s\nnew relative prefix %s\nrelative rpaths %s'
    tty.debug(info %
              (old_relative_prefix, new_relative_prefix, rel))

    # Extract the tarball into the store root, presumably on the same filesystem.
    # The directory created is the base directory name of the old prefix.
    # Moving the old prefix name to the new prefix location should preserve
    # hard links and symbolic links.
    extract_tmp = os.path.join(spack.store.layout.root, '.tmp')
    mkdirp(extract_tmp)
    extracted_dir = os.path.join(extract_tmp,
                                 old_relative_prefix.split(os.path.sep)[-1])

    with closing(tarfile.open(tarfile_path, 'r')) as tar:
        try:
            tar.extractall(path=extract_tmp)
        except Exception as e:
            _delete_staged_downloads(download_result)
            shutil.rmtree(extracted_dir)
            raise e
    try:
        shutil.move(extracted_dir, spec.prefix)
    except Exception as e:
        _delete_staged_downloads(download_result)
        shutil.rmtree(extracted_dir)
        raise e
    os.remove(tarfile_path)
    os.remove(specfile_path)

    try:
        relocate_package(spec, allow_root)
    except Exception as e:
        shutil.rmtree(spec.prefix)
        raise e
    else:
        manifest_file = os.path.join(spec.prefix,
                                     spack.store.layout.metadata_dir,
                                     spack.store.layout.manifest_file_name)
        if not os.path.exists(manifest_file):
            spec_id = spec.format('{name}/{hash:7}')
            tty.warn('No manifest file in tarball for spec %s' % spec_id)
    finally:
        if tmpdir:
            shutil.rmtree(tmpdir)
        if os.path.exists(filename):
            os.remove(filename)
        _delete_staged_downloads(download_result)