Skip to content

Commit

Permalink
feat(tools): idf_monitor: support for loadable hint provider modules
Browse files Browse the repository at this point in the history
Currently hints are supported based on hints.yml only, which may be
limiting for some use cases. This introduces a generic plugin approach,
which allows to implement hint module that doesn't require entry in hints.yml.
Such module has the full command output available and it is not limited to
a single regex in hints.yml.

Note that regex in hint.yml expects the output concatenated into a single line,
but hint modules are getting the output unchanged.

Signed-off-by: Frantisek Hrbata <[email protected]>
  • Loading branch information
igrr authored and fhrbata committed Aug 5, 2023
1 parent ed35c3a commit 54d4662
Showing 1 changed file with 42 additions and 7 deletions.
49 changes: 42 additions & 7 deletions tools/idf_py_actions/tools.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import asyncio
import importlib
import json
import os
import re
import subprocess
import sys
from asyncio.subprocess import Process
from io import open
from pkgutil import iter_modules
from types import FunctionType
from typing import Any, Dict, Generator, List, Match, Optional, TextIO, Tuple, Union

Expand Down Expand Up @@ -165,16 +167,50 @@ def debug_print_idf_version() -> None:
print_warning(f'ESP-IDF {idf_version() or "version unknown"}')


def load_hints() -> Any:
def load_hints() -> Dict:
"""Helper function to load hints yml file"""
with open(os.path.join(os.path.dirname(__file__), 'hints.yml'), 'r') as file:
hints = yaml.safe_load(file)
hints: Dict = {
'yml': [],
'modules': []
}

current_module_dir = os.path.dirname(__file__)
with open(os.path.join(current_module_dir, 'hints.yml'), 'r') as file:
hints['yml'] = yaml.safe_load(file)

hint_modules_dir = os.path.join(current_module_dir, 'hint_modules')
if not os.path.exists(hint_modules_dir):
return hints

sys.path.append(hint_modules_dir)
for _, name, _ in iter_modules([hint_modules_dir]):
# Import modules for hint processing and add list of their 'generate_hint' functions into hint dict.
# If the module doesn't have the function 'generate_hint', it will raise an exception
try:
hints['modules'].append(getattr(importlib.import_module(name), 'generate_hint'))
except ModuleNotFoundError:
red_print(f'Failed to import "{name}" from "{hint_modules_dir}" as a module')
raise SystemExit(1)
except AttributeError:
red_print('Module "{}" does not have function generate_hint.'.format(name))
raise SystemExit(1)

return hints


def generate_hints_buffer(output: str, hints: list) -> Generator:
def generate_hints_buffer(output: str, hints: Dict) -> Generator:
"""Helper function to process hints within a string buffer"""
for hint in hints:
# Call modules for possible hints with unchanged output. Note that
# hints in hints.yml expect new line trimmed, but modules should
# get the output unchanged. Please see tools/idf_py_actions/hints.yml
for generate_hint in hints['modules']:
module_hint = generate_hint(output)
if module_hint:
yield module_hint

# hints expect new lines trimmed
output = ' '.join(line.strip() for line in output.splitlines() if line.strip())
for hint in hints['yml']:
variables_list = hint.get('variables')
hint_list, hint_vars, re_vars = [], [], []
match: Optional[Match[str]] = None
Expand Down Expand Up @@ -214,8 +250,7 @@ def generate_hints(*filenames: str) -> Generator:
hints = load_hints()
for file_name in filenames:
with open(file_name, 'r') as file:
output = ' '.join(line.strip() for line in file if line.strip())
yield from generate_hints_buffer(output, hints)
yield from generate_hints_buffer(file.read(), hints)


def fit_text_in_terminal(out: str) -> str:
Expand Down

0 comments on commit 54d4662

Please sign in to comment.