blob: 7f715f11d629f5a9ee3615c46c5587d15a296310 [file]
# Copyright 2026 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Host interface for invoking Google Cloud SDK (gcloud) subcommands."""
import functools
import os
import pathlib
import shutil
import subprocess
import sys
try:
from build.auth import apt
except ImportError:
# Whether mypy considers this a redefinition depends on whether
# `build.auth` is resolvable in the context it's checked in.
import apt # type: ignore[no-redef, unused-ignore]
# Standard relative subpath for gcloud's Application Default Credentials (ADC).
ADC_SUBPATH = pathlib.Path(
".config/gcloud/application_default_credentials.json"
)
def get_default_adc_path() -> pathlib.Path:
"""Returns the default, standard absolute path of gcloud's ADC JSON file."""
try:
home_dir = pathlib.Path.home()
except (RuntimeError, KeyError):
# Fallback for homeless or user-less environments
home_dir = pathlib.Path("/tmp")
return home_dir / ADC_SUBPATH
def resolve_global_adc_path() -> pathlib.Path:
"""Resolves and returns the active absolute path of global ADC.
Prioritizes GOOGLE_APPLICATION_CREDENTIALS if defined in the environment,
falling back to the standard gcloud ADC path.
"""
env_path = os.environ.get("GOOGLE_APPLICATION_CREDENTIALS")
if env_path:
return pathlib.Path(env_path)
return get_default_adc_path()
@functools.cache
def path() -> pathlib.Path | None:
"""Detects and returns the absolute canonical path of the gcloud binary if installed."""
path_val = shutil.which("gcloud")
if path_val:
return pathlib.Path(path_val)
# Fallback to standard system package installation location if PATH has not been updated yet.
return apt.get_binary_path("google-cloud-cli", "gcloud")
def login() -> None:
"""Launches the standard gcloud Application Default Credentials (ADC) login workflow.
Raises:
RuntimeError: If gcloud is not installed or the login command fails.
"""
gcloud_path = path()
if not gcloud_path:
raise RuntimeError("Google Cloud SDK ('gcloud') is not installed.")
try:
# Standard streams are forwarded to let the browser or code-based login flows
# run perfectly in the active terminal/TTY.
subprocess.run(
[str(gcloud_path), "auth", "application-default", "login"],
stdin=sys.stdin,
stdout=sys.stdout,
stderr=sys.stderr,
check=True,
)
except subprocess.CalledProcessError as e:
raise RuntimeError(f"Interactive gcloud login failed: {e}")