summaryrefslogtreecommitdiffstats
path: root/comm/python/mutlh/mutlh/site.py
blob: ab93e874e98eaf47c2a0406780d7c3003073da9e (plain)
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
#  This Source Code Form is subject to the terms of the Mozilla Public
#  License, v. 2.0. If a copy of the MPL was not distributed with this
#  file, You can obtain one at https://mozilla.org/MPL/2.0/.

import functools
import os
from typing import Callable, Optional

from mach.requirements import MachEnvRequirements, UnexpectedFlexibleRequirementException
from mach.site import (
    PIP_NETWORK_INSTALL_RESTRICTED_VIRTUALENVS,
    CommandSiteManager,
    MozSiteMetadata,
    SitePackagesSource,
    _mach_virtualenv_root,
)


class SiteNotFoundException(Exception):
    def __init__(self, site_name, manifest_paths):
        self.site_name = site_name
        self.manifest_paths = manifest_paths
        self.args = (site_name, manifest_paths)


@functools.lru_cache(maxsize=None)
def find_manifest(topsrcdir, site_name):
    manifest_paths = (
        os.path.join(topsrcdir, "comm", "python", "sites", f"{site_name}.txt"),
        os.path.join(topsrcdir, "python", "sites", f"{site_name}.txt"),
    )

    for check_path in manifest_paths:
        if os.path.exists(check_path):
            return check_path

    raise SiteNotFoundException(site_name, manifest_paths)


@functools.lru_cache(maxsize=None)
def resolve_requirements(topsrcdir, site_name):
    try:
        manifest_path = find_manifest(topsrcdir, site_name)
    except SiteNotFoundException as e:
        raise Exception(
            f'The current command is using the "{e.site_name}" '
            "site. However, that site is missing its associated "
            f"requirements definition file in one of the supported "
            f"paths: {e.manifest_paths}."
        )
    is_thunderbird = True
    try:
        return MachEnvRequirements.from_requirements_definition(
            topsrcdir,
            is_thunderbird,
            site_name not in PIP_NETWORK_INSTALL_RESTRICTED_VIRTUALENVS,
            manifest_path,
        )
    except UnexpectedFlexibleRequirementException as e:
        raise Exception(
            f'The "{site_name}" site does not have all pypi packages pinned '
            f'in the format "package==version" (found "{e.raw_requirement}").\n'
            f"Only the {PIP_NETWORK_INSTALL_RESTRICTED_VIRTUALENVS} sites are "
            "allowed to have unpinned packages."
        )


class MutlhCommandSiteManager(CommandSiteManager):
    @classmethod
    def from_environment(
        cls,
        topsrcdir: str,
        get_state_dir: Callable[[], Optional[str]],
        site_name: str,
        command_virtualenvs_dir: str,
    ):
        """
        Args:
            topsrcdir: The path to the Firefox repo
            get_state_dir: A function that resolves the path to the checkout-scoped
                state_dir, generally ~/.mozbuild/srcdirs/<checkout-based-dir>/
            site_name: The name of this site, such as "build"
            command_virtualenvs_dir: The location under which this site's virtualenv
            should be created
        """
        active_metadata = MozSiteMetadata.from_runtime()
        assert (
            active_metadata
        ), "A Mach-managed site must be active before doing work with command sites"

        mach_site_packages_source = active_metadata.mach_site_packages_source
        pip_restricted_site = site_name in PIP_NETWORK_INSTALL_RESTRICTED_VIRTUALENVS
        if not pip_restricted_site and mach_site_packages_source == SitePackagesSource.SYSTEM:
            # Sites that aren't pip-network-install-restricted are likely going to be
            # incompatible with the system. Besides, this use case shouldn't exist, since
            # using the system packages is supposed to only be needed to lower risk of
            # important processes like building Firefox.
            raise Exception(
                'Cannot use MACH_BUILD_PYTHON_NATIVE_PACKAGE_SOURCE="system" for any '
                f"sites other than {PIP_NETWORK_INSTALL_RESTRICTED_VIRTUALENVS}. The "
                f'current attempted site is "{site_name}".'
            )

        mach_virtualenv_root = (
            _mach_virtualenv_root(get_state_dir())
            if mach_site_packages_source == SitePackagesSource.VENV
            else None
        )
        populate_virtualenv = (
            mach_site_packages_source == SitePackagesSource.VENV or not pip_restricted_site
        )
        return cls(
            topsrcdir,
            mach_virtualenv_root,
            os.path.join(command_virtualenvs_dir, site_name),
            site_name,
            active_metadata,
            populate_virtualenv,
            resolve_requirements(topsrcdir, site_name),
        )