Skip to content

Commit

Permalink
feat(doctor): colouring output
Browse files Browse the repository at this point in the history
  • Loading branch information
mzaatar committed Dec 15, 2022
1 parent 5c0e67a commit 6bfb300
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 76 deletions.
23 changes: 18 additions & 5 deletions src/algokit/cli/doctor.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import click
import pyperclip3 # type: ignore
from algokit.core.doctor import DoctorFunctions
from algokit.core.doctor import DoctorFunctions, ProcessResult

logger = logging.getLogger(__name__)
DOCTOR_END_MESSAGE = (
Expand All @@ -30,7 +30,7 @@
def doctor_command(*, copy_to_clipboard: bool) -> None:
os_type = platform.system().lower()

service_outputs: dict[str, str] = {}
service_outputs: dict[str, ProcessResult] = {}
service_outputs_contents_lines: list[str] = []
doctor_functions = DoctorFunctions()

Expand All @@ -51,15 +51,28 @@ def doctor_command(*, copy_to_clipboard: bool) -> None:
service_outputs["Node.js"] = doctor_functions.get_node_info()
service_outputs["Npm"] = doctor_functions.get_npm_info()

critical_services = ["Docker", "Docker Compose", "Git"]
# Print the status details
if copy_to_clipboard:
for key, value in service_outputs.items():
logger.info(click.style(f"{key}: ", bold=True) + f"{value}")
service_outputs_contents_lines.append(f"{key}: {value}\n")
color = "green"
if value.exit_code != 0:
if key in critical_services:
color = "red"
else:
color = "yellow"
logger.info(click.style(f"{key}: ", bold=True) + click.style(f"{value.info}", fg=color))
service_outputs_contents_lines.append(f"{key}: {value.info}\n")
service_outputs_contents_lines.append(DOCTOR_END_MESSAGE)
else:
for key, value in service_outputs.items():
logger.info(click.style(f"{key}: ", bold=True) + f"{value}")
color = "green"
if value.exit_code != 0:
if key in critical_services:
color = "red"
else:
color = "yellow"
logger.info(click.style(f"{key}: ", bold=True) + click.style(f"{value.info}", fg=color))

# print end message anyway
logger.info(DOCTOR_END_MESSAGE)
Expand Down
179 changes: 108 additions & 71 deletions src/algokit/core/doctor.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import dataclasses
import logging
import platform
from datetime import datetime, timezone
Expand All @@ -14,123 +15,159 @@
)


@dataclasses.dataclass
class ProcessResult:
info: str
exit_code: int


class DoctorFunctions:
def get_date(self) -> str:
return format(datetime.now(timezone.utc).astimezone().isoformat())
def get_date(self) -> ProcessResult:
return ProcessResult(format(datetime.now(timezone.utc).astimezone().isoformat()), 0)

def get_algokit_info(self) -> str:
algokit_info = self.get_installed_software_version(["pip", "show", "AlgoKit"])
return f"{algokit_info['version']} {algokit_info['location']}"
def get_algokit_info(self) -> ProcessResult:
try:
process_results = proc.run(["pip", "show", "AlgoKit"])
algokit_info: dict[str, str] = {}
for line in process_results.output.splitlines():
line_parts = line.split(":")
algokit_info[line_parts[0].lower().strip()] = line_parts[1].strip()
return ProcessResult(f"{algokit_info['version']} {algokit_info['location']}", process_results.exit_code)
except Exception:
return ProcessResult("Not found", 1)

def get_choco_info(self) -> str:
def get_choco_info(self) -> ProcessResult:
try:
return proc.run(["choco"]).output.splitlines()[0].split(" v")[1]
process_results = proc.run(["choco"])
return ProcessResult(process_results.output.splitlines()[0].split(" v")[1], process_results.exit_code)
except Exception:
return "None found"
return ProcessResult("None found", 1)

def get_brew_info(self) -> str:
def get_brew_info(self) -> ProcessResult:
try:
return proc.run(["brew", "-v"]).output.splitlines()[0].split(" ")[1]
process_results = proc.run(["brew", "-v"])
return ProcessResult(process_results.output.splitlines()[0].split(" ")[1], process_results.exit_code)
except Exception:
return "None found"
return ProcessResult("None found", 1)

def get_os(self, os_type: str) -> str:
def get_os(self, os_type: str) -> ProcessResult:
os_version = ""
if os_type == "windows":
os_version = platform.win32_ver()[0]
elif os_type == "darwin":
os_version = platform.mac_ver()[0]
else:
os_version = platform.version()
return f"{os_type} {os_version}"
return ProcessResult(f"{os_type} {os_version}", 0)

