def download_tarball()

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


def download_tarball(spec, unsigned=False, mirrors_for_spec=None):
    """
    Download binary tarball for given package into stage area, returning
    path to downloaded tarball if successful, None otherwise.

    Args:
        spec (spack.spec.Spec): Concrete spec
        unsigned (bool): Whether or not to require signed binaries
        mirrors_for_spec (list): Optional list of concrete specs and mirrors
            obtained by calling binary_distribution.get_mirrors_for_spec().
            These will be checked in order first before looking in other
            configured mirrors.

    Returns:
        ``None`` if the tarball could not be downloaded (maybe also verified,
        depending on whether new-style signed binary packages were found).
        Otherwise, return an object indicating the path to the downloaded
        tarball, the path to the downloaded specfile (in the case of new-style
        buildcache), and whether or not the tarball is already verified.

    .. code-block:: JSON

       {
           "tarball_path": "path-to-locally-saved-tarfile",
           "specfile_path": "none-or-path-to-locally-saved-specfile",
           "signature_verified": "true-if-binary-pkg-was-already-verified"
       }
    """
    if not spack.mirror.MirrorCollection():
        tty.die("Please add a spack mirror to allow " +
                "download of pre-compiled packages.")

    tarball = tarball_path_name(spec, '.spack')
    specfile_prefix = tarball_name(spec, '.spec')

    mirrors_to_try = []

    # Note on try_first and try_next:
    # mirrors_for_spec mostly likely came from spack caching remote
    # mirror indices locally and adding their specs to a local data
    # structure supporting quick lookup of concrete specs.  Those
    # mirrors are likely a subset of all configured mirrors, and
    # we'll probably find what we need in one of them.  But we'll
    # look in all configured mirrors if needed, as maybe the spec
    # we need was in an un-indexed mirror.  No need to check any
    # mirror for the spec twice though.
    try_first = [i['mirror_url'] for i in mirrors_for_spec] if mirrors_for_spec else []
    try_next = [
        i.fetch_url for i in spack.mirror.MirrorCollection().values()
        if i.fetch_url not in try_first
    ]

    for url in try_first + try_next:
        mirrors_to_try.append({
            'specfile': url_util.join(url,
                                      _build_cache_relative_path, specfile_prefix),
            'spackfile': url_util.join(url,
                                       _build_cache_relative_path, tarball)
        })

    tried_to_verify_sigs = []

    # Assumes we care more about finding a spec file by preferred ext
    # than by mirrory priority.  This can be made less complicated as
    # we remove support for deprecated spec formats and buildcache layouts.
    for ext in ['json.sig', 'json', 'yaml']:
        for mirror_to_try in mirrors_to_try:
            specfile_url = '{0}.{1}'.format(mirror_to_try['specfile'], ext)
            spackfile_url = mirror_to_try['spackfile']
            local_specfile_stage = try_fetch(specfile_url)
            if local_specfile_stage:
                local_specfile_path = local_specfile_stage.save_filename
                signature_verified = False

                if ext.endswith('.sig') and not unsigned:
                    # If we found a signed specfile at the root, try to verify
                    # the signature immediately.  We will not download the
                    # tarball if we could not verify the signature.
                    tried_to_verify_sigs.append(specfile_url)
                    signature_verified = try_verify(local_specfile_path)
                    if not signature_verified:
                        tty.warn("Failed to verify: {0}".format(specfile_url))

                if unsigned or signature_verified or not ext.endswith('.sig'):
                    # We will download the tarball in one of three cases:
                    #     1. user asked for --no-check-signature
                    #     2. user didn't ask for --no-check-signature, but we
                    #     found a spec.json.sig and verified the signature already
                    #     3. neither of the first two cases are true, but this file
                    #     is *not* a signed json (not a spec.json.sig file).  That
                    #     means we already looked at all the mirrors and either didn't
                    #     find any .sig files or couldn't verify any of them.  But it
                    #     is still possible to find an old style binary package where
                    #     the signature is a detached .asc file in the outer archive
                    #     of the tarball, and in that case, the only way to know is to
                    #     download the tarball.  This is a deprecated use case, so if
                    #     something goes wrong during the extraction process (can't
                    #     verify signature, checksum doesn't match) we will fail at
                    #     that point instead of trying to download more tarballs from
                    #     the remaining mirrors, looking for one we can use.
                    tarball_stage = try_fetch(spackfile_url)
                    if tarball_stage:
                        return {
                            'tarball_stage': tarball_stage,
                            'specfile_stage': local_specfile_stage,
                            'signature_verified': signature_verified,
                        }

                local_specfile_stage.destroy()

    # Falling through the nested loops meeans we exhaustively searched
    # for all known kinds of spec files on all mirrors and did not find
    # an acceptable one for which we could download a tarball.

    if tried_to_verify_sigs:
        raise NoVerifyException(("Spack found new style signed binary packages, "
                                 "but was unable to verify any of them.  Please "
                                 "obtain and trust the correct public key.  If "
                                 "these are public spack binaries, please see the "
                                 "spack docs for locations where keys can be found."))

    tty.warn("download_tarball() was unable to download " +
             "{0} from any configured mirrors".format(spec))
    return None