Skip to content

Commit

Permalink
ver 0.1.3.f1-alpha
Browse files Browse the repository at this point in the history
  • Loading branch information
blademd committed Jul 15, 2023
1 parent ec62f3e commit 0a65202
Show file tree
Hide file tree
Showing 24 changed files with 180 additions and 248 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ python -m thymus clier

## Documentation

Please, refer to [Wiki](https://github.com/blademd/thymus/wiki) (*work in progress*)
Please, refer to [Wiki](https://github.com/blademd/thymus/wiki).

## Feedback

Expand Down
130 changes: 0 additions & 130 deletions olddoc.md

This file was deleted.

23 changes: 21 additions & 2 deletions release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
* Cisco IOS (IOS-XE), Arista EOS support.
* Now you can close a working context with the Escape key (with a confirmation dialog).
* Logging system with rotating files. Log files are stored in the "logs/" folder. The config file for the logging is "settings/logging.conf".
** Logs are accessible inside the Application via a modal dialog (Ctrl+L).
* * Logs are accessible inside the Application via a modal dialog (Ctrl+L).

# Changes
## Changes

* Textual version 0.29.0.
* Main screen was redesigned. It does not contain any active elements anymore.
Expand Down Expand Up @@ -59,3 +59,22 @@
* If the content of two different files was the same `compare`, and `diff` calls crashed the app.
* An empty input field of a working screen crashed the app after pressing the Enter key.
* Minor bugs.

# Version 0.1.3.f1-alpha

## Changes

* Folder structure was changed.

## Enhancements

* Now, JunOS has its native `match` keyword for filtering.
* After the sequence of "| " the auto-complete stops making the experience more smooth.

## Fixes

* IOS/EOS. The heuristics mechanism produced the double output both in the text field and the left sidebar.
* IOS/EOS. The `up` or `exit` commands did not consider the accessibility of the parent's section. Users could get useless buds.
* The `level` setting in the "logging.conf" did not work.
* IOS/EOS. The `wildcard` sub-command did not work with the path argument.
* IOS/EOS. The parser did not take into account the possible variable length of indentation in a file.
2 changes: 1 addition & 1 deletion thymus/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = '0.1.3-alpha'
__version__ = '0.1.3.f1-alpha'

CONFIG_PATH = 'thymus/settings/'
CONFIG_NAME = 'thymus.json'
Expand Down
45 changes: 22 additions & 23 deletions thymus/app_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,6 @@ def __init_logging(self) -> None:
err_msg += f'Exception: "{err}".'
errors.append(err_msg)
try:
self.__logger.setLevel(logging.INFO)
formatter = logging.Formatter(LOGGING_FORMAT)
buf_handler = BufferingHandler(LOGGING_BUF_CAP)
buf_handler.setFormatter(formatter)
Expand Down Expand Up @@ -207,18 +206,38 @@ def __process_config(self) -> None:
self.__logger.error(f'{err}')
self.__is_alert = True

def __read_config(self) -> None:
if not self.__is_dir:
return
self.__logger.debug(f'Loading a configuration from: {CONFIG_PATH}{CONFIG_NAME}.')
data: dict[str, Any] = {}
with open(f'{CONFIG_PATH}{CONFIG_NAME}', encoding='utf-8') as f:
data = json.load(f)
if not data:
raise Exception(f'Reading of the config file "{CONFIG_NAME}" was failed.')
self.validate_keys(DEFAULT_GLOBALS, data, self.__validate_globals)
for platform, store in PLATFORMS.items():
if platform_data := data.get(platform):
if not hasattr(self, f'_AppSettings__validate_{platform}_key'):
self.__logger.error(f'No validator for {platform.upper()}. Default.')
continue
validator = getattr(self, f'_AppSettings__validate_{platform}_key')
self.validate_keys(store, platform_data, validator, platform)
else:
self.__logger.warning(f'No data for {platform.upper()}. Default.')

def __save_config(self) -> None:
if not self.__is_dir:
return
self.__logger.debug(f'Saving a configuration into the file: {CONFIG_PATH}/{CONFIG_NAME}.')
self.__logger.debug(f'Saving a configuration into the file: {CONFIG_PATH}{CONFIG_NAME}.')
data = self.globals
for platform, platform_data in PLATFORMS.items():
data.update(
{
platform: self.__platforms[platform] if self.__platforms.get(platform) else platform_data
}
)
with open(f'{CONFIG_PATH}/{CONFIG_NAME}', 'w', encoding='utf-8') as f:
with open(f'{CONFIG_PATH}{CONFIG_NAME}', 'w', encoding='utf-8') as f:
json.dump(data, f, indent=4)
f.flush()
os.fsync(f.fileno())
Expand Down Expand Up @@ -317,26 +336,6 @@ def __validate_eos_key(self, key: str, value: str | int) -> str | int:
self.__logger.warning(f'Unknown EOS attribute: {key}. Ignore.')
return value

def __read_config(self) -> None:
if not self.__is_dir:
return
self.__logger.debug(f'Loading a configuration from: {CONFIG_PATH}/{CONFIG_NAME}.')
data: dict[str, Any] = {}
with open(f'{CONFIG_PATH}/{CONFIG_NAME}', encoding='utf-8') as f:
data = json.load(f)
if not data:
raise Exception(f'Reading of the config file "{CONFIG_NAME}" was failed.')
self.validate_keys(DEFAULT_GLOBALS, data, self.__validate_globals)
for platform, store in PLATFORMS.items():
if platform_data := data.get(platform):
if not hasattr(self, f'_AppSettings__validate_{platform}_key'):
self.__logger.error(f'No validator for {platform.upper()}. Default.')
continue
validator = getattr(self, f'_AppSettings__validate_{platform}_key')
self.validate_keys(store, platform_data, validator, platform)
else:
self.__logger.warning(f'No data for {platform.upper()}. Default.')

def process_command(self, command: str) -> SettingsResponse:
if not command.startswith('global '):
return SettingsResponse.error('Unknown global command.')
Expand Down
15 changes: 14 additions & 1 deletion thymus/contexts/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from functools import reduce
from collections import deque
from typing import TYPE_CHECKING
from logging import Logger, getLogger

from ..responses import AlertResponse
from ..lexers import CommonLexer
Expand Down Expand Up @@ -30,6 +31,7 @@ class Context:
'__content',
'__encoding',
'__spaces',
'__logger',
)
__names_cache: list[tuple[Context, str]] = []
delimiter: str = '^'
Expand Down Expand Up @@ -74,6 +76,10 @@ def spaces(self) -> int:
def nos_type(self) -> str:
return ''

@property
def logger(self) -> Logger:
return self.__logger

@spaces.setter
def spaces(self, value: int) -> None:
if value not in (1, 2, 4):
Expand All @@ -93,16 +99,23 @@ def name(self, value: str) -> None:
@encoding.setter
def encoding(self, value: str) -> None:
try:
'shlop'.encode(value)
'schlop'.encode(value)
self.__encoding = value
except LookupError:
raise ValueError(f'"{value}" is not a correct encoding.')

@logger.setter
def logger(self, value: Logger) -> None:
if type(value) is not Logger:
raise ValueError('Incorrect type of a logger.')
self.__logger = value

def __init__(self, name: str, content: list[str], encoding='utf-8-sig') -> None:
self.__name = name
self.__content = content
self.__encoding = encoding
self.__spaces = 2
self.__logger = getLogger()

def free(self) -> None:
if (type(self), self.__name) in self.__names_cache:
Expand Down
1 change: 1 addition & 0 deletions thymus/contexts/eos.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from . import IOSContext


class EOSContext(IOSContext):
def __init__(self, name: str, content: list[str], encoding: str = 'utf-8-sig') -> None:
super().__init__(name, content, encoding)
Expand Down
25 changes: 16 additions & 9 deletions thymus/contexts/ios.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,16 @@ def __init__(self, name: str, content: list[str], encoding: str = 'utf-8-sig') -
self.keywords['filter'].append('include')

def __rebuild_tree(self) -> None:
self.command_top()
self.__tree = None
self.__cursor = None
self.__tree = construct_tree(
config=self.content,
delimiter=self.delimiter,
is_heuristics=self.__is_heuristics,
is_crop=self.__is_crop,
is_promisc=self.__is_promisc
)
self.__cursor = self.__tree

def __get_node_content(self, node: Root | Node) -> Generator[str, None, None]:
return lazy_provide_config(self.content, node, self.spaces)
Expand Down Expand Up @@ -228,7 +230,12 @@ def mod_sections(self, jump_node: Optional[Node] = None) -> Generator[str | Fabr
yield '\n'
yield from self.__inspect_children(node, node.path)

def mod_wildcard(self, data: Iterable[str], args: list[str]) -> Generator[str | FabricException, None, None]:
def mod_wildcard(
self,
data: Iterable[str],
args: list[str],
jump_node: Optional[Node] = None
) -> Generator[str | FabricException, None, None]:
if not data or len(args) != 1:
yield FabricException('Incorrect arguments for "wildcard".')
try:
Expand All @@ -241,10 +248,12 @@ def mod_wildcard(self, data: Iterable[str], args: list[str]) -> Generator[str |
if isinstance(head, Exception):
yield head
else:
if not self.__cursor.children:
node = jump_node if jump_node else self.__cursor
if not node.children:
yield FabricException('No sections at this level.')
yield '\n'
for path, child in self.__inspect_children(self.__cursor, self.__cursor.path, is_pair=True):
for path, child in self.__inspect_children(node, node.path, is_pair=True):
self.logger.debug(f'{path} {child.name}')
if re.search(regexp, path):
yield from self.__get_node_content(child)
except StopIteration:
Expand Down Expand Up @@ -324,7 +333,7 @@ def __check_leading_mod(name: str, position: int, args_count: int, args_limit: i
data = self.mod_count(data, elem[1:])
break
elif command in self.keywords['wildcard']:
data = self.mod_wildcard(data, elem[1:])
data = self.mod_wildcard(data, elem[1:], jump_node)
elif command in self.keywords['diff']:
__check_leading_mod(command, number, len(elem[1:]), 1)
data = self.mod_diff(elem[1:], jump_node)
Expand Down Expand Up @@ -423,7 +432,8 @@ def command_up(self, args: deque[str]) -> Response:
if current.name == 'root':
break
current = current.parent
steps -= 1
if current.is_accessible:
steps -= 1
self.__cursor = current
return AlertResponse.success()

Expand Down Expand Up @@ -454,15 +464,12 @@ def command_set(self, args: deque[str]) -> Response:
else:
self.__is_crop = False
self.__rebuild_tree()
analyze_heuristics(self.__tree, self.delimiter, self.__is_crop)
elif command == 'promisc':
if value in ('on', '1', 1):
self.__is_promisc = True
else:
self.__is_promisc = False
self.__rebuild_tree()
if self.__is_heuristics:
analyze_heuristics(self.__tree, self.delimiter, self.__is_crop)
return AlertResponse.success(f'The "set {command}" was successfully modified.')
else:
args.appendleft(command)
Expand Down
Loading

0 comments on commit 0a65202

Please sign in to comment.