def get_docker_info(self) -> str:
def get_docker_info(self) -> ProcessResult:
try:
docker_version = proc.run(["docker", "-v"]).output.splitlines()[0].split(" ")[2].split(",")[0]
return docker_version
process_results = proc.run(["docker", "-v"])
return ProcessResult(
process_results.output.splitlines()[0].split(" ")[2].split(",")[0], process_results.exit_code
)
except Exception:
return (
"None found.\nDocker required to `run algokit sandbox` command;"
" install via https://docs.docker.com/get-docker/"
return ProcessResult(
(
"None found.\nDocker required to `run algokit sandbox` command;"
" install via https://docs.docker.com/get-docker/"
),
1,
)

def get_docker_compose_info(self) -> str:
def get_docker_compose_info(self) -> ProcessResult:
try:
docker_compose_version = proc.run(["docker-compose", "-v"]).output.splitlines()[0].split(" v")[2]
return (
docker_compose_version
if self.is_minimum_version(docker_compose_version, DOCKER_COMPOSE_MINIMUM_VERSION)
else f"{docker_compose_version}.\n{docker_compose_minimum_version_message}"
process_results = proc.run(["docker-compose", "-v"])
docker_compose_version = process_results.output.splitlines()[0].split(" v")[2]
minimum_version_met = self.is_minimum_version(docker_compose_version, DOCKER_COMPOSE_MINIMUM_VERSION)
return ProcessResult(
(
docker_compose_version
if minimum_version_met
else f"{docker_compose_version}.\n{docker_compose_minimum_version_message}"
),
process_results.exit_code if minimum_version_met else 1,
)
except Exception:
return f"None found. {docker_compose_minimum_version_message}"
return ProcessResult(f"None found. {docker_compose_minimum_version_message}", 1)

def get_git_info(self, system: str) -> str:
def get_git_info(self, system: str) -> ProcessResult:
try:
git_version = proc.run(["git", "-v"]).output.splitlines()[0].split(" ")[2]
return git_version
process_results = proc.run(["git", "-v"])
return ProcessResult(process_results.output.splitlines()[0].split(" ")[2], process_results.exit_code)
except Exception:
if system == "windows":
return (
"Git required to `run algokit init`;"
"install via `choco install git` if using Chocolatey or "
"via https://github.com/git-guides/install-git#install-git-on-windows"
return ProcessResult(
(
"Git required to `run algokit init`; install via `choco install git` if using Chocolatey or "
"via https://github.com/git-guides/install-git#install-git-on-windows"
),
1,
)

else:
return "Git required to run algokit init; " "install via https://github.com/git-guides/install-git"

def get_algokit_python_info(self) -> str:
return proc.run(["python", "--version"]).output.splitlines()[0].split(" ")[1]
return ProcessResult(
"Git required to run algokit init; " "install via https://github.com/git-guides/install-git", 1
)

def get_global_python_info(self) -> str:
return "[TODO] <version of first global path python3 version> <path> | None found"
def get_algokit_python_info(self) -> ProcessResult:
try:
process_results = proc.run(["python", "--version"])
return ProcessResult(process_results.output.splitlines()[0].split(" ")[1], process_results.exit_code)
except Exception:
return ProcessResult("None found.", 1)

def get_pipx_info(self) -> str:
def get_global_python_info(self) -> ProcessResult:
try:
pipx_version = proc.run(["pipx", "--version"]).output.splitlines()[0]
return pipx_version
# [TODO] <version of first global path python3 version> <path> | None found
process_results = proc.run(["python", "--version"])
return ProcessResult(process_results.output.splitlines()[0].split(" ")[1], process_results.exit_code)
except Exception:
return "None found.\nPipx is required to install Poetry; install via https://pypa.github.io/pipx/"
return ProcessResult("None found.", 1)

def get_poetry_info(self) -> str:
def get_pipx_info(self) -> ProcessResult:
try:
poetry_version = (
proc.run(["poetry", "--version"]).output.splitlines()[-1].split("version ")[1].split(")")[0]
process_results = proc.run(["pipx", "--version"])
return ProcessResult(process_results.output.splitlines()[0], process_results.exit_code)
except Exception:
return ProcessResult(
"None found.\nPipx is required to install Poetry; install via https://pypa.github.io/pipx/", 1
)
return poetry_version

def get_poetry_info(self) -> ProcessResult:
try:
process_results = proc.run(["poetry", "--version"])
poetry_version = process_results.output.splitlines()[-1].split("version ")[1].split(")")[0]
return ProcessResult(poetry_version, process_results.exit_code)
except Exception:
return (
"None found.\nPoetry is required for some Python-based templates; "
"install via algokit bootstrap within project directory, "
"or via https://python-poetry.org/docs/#installation"
return ProcessResult(
(
"None found.\nPoetry is required for some Python-based templates; "
"install via algokit bootstrap within project directory, "
"or via https://python-poetry.org/docs/#installation"
),
1,
)

def get_node_info(self) -> str:
def get_node_info(self) -> ProcessResult:
try:
node_version = proc.run(["node", "-v"]).output.splitlines()[0].split("v")[1]
return node_version
process_results = proc.run(["node", "-v"])
return ProcessResult(process_results.output.splitlines()[0].split("v")[1], process_results.exit_code)
except Exception:
return (
"None found.\nNode.js is required for some Node.js-based templates; "
"install via `algokit bootstrap` within project directory, "
"or via https://nodejs.dev/en/learn/how-to-install-nodejs/"
return ProcessResult(
(
"None found.\nNode.js is required for some Node.js-based templates; "
"install via `algokit bootstrap` within project directory, "
"or via https://nodejs.dev/en/learn/how-to-install-nodejs/"
),
1,
)

def get_npm_info(self) -> str:
def get_npm_info(self) -> ProcessResult:
try:
npm_version = proc.run(["npm", "-v"]).output
return npm_version
process_results = proc.run(["npm", "-v"])
return ProcessResult(process_results.output, process_results.exit_code)
except Exception:
return "None found"

def get_installed_software_version(self, command: list[str]) -> dict[str, str]:
package_info_lines = proc.run(command).output.splitlines()
results: dict[str, str] = {}
for line in package_info_lines:
line_parts = line.split(":")
results[line_parts[0].lower().strip()] = line_parts[1].strip()
return results
return ProcessResult("None found", 1)

def is_minimum_version(self, system_version: str, minimum_version: str) -> bool:
system_version_as_tuple = tuple(map(int, (system_version.split("."))))
Expand Down

0 comments on commit 6bfb300

Please sign in to comment.