Skip to content

Base

๐Ÿค– AI-Generated Content

This documentation was generated with AI assistance and is still being audited. Some, or potentially a lot, of this information may be inaccurate. Learn more.

provide.foundation.tools.base

Base classes for tool management.

This module provides the foundation for tool managers, including the base manager class and metadata structures.

Classes

BaseToolManager

BaseToolManager(config: BaseConfig)

Bases: ABC

Abstract base class for tool managers.

Provides common functionality for downloading, verifying, and installing development tools. Subclasses must implement platform-specific logic.

Attributes:

Name Type Description
config

Configuration object.

tool_name str

Name of the tool being managed.

executable_name str

Name of the executable file.

supported_platforms list[str]

List of supported platforms.

Initialize the tool manager.

Parameters:

Name Type Description Default
config BaseConfig

Configuration object containing settings.

required
Source code in provide/foundation/tools/base.py
def __init__(self, config: BaseConfig) -> None:
    """Initialize the tool manager.

    Args:
        config: Configuration object containing settings.

    """
    if not self.tool_name:
        raise ToolError("Subclass must define tool_name")
    if not self.executable_name:
        raise ToolError("Subclass must define executable_name")

    self.config = config

    # Lazy-load components to avoid circular imports
    self._cache: ToolCache | None = None
    self._downloader: ToolDownloader | None = None
    self._verifier: ToolVerifier | None = None
    self._installer: ToolInstaller | None = None
    self._resolver: VersionResolver | None = None

    log.debug(f"Initialized {self.tool_name} manager")
Attributes
cache property
cache: ToolCache

Get or create cache instance.

downloader property
downloader: ToolDownloader

Get or create downloader instance.

installer property
installer: ToolInstaller

Get or create installer instance.

resolver property
resolver: VersionResolver

Get or create version resolver instance.

verifier property
verifier: ToolVerifier

Get or create verifier instance.

Functions
get_available_versions abstractmethod
get_available_versions() -> list[str]

Get list of available versions from upstream.

Returns:

Type Description
list[str]

List of version strings available for download.

Source code in provide/foundation/tools/base.py
@abstractmethod
def get_available_versions(self) -> list[str]:
    """Get list of available versions from upstream.

    Returns:
        List of version strings available for download.

    """
get_install_path
get_install_path(version: str) -> Path

Get the installation path for a version.

Parameters:

Name Type Description Default
version str

Version string.

required

Returns:

Type Description
Path

Path where the version is/will be installed.

Source code in provide/foundation/tools/base.py
def get_install_path(self, version: str) -> Path:
    """Get the installation path for a version.

    Args:
        version: Version string.

    Returns:
        Path where the version is/will be installed.

    """
    base_path = Path.home() / ".provide-foundation" / "tools" / self.tool_name / version
    return base_path
get_metadata abstractmethod
get_metadata(version: str) -> ToolMetadata

Get metadata for a specific version.

Parameters:

Name Type Description Default
version str

Version string to get metadata for.

required

Returns:

Type Description
ToolMetadata

ToolMetadata object with download URLs and checksums.

Source code in provide/foundation/tools/base.py
@abstractmethod
def get_metadata(self, version: str) -> ToolMetadata:
    """Get metadata for a specific version.

    Args:
        version: Version string to get metadata for.

    Returns:
        ToolMetadata object with download URLs and checksums.

    """
get_platform_info
get_platform_info() -> dict[str, str]

Get current platform information.

Returns:

Type Description
dict[str, str]

Dictionary with platform and arch keys.

Source code in provide/foundation/tools/base.py
def get_platform_info(self) -> dict[str, str]:
    """Get current platform information.

    Returns:
        Dictionary with platform and arch keys.

    """
    import platform

    system = platform.system().lower()
    if system == "darwin":
        system = "darwin"
    elif system == "linux":
        system = "linux"
    elif system == "windows":
        system = "windows"

    machine = platform.machine().lower()
    if machine in ["x86_64", "amd64"]:
        arch = "amd64"
    elif machine in ["aarch64", "arm64"]:
        arch = "arm64"
    else:
        arch = machine

    return {"platform": system, "arch": arch}
