summaryrefslogtreecommitdiff
path: root/lib/spack/spack/container/images.py
blob: 476fbab1db3614a78d2efd1ae5046b121bd2d9f6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# Copyright 2013-2023 Lawrence Livermore National Security, LLC and other
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
"""Manages the details on the images used in the various stages."""
import json
import os.path
import shlex
import sys

import llnl.util.filesystem as fs
import llnl.util.tty as tty

import spack.util.git

#: Global variable used to cache in memory the content of images.json
_data = None


def data():
    """Returns a dictionary with the static data on the images.

    The dictionary is read from a JSON file lazily the first time
    this function is called.
    """
    global _data
    if not _data:
        json_dir = os.path.abspath(os.path.dirname(__file__))
        json_file = os.path.join(json_dir, "images.json")
        with open(json_file) as f:
            _data = json.load(f)
    return _data


def build_info(image, spack_version):
    """Returns the name of the build image and its tag.

    Args:
        image (str): image to be used at run-time. Should be of the form
            <image_name>:<image_tag> e.g. "ubuntu:18.04"
        spack_version (str): version of Spack that we want to use to build

    Returns:
        A tuple with (image_name, image_tag) for the build image
    """
    # Don't handle error here, as a wrong image should have been
    # caught by the JSON schema
    image_data = data()["images"][image]
    build_image = image_data.get("build", None)
    if not build_image:
        return None, None

    # Translate version from git to docker if necessary
    build_tag = image_data["build_tags"].get(spack_version, spack_version)

    return build_image, build_tag


def os_package_manager_for(image):
    """Returns the name of the OS package manager for the image
    passed as argument.

    Args:
        image (str): image to be used at run-time. Should be of the form
            <image_name>:<image_tag> e.g. "ubuntu:18.04"

    Returns:
        Name of the package manager, e.g. "apt" or "yum"
    """
    name = data()["images"][image]["os_package_manager"]
    return name


def all_bootstrap_os():
    """Return a list of all the OS that can be used to bootstrap Spack"""
    return list(data()["images"])


def commands_for(package_manager):
    """Returns the commands used to update system repositories, install
    system packages and clean afterwards.

    Args:
        package_manager (str): package manager to be used

    Returns:
        A tuple of (update, install, clean) commands.
    """
    info = data()["os_package_managers"][package_manager]
    return info["update"], info["install"], info["clean"]


def bootstrap_template_for(image):
    return data()["images"][image]["bootstrap"]["template"]


def _verify_ref(url, ref, enforce_sha):
    # Do a checkout in a temporary directory
    msg = 'Cloning "{0}" to verify ref "{1}"'.format(url, ref)
    tty.info(msg, stream=sys.stderr)
    git = spack.util.git.git(required=True)
    with fs.temporary_dir():
        git("clone", "-q", url, ".")
        sha = git(
            "rev-parse", "-q", ref + "^{commit}", output=str, error=os.devnull, fail_on_error=False
        )
        if git.returncode:
            msg = '"{0}" is not a valid reference for "{1}"'
            raise RuntimeError(msg.format(sha, url))

        if enforce_sha:
            ref = sha.strip()

        return ref


def checkout_command(url, ref, enforce_sha, verify):
    """Return the checkout command to be used in the bootstrap phase.

    Args:
        url (str): url of the Spack repository
        ref (str): either a branch name, a tag or a commit sha
        enforce_sha (bool): if true turns every
        verify (bool):
    """
    url = url or "https://github.com/spack/spack.git"
    ref = ref or "develop"
    enforce_sha, verify = bool(enforce_sha), bool(verify)
    # If we want to enforce a sha or verify the ref we need
    # to checkout the repository locally
    if enforce_sha or verify:
        ref = _verify_ref(url, ref, enforce_sha)

    return " && ".join(
        [
            "git init --quiet",
            f"git remote add origin {shlex.quote(url)}",
            f"git fetch --depth=1 origin {shlex.quote(ref)}",
            "git checkout --detach FETCH_HEAD",
        ]
    )