Merging upstream version 0.12.0.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
f45bc3d463
commit
8d2f70e3c7
77 changed files with 23610 additions and 2331 deletions
8
eos_downloader/cli/__main__.py
Normal file
8
eos_downloader/cli/__main__.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
"""ARDL Module CLI."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from .cli import cli
|
||||
|
||||
if __name__ == "__main__":
|
||||
cli()
|
|
@ -14,8 +14,8 @@ import click
|
|||
|
||||
from eos_downloader import __version__
|
||||
from eos_downloader.cli.debug import commands as debug_commands
|
||||
from eos_downloader.cli.get import commands as get_commands
|
||||
from eos_downloader.cli.info import commands as info_commands
|
||||
from eos_downloader.cli.get import commands as get_commands
|
||||
|
||||
from eos_downloader.cli.utils import AliasedGroup
|
||||
|
||||
|
@ -29,10 +29,29 @@ from eos_downloader.cli.utils import AliasedGroup
|
|||
default=None,
|
||||
help="Arista Token from your customer account",
|
||||
)
|
||||
def ardl(ctx: click.Context, token: str) -> None:
|
||||
@click.option(
|
||||
"--log-level",
|
||||
"--log",
|
||||
help="Logging level of the command",
|
||||
default="error",
|
||||
type=click.Choice(
|
||||
["debug", "info", "warning", "error", "critical"], case_sensitive=False
|
||||
),
|
||||
)
|
||||
# Boolean triggers
|
||||
@click.option(
|
||||
"--debug-enabled",
|
||||
"--debug",
|
||||
is_flag=True,
|
||||
help="Activate debug mode for ardl cli",
|
||||
default=False,
|
||||
)
|
||||
def ardl(ctx: click.Context, token: str, log_level: str, debug_enabled: bool) -> None:
|
||||
"""Arista Network Download CLI"""
|
||||
ctx.ensure_object(dict)
|
||||
ctx.obj["token"] = token
|
||||
ctx.obj["log_level"] = log_level
|
||||
ctx.obj["debug"] = debug_enabled
|
||||
|
||||
|
||||
@ardl.group(cls=AliasedGroup, no_args_is_help=True)
|
||||
|
@ -61,11 +80,19 @@ def debug(ctx: click.Context, cls: click.Group = AliasedGroup) -> None:
|
|||
|
||||
def cli() -> None:
|
||||
"""Load ANTA CLI"""
|
||||
# Load group commands
|
||||
# Load group commands for get
|
||||
get.add_command(get_commands.eos)
|
||||
get.add_command(get_commands.cvp)
|
||||
info.add_command(info_commands.eos_versions)
|
||||
get.add_command(get_commands.path)
|
||||
|
||||
# Debug
|
||||
debug.add_command(debug_commands.xml)
|
||||
|
||||
# Get info commands
|
||||
info.add_command(info_commands.versions)
|
||||
info.add_command(info_commands.latest)
|
||||
info.add_command(info_commands.mapping)
|
||||
|
||||
# Load CLI
|
||||
ardl(obj={}, auto_envvar_prefix="arista")
|
||||
|
||||
|
|
|
@ -10,14 +10,17 @@
|
|||
Commands for ARDL CLI to get data.
|
||||
"""
|
||||
|
||||
# Standard library imports
|
||||
import xml.etree.ElementTree as ET
|
||||
from xml.dom import minidom
|
||||
|
||||
# Third party imports
|
||||
import click
|
||||
from loguru import logger
|
||||
from rich.console import Console
|
||||
|
||||
import eos_downloader.eos
|
||||
# Local imports
|
||||
import eos_downloader.defaults
|
||||
import eos_downloader.logics.arista_server
|
||||
from eos_downloader.cli.utils import cli_logging
|
||||
|
||||
|
||||
@click.command()
|
||||
|
@ -33,34 +36,46 @@ import eos_downloader.eos
|
|||
"--log-level",
|
||||
"--log",
|
||||
help="Logging level of the command",
|
||||
default=None,
|
||||
default="INFO",
|
||||
type=click.Choice(
|
||||
["debug", "info", "warning", "error", "critical"], case_sensitive=False
|
||||
),
|
||||
)
|
||||
def xml(ctx: click.Context, output: str, log_level: str) -> None:
|
||||
# sourcery skip: remove-unnecessary-cast
|
||||
"""Extract XML directory structure"""
|
||||
console = Console()
|
||||
# Get from Context
|
||||
"""Downloads and saves XML data from Arista EOS server.
|
||||
|
||||
This function authenticates with an Arista server, retrieves XML data,
|
||||
and saves it to a file in a prettified format.
|
||||
|
||||
Args:
|
||||
ctx (click.Context): Click context object containing authentication token
|
||||
output (str): File path where the XML output should be saved
|
||||
log_level (str): Logging level to use for output messages
|
||||
|
||||
Raises:
|
||||
Exception: If authentication with the server fails
|
||||
|
||||
Example:
|
||||
>>> xml(ctx, "output.xml", "INFO")
|
||||
INFO: connected to server aaa.bbb.ccc
|
||||
INFO: XML file saved under output.xml
|
||||
"""
|
||||
|
||||
log = cli_logging(log_level)
|
||||
token = ctx.obj["token"]
|
||||
|
||||
logger.remove()
|
||||
if log_level is not None:
|
||||
logger.add("eos-downloader.log", rotation="10 MB", level=log_level.upper())
|
||||
|
||||
my_download = eos_downloader.eos.EOSDownloader(
|
||||
image="unset",
|
||||
software="EOS",
|
||||
version="unset",
|
||||
token=token,
|
||||
hash_method="sha512sum",
|
||||
server = eos_downloader.logics.arista_server.AristaServer(
|
||||
token=token, session_server=eos_downloader.defaults.DEFAULT_SERVER_SESSION
|
||||
)
|
||||
|
||||
my_download.authenticate()
|
||||
xml_object: ET.ElementTree = (
|
||||
my_download.get_folder_tree()
|
||||
) # pylint: disable=protected-access
|
||||
try:
|
||||
server.authenticate()
|
||||
except Exception as error: # pylint: disable=W0703
|
||||
log.error(f"Cant connect to server: {error}")
|
||||
log.info(f"connected to server {eos_downloader.defaults.DEFAULT_SERVER_SESSION}")
|
||||
xml_data = server.get_xml_data()
|
||||
if xml_data is None:
|
||||
log.error("No XML data received")
|
||||
return
|
||||
xml_object: ET.ElementTree = xml_data # pylint: disable=protected-access
|
||||
xml_content = xml_object.getroot()
|
||||
|
||||
xmlstr = minidom.parseString(ET.tostring(xml_content)).toprettyxml(
|
||||
|
@ -68,5 +83,4 @@ def xml(ctx: click.Context, output: str, log_level: str) -> None:
|
|||
)
|
||||
with open(output, "w", encoding="utf-8") as f:
|
||||
f.write(str(xmlstr))
|
||||
|
||||
console.print(f"XML file saved in: { output }")
|
||||
log.info(f"XML file saved under {output}")
|
||||
|
|
|
@ -2,252 +2,385 @@
|
|||
# coding: utf-8 -*-
|
||||
# pylint: disable=no-value-for-parameter
|
||||
# pylint: disable=too-many-arguments
|
||||
# pylint: disable=too-many-positional-arguments
|
||||
# pylint: disable=line-too-long
|
||||
# pylint: disable=redefined-builtin
|
||||
# pylint: disable=broad-exception-caught
|
||||
# flake8: noqa E501
|
||||
|
||||
"""
|
||||
Commands for ARDL CLI to get data.
|
||||
"""
|
||||
"""CLI commands for listing Arista package information."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from typing import Union
|
||||
|
||||
import click
|
||||
from loguru import logger
|
||||
from rich.console import Console
|
||||
from eos_downloader.models.data import RTYPE_FEATURE
|
||||
from eos_downloader.logics.download import SoftManager
|
||||
from eos_downloader.logics.arista_server import AristaServer
|
||||
from eos_downloader.logics.arista_xml_server import (
|
||||
EosXmlObject,
|
||||
AristaXmlQuerier,
|
||||
CvpXmlObject,
|
||||
)
|
||||
|
||||
import eos_downloader.eos
|
||||
from eos_downloader.models.version import BASE_VERSION_STR, RTYPE_FEATURE, RTYPES
|
||||
|
||||
EOS_IMAGE_TYPE = [
|
||||
"64",
|
||||
"INT",
|
||||
"2GB-INT",
|
||||
"cEOS",
|
||||
"cEOS64",
|
||||
"vEOS",
|
||||
"vEOS-lab",
|
||||
"EOS-2GB",
|
||||
"default",
|
||||
]
|
||||
CVP_IMAGE_TYPE = ["ova", "rpm", "kvm", "upgrade"]
|
||||
from .utils import initialize, search_version, download_files, handle_docker_import
|
||||
|
||||
|
||||
@click.command(no_args_is_help=True)
|
||||
@click.pass_context
|
||||
@click.option(
|
||||
"--image-type",
|
||||
default="default",
|
||||
help="EOS Image type",
|
||||
type=click.Choice(EOS_IMAGE_TYPE),
|
||||
required=True,
|
||||
)
|
||||
@click.option("--version", default=None, help="EOS version", type=str, required=False)
|
||||
@click.option(
|
||||
"--latest",
|
||||
"-l",
|
||||
is_flag=True,
|
||||
type=click.BOOL,
|
||||
default=False,
|
||||
help="Get latest version in given branch. If --branch is not use, get the latest branch with specific release type",
|
||||
)
|
||||
@click.option(
|
||||
"--release-type",
|
||||
"-rtype",
|
||||
type=click.Choice(RTYPES, case_sensitive=False),
|
||||
default=RTYPE_FEATURE,
|
||||
help="EOS release type to search",
|
||||
)
|
||||
@click.option(
|
||||
"--branch",
|
||||
"-b",
|
||||
type=click.STRING,
|
||||
default=None,
|
||||
help="EOS Branch to list releases",
|
||||
)
|
||||
@click.option(
|
||||
"--docker-name",
|
||||
default="arista/ceos",
|
||||
help="Docker image name (default: arista/ceos)",
|
||||
type=str,
|
||||
show_default=True,
|
||||
)
|
||||
@click.command()
|
||||
@click.option("--format", default="vmdk", help="Image format", show_default=True)
|
||||
@click.option(
|
||||
"--output",
|
||||
default=str(os.path.relpath(os.getcwd(), start=os.curdir)),
|
||||
help="Path to save image",
|
||||
type=click.Path(),
|
||||
show_default=True,
|
||||
show_envvar=True,
|
||||
)
|
||||
# Debugging
|
||||
@click.option(
|
||||
"--log-level",
|
||||
"--log",
|
||||
help="Logging level of the command",
|
||||
default=None,
|
||||
type=click.Choice(
|
||||
["debug", "info", "warning", "error", "critical"], case_sensitive=False
|
||||
),
|
||||
"--latest",
|
||||
is_flag=True,
|
||||
help="Get latest version. If --branch is not use, get the latest branch with specific release type",
|
||||
default=False,
|
||||
show_envvar=True,
|
||||
)
|
||||
# Boolean triggers
|
||||
@click.option(
|
||||
"--eve-ng",
|
||||
is_flag=True,
|
||||
help="Run EVE-NG vEOS provisioning (only if CLI runs on an EVE-NG server)",
|
||||
default=False,
|
||||
)
|
||||
@click.option(
|
||||
"--disable-ztp",
|
||||
is_flag=True,
|
||||
help="Disable ZTP process in vEOS image (only available with --eve-ng)",
|
||||
default=False,
|
||||
show_envvar=True,
|
||||
)
|
||||
@click.option(
|
||||
"--import-docker",
|
||||
is_flag=True,
|
||||
help="Import docker image (only available with --image_type cEOSlab)",
|
||||
help="Import docker image to local docker",
|
||||
default=False,
|
||||
show_envvar=True,
|
||||
)
|
||||
@click.option(
|
||||
"--skip-download",
|
||||
is_flag=True,
|
||||
help="Skip download process - for debug only",
|
||||
default=False,
|
||||
)
|
||||
@click.option(
|
||||
"--docker-name",
|
||||
default="arista/ceos",
|
||||
help="Docker image name",
|
||||
show_default=True,
|
||||
show_envvar=True,
|
||||
)
|
||||
@click.option(
|
||||
"--docker-tag",
|
||||
default=None,
|
||||
help="Docker image tag",
|
||||
show_default=True,
|
||||
show_envvar=True,
|
||||
)
|
||||
@click.option(
|
||||
"--version",
|
||||
default=None,
|
||||
help="EOS version to download",
|
||||
show_default=True,
|
||||
show_envvar=True,
|
||||
)
|
||||
@click.option(
|
||||
"--release-type",
|
||||
default=RTYPE_FEATURE,
|
||||
help="Release type (M for Maintenance, F for Feature)",
|
||||
show_default=True,
|
||||
show_envvar=True,
|
||||
)
|
||||
@click.option(
|
||||
"--branch",
|
||||
default=None,
|
||||
help="Branch to download",
|
||||
show_default=True,
|
||||
show_envvar=True,
|
||||
)
|
||||
@click.option(
|
||||
"--dry-run",
|
||||
is_flag=True,
|
||||
help="Enable dry-run mode: only run code without system changes",
|
||||
default=False,
|
||||
)
|
||||
@click.pass_context
|
||||
def eos(
|
||||
ctx: click.Context,
|
||||
image_type: str,
|
||||
format: str,
|
||||
output: str,
|
||||
log_level: str,
|
||||
eve_ng: bool,
|
||||
disable_ztp: bool,
|
||||
import_docker: bool,
|
||||
skip_download: bool,
|
||||
docker_name: str,
|
||||
version: Union[str, None] = None,
|
||||
release_type: str = RTYPE_FEATURE,
|
||||
latest: bool = False,
|
||||
branch: Union[str, None] = None,
|
||||
docker_tag: str,
|
||||
version: Union[str, None],
|
||||
release_type: str,
|
||||
latest: bool,
|
||||
branch: Union[str, None],
|
||||
dry_run: bool,
|
||||
) -> int:
|
||||
# pylint: disable=R0917
|
||||
"""Download EOS image from Arista website"""
|
||||
console = Console()
|
||||
# Get from Context
|
||||
token = ctx.obj["token"]
|
||||
is_latest: bool = False
|
||||
if token is None or token == "":
|
||||
console.print(
|
||||
"❗ Token is unset ! Please configure ARISTA_TOKEN or use --token option",
|
||||
style="bold red",
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
logger.remove()
|
||||
if log_level is not None:
|
||||
logger.add("eos-downloader.log", rotation="10 MB", level=log_level.upper())
|
||||
|
||||
console.print(
|
||||
"🪐 [bold blue]eos-downloader[/bold blue] is starting...",
|
||||
"""Download EOS image from Arista server."""
|
||||
# pylint: disable=unused-variable
|
||||
console, token, debug, log_level = initialize(ctx)
|
||||
version = search_version(
|
||||
console, token, version, latest, branch, format, release_type
|
||||
)
|
||||
console.print(f" - Image Type: {image_type}")
|
||||
console.print(f" - Version: {version}")
|
||||
|
||||
if version is not None:
|
||||
my_download = eos_downloader.eos.EOSDownloader(
|
||||
image=image_type,
|
||||
software="EOS",
|
||||
version=version,
|
||||
token=token,
|
||||
hash_method="sha512sum",
|
||||
if version is None:
|
||||
raise ValueError("Version is not set correctly")
|
||||
try:
|
||||
eos_dl_obj = EosXmlObject(
|
||||
searched_version=version, token=token, image_type=format
|
||||
)
|
||||
my_download.authenticate()
|
||||
except Exception:
|
||||
console.print_exception(show_locals=True)
|
||||
return 1
|
||||
|
||||
elif latest:
|
||||
is_latest = True
|
||||
my_download = eos_downloader.eos.EOSDownloader(
|
||||
image=image_type,
|
||||
software="EOS",
|
||||
version="unset",
|
||||
token=token,
|
||||
hash_method="sha512sum",
|
||||
)
|
||||
my_download.authenticate()
|
||||
if branch is None:
|
||||
branch = str(my_download.latest_branch(rtype=release_type).branch)
|
||||
latest_version = my_download.latest_eos(branch, rtype=release_type)
|
||||
if str(latest_version) == BASE_VERSION_STR:
|
||||
console.print(
|
||||
f"[red]Error[/red], cannot find any version in {branch} for {release_type} release type"
|
||||
cli = SoftManager(dry_run=dry_run)
|
||||
|
||||
if not skip_download:
|
||||
if not eve_ng:
|
||||
download_files(
|
||||
console, cli, eos_dl_obj, output, rich_interface=True, debug=debug
|
||||
)
|
||||
sys.exit(1)
|
||||
my_download.version = str(latest_version)
|
||||
|
||||
if eve_ng:
|
||||
my_download.provision_eve(noztp=disable_ztp, checksum=True)
|
||||
else:
|
||||
my_download.download_local(file_path=output, checksum=True)
|
||||
else:
|
||||
try:
|
||||
cli.provision_eve(eos_dl_obj, noztp=True)
|
||||
except Exception as e:
|
||||
if debug:
|
||||
console.print_exception(show_locals=True)
|
||||
else:
|
||||
console.print(f"\n[red]Exception raised: {e}[/red]")
|
||||
return 1
|
||||
|
||||
if import_docker:
|
||||
my_download.docker_import(image_name=docker_name, is_latest=is_latest)
|
||||
console.print("✅ processing done !")
|
||||
sys.exit(0)
|
||||
return handle_docker_import(
|
||||
console, cli, eos_dl_obj, output, docker_name, docker_tag, debug
|
||||
)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
@click.command(no_args_is_help=True)
|
||||
@click.pass_context
|
||||
@click.command()
|
||||
@click.option(
|
||||
"--format",
|
||||
default="upgrade",
|
||||
help="CVP Image type",
|
||||
type=click.Choice(CVP_IMAGE_TYPE),
|
||||
required=True,
|
||||
default="ova",
|
||||
help="Image format",
|
||||
show_default=True,
|
||||
show_envvar=True,
|
||||
)
|
||||
@click.option("--version", default=None, help="CVP version", type=str, required=True)
|
||||
@click.option(
|
||||
"--output",
|
||||
default=str(os.path.relpath(os.getcwd(), start=os.curdir)),
|
||||
help="Path to save image",
|
||||
type=click.Path(),
|
||||
show_default=True,
|
||||
show_envvar=True,
|
||||
)
|
||||
@click.option(
|
||||
"--log-level",
|
||||
"--log",
|
||||
help="Logging level of the command",
|
||||
default=None,
|
||||
type=click.Choice(
|
||||
["debug", "info", "warning", "error", "critical"], case_sensitive=False
|
||||
),
|
||||
"--latest",
|
||||
is_flag=True,
|
||||
help="Get latest version. If --branch is not use, get the latest branch with specific release type",
|
||||
default=False,
|
||||
show_envvar=True,
|
||||
)
|
||||
@click.option(
|
||||
"--version",
|
||||
default=None,
|
||||
help="EOS version to download",
|
||||
show_default=True,
|
||||
show_envvar=True,
|
||||
)
|
||||
@click.option(
|
||||
"--branch",
|
||||
default=None,
|
||||
help="Branch to download",
|
||||
show_default=True,
|
||||
show_envvar=True,
|
||||
)
|
||||
@click.option(
|
||||
"--dry-run",
|
||||
is_flag=True,
|
||||
help="Enable dry-run mode: only run code without system changes",
|
||||
default=False,
|
||||
)
|
||||
@click.pass_context
|
||||
def cvp(
|
||||
ctx: click.Context, version: str, format: str, output: str, log_level: str
|
||||
ctx: click.Context,
|
||||
latest: bool,
|
||||
format: str,
|
||||
output: str,
|
||||
version: Union[str, None],
|
||||
branch: Union[str, None],
|
||||
dry_run: bool = False,
|
||||
) -> int:
|
||||
"""Download CVP image from Arista website"""
|
||||
console = Console()
|
||||
# Get from Context
|
||||
token = ctx.obj["token"]
|
||||
if token is None or token == "":
|
||||
"""Download CVP image from Arista server."""
|
||||
# pylint: disable=unused-variable
|
||||
console, token, debug, log_level = initialize(ctx)
|
||||
|
||||
if version is not None:
|
||||
console.print(
|
||||
"❗ Token is unset ! Please configure ARISTA_TOKEN or use --token option",
|
||||
style="bold red",
|
||||
f"Searching for EOS version [green]{version}[/green] for [blue]{format}[/blue] format..."
|
||||
)
|
||||
elif latest:
|
||||
console.print(
|
||||
f"Searching for [blue]latest[/blue] EOS version for [blue]{format}[/blue] format..."
|
||||
)
|
||||
elif branch is not None:
|
||||
console.print(
|
||||
f"Searching for EOS [b]latest[/b] version for [blue]{branch}[/blue] branch for [blue]{format}[/blue] format..."
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
logger.remove()
|
||||
if log_level is not None:
|
||||
logger.add("eos-downloader.log", rotation="10 MB", level=log_level.upper())
|
||||
if branch is not None or latest:
|
||||
try:
|
||||
querier = AristaXmlQuerier(token=token)
|
||||
version_obj = querier.latest(package="cvp", branch=branch)
|
||||
version = str(version_obj)
|
||||
except Exception as e:
|
||||
console.print(f"Token is set to: {token}")
|
||||
console.print_exception(show_locals=True)
|
||||
return 1
|
||||
|
||||
console.print(
|
||||
"🪐 [bold blue]eos-downloader[/bold blue] is starting...",
|
||||
)
|
||||
console.print(f" - Image Type: {format}")
|
||||
console.print(f" - Version: {version}")
|
||||
console.print(f"version to download is {version}")
|
||||
|
||||
my_download = eos_downloader.eos.EOSDownloader(
|
||||
image=format,
|
||||
software="CloudVision",
|
||||
version=version,
|
||||
token=token,
|
||||
hash_method="md5sum",
|
||||
if version is None:
|
||||
raise ValueError("Version is not set correctly")
|
||||
try:
|
||||
cvp_dl_obj = CvpXmlObject(
|
||||
searched_version=version, token=token, image_type=format
|
||||
)
|
||||
except Exception as e:
|
||||
if debug:
|
||||
console.print_exception(show_locals=True)
|
||||
else:
|
||||
console.print(f"\n[red]Exception raised: {e}[/red]")
|
||||
return 1
|
||||
|
||||
cli = SoftManager(dry_run=dry_run)
|
||||
download_files(
|
||||
console,
|
||||
cli,
|
||||
cvp_dl_obj,
|
||||
output,
|
||||
rich_interface=True,
|
||||
debug=debug,
|
||||
checksum_format="md5sum",
|
||||
)
|
||||
|
||||
my_download.authenticate()
|
||||
console.print(f"CVP file is saved under: {output}")
|
||||
return 0
|
||||
|
||||
my_download.download_local(file_path=output, checksum=False)
|
||||
console.print("✅ processing done !")
|
||||
sys.exit(0)
|
||||
|
||||
@click.command()
|
||||
@click.option(
|
||||
"--source",
|
||||
"-s",
|
||||
help="Image path to download from Arista Website",
|
||||
type=str,
|
||||
show_default=False,
|
||||
show_envvar=False,
|
||||
)
|
||||
@click.option(
|
||||
"--output",
|
||||
"-o",
|
||||
default=str(os.path.relpath(os.getcwd(), start=os.curdir)),
|
||||
help="Path to save downloaded package",
|
||||
type=click.Path(),
|
||||
show_default=True,
|
||||
show_envvar=True,
|
||||
)
|
||||
@click.option(
|
||||
"--import-docker",
|
||||
is_flag=True,
|
||||
help="Import docker image to local docker",
|
||||
default=False,
|
||||
show_envvar=True,
|
||||
)
|
||||
@click.option(
|
||||
"--docker-name",
|
||||
default="arista/ceos:raw",
|
||||
help="Docker image name",
|
||||
show_default=True,
|
||||
show_envvar=True,
|
||||
)
|
||||
@click.option(
|
||||
"--docker-tag",
|
||||
default="dev",
|
||||
help="Docker image tag",
|
||||
show_default=True,
|
||||
show_envvar=True,
|
||||
)
|
||||
@click.pass_context
|
||||
# pylint: disable=too-many-branches
|
||||
def path(
|
||||
ctx: click.Context,
|
||||
output: str,
|
||||
source: str,
|
||||
import_docker: bool,
|
||||
docker_name: str,
|
||||
docker_tag: str,
|
||||
) -> int:
|
||||
"""Download image from Arista server using direct path."""
|
||||
console, token, debug, log_level = initialize(ctx)
|
||||
|
||||
if source is None:
|
||||
console.print("[red]Source is not set correctly ![/red]")
|
||||
return 1
|
||||
|
||||
filename = os.path.basename(source)
|
||||
|
||||
console.print(f"Downloading file {filename} from source: {source}")
|
||||
console.print(f"Saving file to: {output}")
|
||||
|
||||
ar_server = AristaServer(token=token)
|
||||
|
||||
try:
|
||||
file_url = ar_server.get_url(source)
|
||||
if log_level == "debug":
|
||||
console.print(f"URL to download file is: {file_url}")
|
||||
except Exception as e:
|
||||
if debug:
|
||||
console.print_exception(show_locals=True)
|
||||
else:
|
||||
console.print(f"\n[red]Exception raised: {e}[/red]")
|
||||
return 1
|
||||
|
||||
if file_url is None:
|
||||
console.print("File URL is set to None when we expect a string")
|
||||
return 1
|
||||
|
||||
cli = SoftManager(dry_run=False)
|
||||
|
||||
try:
|
||||
cli.download_file(file_url, output, filename=filename)
|
||||
except Exception as e:
|
||||
if debug:
|
||||
console.print_exception(show_locals=True)
|
||||
else:
|
||||
console.print(f"\n[red]Exception raised: {e}[/red]")
|
||||
return 1
|
||||
|
||||
if import_docker:
|
||||
console.print(
|
||||
f"Importing docker image [green]{docker_name}:{docker_tag}[/green] from [blue]{os.path.join(output, filename)}[/blue]..."
|
||||
)
|
||||
|
||||
try:
|
||||
cli.import_docker(
|
||||
local_file_path=os.path.join(output, filename),
|
||||
docker_name=docker_name,
|
||||
docker_tag=docker_tag,
|
||||
)
|
||||
except FileNotFoundError:
|
||||
if debug:
|
||||
console.print_exception(show_locals=True)
|
||||
else:
|
||||
console.print(
|
||||
f"\n[red]File not found: {os.path.join(output, filename)}[/red]"
|
||||
)
|
||||
return 1
|
||||
|
||||
console.print(
|
||||
f"Docker image imported successfully: [green]{docker_name}:{docker_tag}[/green]"
|
||||
)
|
||||
|
||||
return 0
|
||||
|
|
182
eos_downloader/cli/get/utils.py
Normal file
182
eos_downloader/cli/get/utils.py
Normal file
|
@ -0,0 +1,182 @@
|
|||
"""Generic functions for the CLI."""
|
||||
# pylint: disable=too-many-arguments
|
||||
# pylint: disable=too-many-positional-arguments
|
||||
|
||||
import os
|
||||
from typing import cast, Optional, Union, Any
|
||||
import subprocess
|
||||
|
||||
import click
|
||||
from rich.console import Console
|
||||
|
||||
from eos_downloader.cli.utils import cli_logging, console_configuration
|
||||
from eos_downloader.models.data import RTYPE_FEATURE, RTYPES
|
||||
from eos_downloader.models.types import ReleaseType
|
||||
from eos_downloader.logics.arista_xml_server import AristaXmlQuerier, AristaXmlObjects
|
||||
|
||||
|
||||
def initialize(ctx: click.Context) -> tuple[Console, str, bool, str]:
|
||||
"""Initializes the CLI context with necessary configurations.
|
||||
|
||||
Args:
|
||||
ctx (click.Context): The Click context object containing command-line parameters.
|
||||
|
||||
Returns:
|
||||
tuple: A tuple containing the console configuration, token, debug flag, and log level.
|
||||
"""
|
||||
|
||||
console = console_configuration()
|
||||
token = ctx.obj["token"]
|
||||
debug = ctx.obj["debug"]
|
||||
log_level = ctx.obj["log_level"]
|
||||
cli_logging(log_level)
|
||||
|
||||
return console, token, debug, log_level
|
||||
|
||||
|
||||
def search_version(
|
||||
console: Console,
|
||||
token: str,
|
||||
version: Optional[str],
|
||||
latest: bool,
|
||||
branch: Optional[str],
|
||||
file_format: str,
|
||||
release_type: str,
|
||||
) -> Union[str, None]:
|
||||
"""Searches for the specified EOS version based on the provided parameters.
|
||||
|
||||
Args:
|
||||
console (Console): The console object used for printing messages.
|
||||
token (str): The authentication token for accessing the EOS API.
|
||||
version (str or None): The specific version of EOS to search for. If None, other parameters are used.
|
||||
latest (bool): If True, search for the latest EOS version.
|
||||
branch (str or None): The branch of EOS to search for. If None, the default branch is used.
|
||||
format (str): The format of the EOS version (e.g., 'tar', 'zip').
|
||||
release_type (str): The type of release (e.g., 'feature', 'maintenance').
|
||||
|
||||
Returns:
|
||||
str: The version of EOS found based on the search criteria.
|
||||
"""
|
||||
|
||||
if version is not None:
|
||||
console.print(
|
||||
f"Searching for EOS version [green]{version}[/green] for [blue]{file_format}[/blue] format..."
|
||||
)
|
||||
elif latest:
|
||||
console.print(
|
||||
f"Searching for [blue]latest[/blue] EOS version for [blue]{file_format}[/blue] format..."
|
||||
)
|
||||
elif branch is not None:
|
||||
console.print(
|
||||
f"Searching for EOS [b]latest[/b] version for [blue]{branch}[/blue] branch for [blue]{file_format}[/blue] format..."
|
||||
)
|
||||
|
||||
if branch is not None or latest:
|
||||
querier = AristaXmlQuerier(token=token)
|
||||
rtype: ReleaseType = cast(
|
||||
ReleaseType, release_type if release_type in RTYPES else RTYPE_FEATURE
|
||||
)
|
||||
version_obj = querier.latest(package="eos", branch=branch, rtype=rtype)
|
||||
version = str(version_obj)
|
||||
return version
|
||||
|
||||
|
||||
def download_files(
|
||||
console: Console,
|
||||
cli: Any,
|
||||
arista_dl_obj: AristaXmlObjects,
|
||||
output: str,
|
||||
rich_interface: bool,
|
||||
debug: bool,
|
||||
checksum_format: str = "sha512sum",
|
||||
) -> None:
|
||||
"""Downloads EOS files and verifies their checksums.
|
||||
|
||||
Args:
|
||||
console (Console): The console object for printing messages.
|
||||
cli (CLI): The CLI object used to perform download and checksum operations.
|
||||
arista_dl_obj (AristaPackage): The EOS download object containing version and filename information.
|
||||
output (str): The output directory where the files will be saved.
|
||||
rich_interface (bool): Flag to indicate if rich interface should be used.
|
||||
debug (bool): Flag to indicate if debug information should be printed.
|
||||
checksum_format (str): The checksum format to use for verification.
|
||||
|
||||
Raises:
|
||||
Exception: If there is an error during the checksum verification.
|
||||
"""
|
||||
|
||||
console.print(
|
||||
f"Starting download for EOS version [green]{arista_dl_obj.version}[/green] for [blue]{arista_dl_obj.image_type}[/blue] format."
|
||||
)
|
||||
cli.downloads(arista_dl_obj, file_path=output, rich_interface=rich_interface)
|
||||
try:
|
||||
cli.checksum(checksum_format)
|
||||
except subprocess.CalledProcessError:
|
||||
if debug:
|
||||
console.print_exception(show_locals=True)
|
||||
else:
|
||||
console.print(
|
||||
f"[red]Checksum error for file {arista_dl_obj.filename}[/red]"
|
||||
)
|
||||
console.print(
|
||||
f"Arista file [green]{arista_dl_obj.filename}[/green] downloaded in: [blue]{output}[/blue]"
|
||||
)
|
||||
|
||||
|
||||
def handle_docker_import(
|
||||
console: Console,
|
||||
cli: Any,
|
||||
arista_dl_obj: AristaXmlObjects,
|
||||
output: str,
|
||||
docker_name: str,
|
||||
docker_tag: Optional[str],
|
||||
debug: bool,
|
||||
) -> int:
|
||||
"""Handles the import of a Docker image using the provided CLI tool.
|
||||
|
||||
Args:
|
||||
console: The console object used for printing messages.
|
||||
cli: The CLI tool object that provides the import_docker method.
|
||||
arista_dl_obj: An object containing information about the EOS download, including version and filename.
|
||||
output: The directory where the Docker image file is located.
|
||||
docker_name: The name to assign to the Docker image.
|
||||
docker_tag: The tag to assign to the Docker image. If None, the version from eos_dl_obj is used.
|
||||
debug: A boolean indicating whether to print detailed exception information.
|
||||
|
||||
Returns:
|
||||
int: 0 if the Docker image is imported successfully, 1 if a FileNotFoundError occurs.
|
||||
"""
|
||||
|
||||
console.print("Importing docker image...")
|
||||
|
||||
if docker_tag is None:
|
||||
docker_tag = arista_dl_obj.version
|
||||
|
||||
if arista_dl_obj.filename is None:
|
||||
console.print("[red]Invalid filename[/red]")
|
||||
return 1
|
||||
|
||||
console.print(
|
||||
f"Importing docker image [green]{docker_name}:{docker_tag}[/green] from [blue]{os.path.join(output, arista_dl_obj.filename)}[/blue]..."
|
||||
)
|
||||
|
||||
try:
|
||||
cli.import_docker(
|
||||
local_file_path=os.path.join(output, arista_dl_obj.filename),
|
||||
docker_name=docker_name,
|
||||
docker_tag=docker_tag,
|
||||
)
|
||||
except FileNotFoundError:
|
||||
if debug:
|
||||
console.print_exception(show_locals=True)
|
||||
else:
|
||||
console.print(
|
||||
f"\n[red]File not found: {os.path.join(output, arista_dl_obj.filename)}[/red]"
|
||||
)
|
||||
return 1
|
||||
|
||||
console.print(
|
||||
f"Docker image imported successfully: [green]{docker_name}:{docker_tag}[/green]"
|
||||
)
|
||||
|
||||
return 0
|
|
@ -6,130 +6,235 @@
|
|||
# pylint: disable=redefined-builtin
|
||||
# flake8: noqa E501
|
||||
|
||||
"""
|
||||
Commands for ARDL CLI to list data.
|
||||
"""CLI commands for listing Arista package information.
|
||||
|
||||
This module provides CLI commands to query and display version information for Arista packages (EOS and CVP).
|
||||
It includes commands to:
|
||||
- List all available versions with filtering options
|
||||
- Get the latest version for a given package/branch
|
||||
|
||||
The commands use Click for CLI argument parsing and support both text and JSON output formats.
|
||||
Authentication is handled via a token passed through Click context.
|
||||
|
||||
Commands:
|
||||
versions: Lists all available versions with optional filtering
|
||||
latest: Shows the latest version matching the filter criteria
|
||||
|
||||
Dependencies:
|
||||
click: CLI framework
|
||||
rich: For pretty JSON output
|
||||
eos_downloader.logics.arista_server: Core logic for querying Arista servers
|
||||
"""
|
||||
|
||||
import sys
|
||||
from typing import Union
|
||||
import json
|
||||
|
||||
import click
|
||||
from loguru import logger
|
||||
from rich.console import Console
|
||||
from rich.pretty import pprint
|
||||
from rich import print_json
|
||||
from rich.panel import Panel
|
||||
|
||||
import eos_downloader.eos
|
||||
from eos_downloader.models.version import BASE_VERSION_STR, RTYPE_FEATURE, RTYPES
|
||||
from eos_downloader.models.data import software_mapping
|
||||
from eos_downloader.models.types import AristaPackage, ReleaseType, AristaMapping
|
||||
import eos_downloader.logics.arista_xml_server
|
||||
from eos_downloader.cli.utils import console_configuration
|
||||
from eos_downloader.cli.utils import cli_logging
|
||||
|
||||
# """
|
||||
# Commands for ARDL CLI to list data.
|
||||
# """
|
||||
|
||||
|
||||
@click.command(no_args_is_help=True)
|
||||
@click.command()
|
||||
@click.option(
|
||||
"--format",
|
||||
type=click.Choice(["json", "text", "fancy"]),
|
||||
default="fancy",
|
||||
help="Output format",
|
||||
)
|
||||
@click.option(
|
||||
"--package", type=click.Choice(["eos", "cvp"]), default="eos", required=False
|
||||
)
|
||||
@click.option("--branch", "-b", type=str, required=False)
|
||||
@click.option("--release-type", type=str, required=False)
|
||||
@click.pass_context
|
||||
@click.option(
|
||||
"--latest",
|
||||
"-l",
|
||||
is_flag=True,
|
||||
type=click.BOOL,
|
||||
default=False,
|
||||
help="Get latest version in given branch. If --branch is not use, get the latest branch with specific release type",
|
||||
)
|
||||
@click.option(
|
||||
"--release-type",
|
||||
"-rtype",
|
||||
type=click.Choice(RTYPES, case_sensitive=False),
|
||||
default=RTYPE_FEATURE,
|
||||
help="EOS release type to search",
|
||||
)
|
||||
@click.option(
|
||||
"--branch",
|
||||
"-b",
|
||||
type=click.STRING,
|
||||
default=None,
|
||||
help="EOS Branch to list releases",
|
||||
)
|
||||
@click.option(
|
||||
"--verbose",
|
||||
"-v",
|
||||
is_flag=True,
|
||||
type=click.BOOL,
|
||||
default=False,
|
||||
help="Human readable output. Default is none to use output in script)",
|
||||
)
|
||||
@click.option(
|
||||
"--log-level",
|
||||
"--log",
|
||||
help="Logging level of the command",
|
||||
default="warning",
|
||||
type=click.Choice(
|
||||
["debug", "info", "warning", "error", "critical"], case_sensitive=False
|
||||
),
|
||||
)
|
||||
def eos_versions(
|
||||
def versions(
|
||||
ctx: click.Context,
|
||||
log_level: str,
|
||||
branch: Union[str, None] = None,
|
||||
release_type: str = RTYPE_FEATURE,
|
||||
latest: bool = False,
|
||||
verbose: bool = False,
|
||||
package: AristaPackage,
|
||||
branch: str,
|
||||
release_type: ReleaseType,
|
||||
format: str,
|
||||
) -> None:
|
||||
# pylint: disable = too-many-branches, R0917
|
||||
"""
|
||||
List Available EOS version on Arista.com website.
|
||||
"""List available package versions from Arista server."""
|
||||
|
||||
Comes with some filters to get latest release (F or M) as well as branch filtering
|
||||
|
||||
- To get latest M release available (without any branch): ardl info eos-versions --latest -rtype m
|
||||
|
||||
- To get latest F release available: ardl info eos-versions --latest -rtype F
|
||||
"""
|
||||
console = Console()
|
||||
# Get from Context
|
||||
console = console_configuration()
|
||||
token = ctx.obj["token"]
|
||||
debug = ctx.obj["debug"]
|
||||
log_level = ctx.obj["log_level"]
|
||||
cli_logging(log_level)
|
||||
|
||||
logger.remove()
|
||||
if log_level is not None:
|
||||
logger.add("eos-downloader.log", rotation="10 MB", level=log_level.upper())
|
||||
querier = eos_downloader.logics.arista_xml_server.AristaXmlQuerier(token=token)
|
||||
|
||||
my_download = eos_downloader.eos.EOSDownloader(
|
||||
image="unset",
|
||||
software="EOS",
|
||||
version="unset",
|
||||
token=token,
|
||||
hash_method="sha512sum",
|
||||
)
|
||||
|
||||
auth = my_download.authenticate()
|
||||
if verbose and auth:
|
||||
console.print("✅ Authenticated on arista.com")
|
||||
|
||||
if release_type is not None:
|
||||
release_type = release_type.upper()
|
||||
|
||||
if latest:
|
||||
if branch is None:
|
||||
branch = str(my_download.latest_branch(rtype=release_type).branch)
|
||||
latest_version = my_download.latest_eos(branch, rtype=release_type)
|
||||
if str(latest_version) == BASE_VERSION_STR:
|
||||
console.print(
|
||||
f"[red]Error[/red], cannot find any version in {branch} for {release_type} release type"
|
||||
)
|
||||
sys.exit(1)
|
||||
if verbose:
|
||||
console.print(
|
||||
f"Branch {branch} has been selected with release type {release_type}"
|
||||
)
|
||||
if branch is not None:
|
||||
console.print(f"Latest release for {branch}: {latest_version}")
|
||||
else:
|
||||
console.print(f"Latest EOS release: {latest_version}")
|
||||
received_versions = None
|
||||
try:
|
||||
received_versions = querier.available_public_versions(
|
||||
package=package, branch=branch, rtype=release_type
|
||||
)
|
||||
except ValueError:
|
||||
if debug:
|
||||
console.print_exception(show_locals=True)
|
||||
else:
|
||||
console.print(f"{ latest_version }")
|
||||
else:
|
||||
versions = my_download.get_eos_versions(branch=branch, rtype=release_type)
|
||||
if verbose:
|
||||
console.print(
|
||||
f'List of available versions for {branch if branch is not None else "all branches"}'
|
||||
)
|
||||
for version in versions:
|
||||
console.print(f" → {str(version)}")
|
||||
console.print("[red]No versions found[/red]")
|
||||
return
|
||||
|
||||
if format == "text":
|
||||
console.print("Listing available versions")
|
||||
if received_versions is None:
|
||||
console.print("[red]No versions found[/red]")
|
||||
return
|
||||
for version in received_versions:
|
||||
console.print(f" - version: [blue]{version}[/blue]")
|
||||
elif format == "fancy":
|
||||
lines_output = []
|
||||
if received_versions is None:
|
||||
console.print("[red]No versions found[/red]")
|
||||
return
|
||||
for version in received_versions:
|
||||
lines_output.append(f" - version: [blue]{version}[/blue]")
|
||||
console.print("")
|
||||
console.print(
|
||||
Panel("\n".join(lines_output), title="Available versions", padding=1)
|
||||
)
|
||||
elif format == "json":
|
||||
response = []
|
||||
if received_versions is None:
|
||||
console.print("[red]No versions found[/red]")
|
||||
return
|
||||
for version in received_versions:
|
||||
out = {}
|
||||
out["version"] = str(version)
|
||||
out["branch"] = str(version.branch)
|
||||
response.append(out)
|
||||
response = json.dumps(response) # type: ignore
|
||||
print_json(response)
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.option(
|
||||
"--format",
|
||||
type=click.Choice(["json", "text", "fancy"]),
|
||||
default="fancy",
|
||||
help="Output format",
|
||||
)
|
||||
@click.option(
|
||||
"--package", type=click.Choice(["eos", "cvp"]), default="eos", required=False
|
||||
)
|
||||
@click.option("--branch", "-b", type=str, required=False)
|
||||
@click.option("--release-type", type=str, required=False)
|
||||
@click.pass_context
|
||||
def latest(
|
||||
ctx: click.Context,
|
||||
package: AristaPackage,
|
||||
branch: str,
|
||||
release_type: ReleaseType,
|
||||
format: str,
|
||||
) -> None:
|
||||
"""List available versions of Arista packages (eos or CVP) packages."""
|
||||
|
||||
console = console_configuration()
|
||||
token = ctx.obj["token"]
|
||||
debug = ctx.obj["debug"]
|
||||
log_level = ctx.obj["log_level"]
|
||||
cli_logging(log_level)
|
||||
querier = eos_downloader.logics.arista_xml_server.AristaXmlQuerier(token=token)
|
||||
received_version = None
|
||||
try:
|
||||
received_version = querier.latest(
|
||||
package=package, branch=branch, rtype=release_type
|
||||
)
|
||||
except ValueError:
|
||||
if debug:
|
||||
console.print_exception(show_locals=True)
|
||||
else:
|
||||
pprint([str(version) for version in versions])
|
||||
console.print("[red]No versions found[/red]")
|
||||
|
||||
if format in ["text", "fancy"]:
|
||||
version_info = f"Latest version for [green]{package}[/green]: [blue]{received_version}[/blue]"
|
||||
if branch:
|
||||
version_info += f" for branch [blue]{branch}[/blue]"
|
||||
|
||||
if format == "text":
|
||||
console.print("")
|
||||
console.print(version_info)
|
||||
else: # fancy format
|
||||
console.print("")
|
||||
console.print(Panel(version_info, title="Latest version", padding=1))
|
||||
else: # json format
|
||||
print_json(json.dumps({"version": str(received_version)}))
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.option(
|
||||
"--package", type=click.Choice(["eos", "cvp"]), default="eos", required=False
|
||||
)
|
||||
@click.option(
|
||||
"--format",
|
||||
type=click.Choice(["json", "text", "fancy"]),
|
||||
default="fancy",
|
||||
help="Output format",
|
||||
)
|
||||
@click.option(
|
||||
"--details",
|
||||
is_flag=True,
|
||||
show_default=True,
|
||||
default=False,
|
||||
help="Show details for each flavor",
|
||||
)
|
||||
@click.pass_context
|
||||
def mapping(
|
||||
ctx: click.Context, package: AristaPackage, details: bool, format: str
|
||||
) -> None:
|
||||
"""List available flavors of Arista packages (eos or CVP) packages."""
|
||||
|
||||
mapping_pkg_name: AristaMapping = "EOS"
|
||||
if package == "eos":
|
||||
mapping_pkg_name = "EOS"
|
||||
elif package == "cvp":
|
||||
mapping_pkg_name = "CloudVision"
|
||||
console = console_configuration()
|
||||
log_level = ctx.obj["log_level"]
|
||||
console.print(f"Log Level is: {log_level}")
|
||||
cli_logging(log_level)
|
||||
|
||||
if mapping_pkg_name in software_mapping.model_fields:
|
||||
mapping_entries = getattr(software_mapping, mapping_pkg_name, None)
|
||||
if format == "text":
|
||||
console.print(
|
||||
f"Following flavors for [red]{package}/{mapping_pkg_name}[/red] have been found:"
|
||||
)
|
||||
if mapping_entries is None:
|
||||
console.print("[red]No flavors found[/red]")
|
||||
return
|
||||
for mapping_entry in mapping_entries:
|
||||
console.print(f" * Flavor: [blue]{mapping_entry}[/blue]")
|
||||
if details:
|
||||
console.print(
|
||||
f" - Information: [black]{mapping_entries[mapping_entry]}[/black]"
|
||||
)
|
||||
console.print("\n")
|
||||
elif format == "fancy":
|
||||
lines_output = []
|
||||
if mapping_entries is None:
|
||||
lines_output.append("[red]No flavors found[/red]")
|
||||
console.print("\n".join(lines_output))
|
||||
return
|
||||
for mapping_entry in mapping_entries:
|
||||
lines_output.append(f" * Flavor: [blue]{mapping_entry}[/blue]")
|
||||
if details:
|
||||
lines_output.append(
|
||||
f" - Information: [black]{mapping_entries[mapping_entry]}[/black]"
|
||||
)
|
||||
console.print("")
|
||||
console.print(Panel("\n".join(lines_output), title="Flavors", padding=1))
|
||||
console.print("\n")
|
||||
elif format == "json":
|
||||
mapping_json = software_mapping.model_dump()[package.upper()]
|
||||
print_json(json.dumps(mapping_json))
|
||||
|
|
|
@ -8,23 +8,27 @@ Extension for the python ``click`` module
|
|||
to provide a group or command with aliases.
|
||||
"""
|
||||
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
import click
|
||||
|
||||
from rich import pretty
|
||||
from rich.logging import RichHandler
|
||||
from rich.console import Console
|
||||
|
||||
|
||||
class AliasedGroup(click.Group):
|
||||
"""
|
||||
Implements a subclass of Group that accepts a prefix for a command.
|
||||
If there were a command called push, it would accept pus as an alias (so long as it was unique)
|
||||
"""
|
||||
|
||||
def get_command(self, ctx: click.Context, cmd_name: str) -> Any:
|
||||
"""Documentation to build"""
|
||||
rv = click.Group.get_command(self, ctx, cmd_name)
|
||||
if rv is not None:
|
||||
return rv
|
||||
matches = [x for x in self.list_commands(ctx)
|
||||
if x.startswith(cmd_name)]
|
||||
matches = [x for x in self.list_commands(ctx) if x.startswith(cmd_name)]
|
||||
if not matches:
|
||||
return None
|
||||
if len(matches) == 1:
|
||||
|
@ -36,3 +40,45 @@ class AliasedGroup(click.Group):
|
|||
# always return the full command name
|
||||
_, cmd, args = super().resolve_command(ctx, args)
|
||||
return cmd.name, cmd, args
|
||||
|
||||
|
||||
def cli_logging(level: str = "error") -> logging.Logger:
|
||||
"""
|
||||
Configures and returns a logger with the specified logging level.
|
||||
|
||||
This function sets up the logging configuration using the RichHandler
|
||||
to provide rich formatted log messages. The log messages will include
|
||||
the time and can contain markup and rich tracebacks.
|
||||
|
||||
Args:
|
||||
level (str): The logging level as a string (e.g., 'DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL').
|
||||
|
||||
Returns:
|
||||
logging.Logger: A configured logger instance.
|
||||
"""
|
||||
|
||||
FORMAT = "%(message)s"
|
||||
logging.basicConfig(
|
||||
level=level.upper(),
|
||||
format=FORMAT,
|
||||
datefmt="[%X]",
|
||||
handlers=[
|
||||
RichHandler(
|
||||
show_path=True,
|
||||
show_time=True,
|
||||
show_level=True,
|
||||
markup=True,
|
||||
rich_tracebacks=True,
|
||||
tracebacks_suppress=[click],
|
||||
)
|
||||
],
|
||||
)
|
||||
log = logging.getLogger("rich")
|
||||
return log
|
||||
|
||||
|
||||
def console_configuration() -> Console:
|
||||
"""Configure Rich Terminal for the CLI."""
|
||||
pretty.install()
|
||||
console = Console()
|
||||
return console
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue