File size: 3,460 Bytes
a22c748
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""Subprocess execution and MFA executable discovery."""

from __future__ import annotations

import logging
import os
import shutil
import subprocess
import sys
from pathlib import Path
from typing import List, Optional, Sequence

log = logging.getLogger(__name__)

def run_python(cmd: Sequence[str], *, cwd: Optional[Path] = None) -> None:
    """Run a stage with this environment's interpreter."""
    cmd = list(cmd)
    if cmd and cmd[0] in {"python", Path(sys.executable).name}:
        cmd[0] = sys.executable
    log.info("Running: %s", " ".join(cmd))
    subprocess.run(cmd, cwd=str(cwd) if cwd else None, check=True)



def active_conda_env_name() -> Optional[str]:
    """Return the active conda env name, or None if not in a conda env."""
    name = (os.environ.get("CONDA_DEFAULT_ENV") or "").strip()
    if name:
        return name
    prefix = (os.environ.get("CONDA_PREFIX") or "").strip()
    if prefix:
        return Path(prefix).name
    return None


def is_phonepaint_mfa_env() -> bool:
    """True when the active interpreter is the legacy in-env MFA+MAPS stack."""
    return active_conda_env_name() == "PhonePaintMFA"


def resolve_mfa_bin(env_mfa: str) -> str:
    """Absolute path to the MFA CLI (subprocess; not imported in-process).

    Prefers MFA in the active conda env. The shipped ``PhonePaint`` env has no
    in-env MFA, so it falls back to ``env_mfa`` (default ``mfa_env``), the
    sidecar built by ``./create_mfa_envs.sh``. Legacy ``PhonePaintMFA`` keeps
    MFA in-env and never hops to the sidecar.
    """
    explicit = os.environ.get("MFA_BIN")
    if explicit:
        path = Path(explicit).expanduser()
        if path.is_file():
            return str(path)
        raise SystemExit(f"MFA_BIN is set but not a file: {explicit}")

    candidates: List[Path] = []
    conda_prefix = os.environ.get("CONDA_PREFIX")
    if conda_prefix:
        candidates.append(Path(conda_prefix) / "bin" / "mfa")
        which = shutil.which("mfa")
        if which:
            which_path = Path(which).resolve()
            prefix_path = Path(conda_prefix).resolve()
            try:
                which_path.relative_to(prefix_path)
                candidates.append(which_path)
            except ValueError:
                pass

    allow_sidecar = not is_phonepaint_mfa_env()
    if allow_sidecar:
        if conda_prefix:
            candidates.append(Path(conda_prefix).parent / env_mfa / "bin" / "mfa")
        home = Path.home()
        for base in (home / "miniconda3", home / "anaconda3", home / "mambaforge", home / "miniforge3"):
            candidates.append(base / "envs" / env_mfa / "bin" / "mfa")
        which = shutil.which("mfa")
        if which:
            candidates.append(Path(which))
    seen: set[str] = set()
    for cand in candidates:
        key = str(cand)
        if key in seen:
            continue
        seen.add(key)
        if cand.is_file():
            return str(cand)
    if is_phonepaint_mfa_env():
        env = active_conda_env_name() or "PhonePaint"
        raise SystemExit(
            f"{env} is active but MFA CLI was not found in this env "
            f"($CONDA_PREFIX/bin/mfa). Install MFA in-env or set MFA_BIN; "
            f"the mfa_env sidecar is not used while {env} is active."
        )
    raise SystemExit(
        f"MFA CLI not found in the active env or fallback {env_mfa!r}. "
        "Install MFA in-env, run ./create_mfa_envs.sh, or set MFA_BIN."
    )