install async
install(
    version: str = "latest", force: bool = False
) -> Path

Install a specific version of the tool.

Parameters:

Name Type Description Default
version str

Version to install (default: "latest").

'latest'
force bool

Force reinstall even if cached.

False

Returns:

Type Description
Path

Path to the installed tool.

Raises:

Type Description
ToolInstallError

If installation fails.

Source code in provide/foundation/tools/base.py
async def install(self, version: str = "latest", force: bool = False) -> Path:
    """Install a specific version of the tool.

    Args:
        version: Version to install (default: "latest").
        force: Force reinstall even if cached.

    Returns:
        Path to the installed tool.

    Raises:
        ToolInstallError: If installation fails.

    """
    # Resolve version
    if version in ["latest", "stable", "dev"] or version.startswith(("~", "^")):
        version = self.resolve_version(version)

    # Check cache unless forced
    if not force and (cached_path := self.cache.get(self.tool_name, version)):
        log.info(f"Using cached {self.tool_name} {version}")
        return cached_path

    log.info(f"Installing {self.tool_name} {version}")

    # Get metadata
    metadata = self.get_metadata(version)
    if not metadata.download_url:
        raise ToolInstallError(f"No download URL for {self.tool_name} {version}")

    # Download to secure temporary directory
    from provide.foundation.file.temp import system_temp_dir

    download_path = system_temp_dir() / f"{self.tool_name}-{version}"
    artifact_path = await self.downloader.download_with_progress(
        metadata.download_url,
        download_path,
        metadata.checksum,
    )

    # Verify if checksum provided
    if metadata.checksum and not self.verifier.verify_checksum(artifact_path, metadata.checksum):
        artifact_path.unlink()
        raise ToolVerificationError(f"Checksum verification failed for {self.tool_name} {version}")

    # Install
    install_path = self.installer.install(artifact_path, metadata)

    # Cache the installation
    self.cache.store(self.tool_name, version, install_path)

    # Clean up download
    if artifact_path.exists():
        artifact_path.unlink()

    log.info(f"Successfully installed {self.tool_name} {version} to {install_path}")
    return install_path
is_installed
is_installed(version: str) -> bool

Check if a version is installed.

Parameters:

Name Type Description Default
version str

Version to check.

required

Returns:

Type Description
bool

True if installed, False otherwise.

Source code in provide/foundation/tools/base.py
def is_installed(self, version: str) -> bool:
    """Check if a version is installed.

    Args:
        version: Version to check.

    Returns:
        True if installed, False otherwise.

    """
    install_path = self.get_install_path(version)
    executable = install_path / "bin" / self.executable_name
    return executable.exists()
resolve_version
resolve_version(spec: str) -> str

Resolve a version specification to a concrete version.

Parameters:

Name Type Description Default
spec str

Version specification (e.g., "latest", "~1.5.0").

required

Returns:

Type Description
str

Concrete version string.

Raises:

Type Description
ToolNotFoundError

If version cannot be resolved.

Source code in provide/foundation/tools/base.py
def resolve_version(self, spec: str) -> str:
    """Resolve a version specification to a concrete version.

    Args:
        spec: Version specification (e.g., "latest", "~1.5.0").

    Returns:
        Concrete version string.

    Raises:
        ToolNotFoundError: If version cannot be resolved.

    """
    available = self.get_available_versions()
    if not available:
        raise ToolNotFoundError(f"No versions available for {self.tool_name}")

    resolved = self.resolver.resolve(spec, available)
    if not resolved:
        raise ToolNotFoundError(f"Cannot resolve version '{spec}' for {self.tool_name}")

    log.debug(f"Resolved {self.tool_name} version {spec} to {resolved}")
    return resolved
uninstall
uninstall(version: str) -> bool

Uninstall a specific version.

Parameters:

Name Type Description Default
version str

Version to uninstall.

required

Returns:

Type Description
bool

True if uninstalled, False if not found.

Source code in provide/foundation/tools/base.py
def uninstall(self, version: str) -> bool:
    """Uninstall a specific version.

    Args:
        version: Version to uninstall.

    Returns:
        True if uninstalled, False if not found.

    """
    # Invalidate cache
    self.cache.invalidate(self.tool_name, version)

    # Remove from filesystem
    install_path = self.get_install_path(version)
    if install_path.exists():
        import shutil

        shutil.rmtree(install_path)
        log.info(f"Uninstalled {self.tool_name} {version}")
        return True

    return False

ToolError

ToolError(
    message: str,
    *,
    code: str | None = None,
    context: dict[str, Any] | None = None,
    cause: Exception | None = None,
    **extra_context: Any,
)

Bases: FoundationError

Base exception for tool-related errors.

Source code in provide/foundation/errors/base.py
def __init__(
    self,
    message: str,
    *,
    code: str | None = None,
    context: dict[str, Any] | None = None,
    cause: Exception | None = None,
    **extra_context: Any,
) -> None:
    self.message = message
    self.code = code or self._default_code()
    self.context = context or {}
    self.context.update(extra_context)
    self.cause = cause
    if cause:
        self.__cause__ = cause
    super().__init__(message)

ToolInstallError

ToolInstallError(
    message: str,
    *,
    code: str | None = None,
    context: dict[str, Any] | None = None,
    cause: Exception | None = None,
    **extra_context: Any,
)

Bases: ToolError

Raised when tool installation fails.

Source code in provide/foundation/errors/base.py
def __init__(
    self,
    message: str,
    *,
    code: str | None = None,
    context: dict[str, Any] | None = None,
    cause: Exception | None = None,
    **extra_context: Any,
) -> None:
    self.message = message
    self.code = code or self._default_code()
    self.context = context or {}
    self.context.update(extra_context)
    self.cause = cause
    if cause:
        self.__cause__ = cause
    super().__init__(message)

ToolMetadata

Metadata about a tool version.

Attributes:

Name Type Description
name str

Tool name (e.g., "terraform").

version str

Version string (e.g., "1.5.0").

platform str

Platform identifier (e.g., "linux", "darwin").

arch str

Architecture (e.g., "amd64", "arm64").

checksum str | None

Optional checksum for verification.

signature str | None

Optional GPG/PGP signature.

download_url str | None

URL to download the tool.

checksum_url str | None

URL to download checksums file.

install_path Path | None

Where the tool is/will be installed.

env_vars dict[str, str]

Environment variables to set.

dependencies list[str]

Other tools this depends on.

executable_name str | None

Name of the executable file.

ToolNotFoundError

ToolNotFoundError(
    message: str,
    *,
    code: str | None = None,
    context: dict[str, Any] | None = None,
    cause: Exception | None = None,
    **extra_context: Any,
)

Bases: ToolError

Raised when a tool or version cannot be found.

Source code in provide/foundation/errors/base.py
def __init__(
    self,
    message: str,
    *,
    code: str | None = None,
    context: dict[str, Any] | None = None,
    cause: Exception | None = None,
    **extra_context: Any,
) -> None:
    self.message = message
    self.code = code or self._default_code()
    self.context = context or {}
    self.context.update(extra_context)
    self.cause = cause
    if cause:
        self.__cause__ = cause
    super().__init__(message)

ToolVerificationError

ToolVerificationError(
    message: str,
    *,
    code: str | None = None,
    context: dict[str, Any] | None = None,
    cause: Exception | None = None,
    **extra_context: Any,
)

Bases: ToolError

Raised when tool verification fails.

Source code in provide/foundation/errors/base.py
def __init__(
    self,
    message: str,
    *,
    code: str | None = None,
    context: dict[str, Any] | None = None,
    cause: Exception | None = None,
    **extra_context: Any,
) -> None:
    self.message = message
    self.code = code or self._default_code()
    self.context = context or {}
    self.context.update(extra_context)
    self.cause = cause
    if cause:
        self.__cause__ = cause
    super().__init__(message)

Functions