Skip to content

Commit

Permalink
feat: Improve the definition of shell app.
Browse files Browse the repository at this point in the history
  • Loading branch information
xmnlab committed Mar 29, 2024
1 parent 152cc24 commit cb8e55c
Show file tree
Hide file tree
Showing 9 changed files with 1,354 additions and 605 deletions.
1,822 changes: 1,243 additions & 579 deletions poetry.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ ruff = ">=0.1.5"
bandit = ">=1.7.5"
vulture = ">=2.7"
compose-go = ">=2.20.2"
jupyterlab = ">=4.1.5"
nox = ">=2024.3.2"

[build-system]
requires = ["poetry-core>=1.0.0", "poetry>=1.5.1"]
Expand Down
1 change: 0 additions & 1 deletion src/makim/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""Top-level package for makim."""


__author__ = 'Ivan Ogasawara'
__email__ = '[email protected]'
__version__ = '1.14.0' # semantic-release
Expand Down
1 change: 1 addition & 0 deletions src/makim/__main__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Makim app to be called from `python -m`."""

from makim.cli import run_app

if __name__ == '__main__':
Expand Down
1 change: 1 addition & 0 deletions src/makim/cli.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Cli functions to define the arguments and to call Makim."""

from __future__ import annotations

import os
Expand Down
1 change: 1 addition & 0 deletions src/makim/console.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Functions about console."""

import os


Expand Down
114 changes: 89 additions & 25 deletions src/makim/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
the way to define targets and dependencies. Instead of using the
`Makefile` format, it uses `yaml` format.
"""

from __future__ import annotations

import copy
Expand All @@ -17,17 +18,20 @@

from copy import deepcopy
from pathlib import Path
from typing import Any, Optional, Union
from typing import Any, Dict, List, Optional, Union, cast

import dotenv
import sh
import yaml # type: ignore

from jinja2 import Environment
from typing_extensions import TypeAlias

from makim.console import get_terminal_size
from makim.logs import MakimError, MakimLogs

AppConfigType: TypeAlias = Dict[str, Union[str, List[str]]]

SCOPE_GLOBAL = 0
SCOPE_GROUP = 1
SCOPE_TARGET = 2
Expand All @@ -36,6 +40,12 @@
KNOWN_SHELL_APP_ARGS = {
'bash': ['-e'],
'php': ['-f'],
'nox': ['-f'],
}

# useful when the program just read specific file extension
KNOWN_SHELL_APP_FILE_SUFFIX = {
'nox': '.makim.py',
}

TEMPLATE = Environment(
Expand Down Expand Up @@ -88,6 +98,7 @@ class Makim:
global_data: dict = {}
shell_app: sh.Command = sh.xonsh
shell_args: list[str] = []
tmp_suffix: str = '.makim'

# temporary variables
env: dict = {} # initial env
Expand All @@ -111,10 +122,14 @@ def __init__(self):
self.file = '.makim.yaml'
self.dry_run = False
self.verbose = False
self.shell_app = sh.xonsh
self.shell_args: list[str] = []
self.tmp_suffix: str = '.makim'

def _call_shell_app(self, cmd):
fd, filepath = tempfile.mkstemp(suffix='.makim', text=True)
self._load_shell_app()

fd, filepath = tempfile.mkstemp(suffix=self.tmp_suffix, text=True)

with open(filepath, 'w') as f:
f.write(cmd)
Expand Down Expand Up @@ -185,9 +200,6 @@ def _change_target(self, target_name: str) -> None:
for target_name, target_data in self.group_data['targets'].items():
if target_name == self.target_name:
self.target_data = target_data
shell_app = target_data.get('shell')
if shell_app:
self._load_shell_app(shell_app)
return

MakimLogs.raise_error(
Expand All @@ -201,20 +213,10 @@ def _change_group_data(self, group_name=None) -> None:

if group_name is not None:
self.group_name = group_name
shell_app_default = self.global_data.get('shell', 'xonsh')
if self.group_name == 'default' and len(groups) == 1:
group = next(iter(groups))
self.group_data = groups[group]

shell_app = self.group_data.get('shell', shell_app_default)
self._load_shell_app(shell_app)
return

for group in groups:
if group == self.group_name:
self.group_data = groups[group]
shell_app = groups[group].get('shell', shell_app_default)
self._load_shell_app(shell_app)
return

MakimLogs.raise_error(
Expand Down Expand Up @@ -269,17 +271,79 @@ def update_working_directory(

return working_dir

def _load_shell_app(self, shell_app: str = '') -> None:
if not shell_app:
shell_app = self.global_data.get('shell', 'xonsh')
return
def _extract_shell_app_config(
self, scoped_config: dict[str, Any]
) -> AppConfigType:
"""Extract the shell app configuration from the scoped config data."""
shell_app_data: AppConfigType = scoped_config.get('shell', {})

cmd = shell_app.split(' ')
cmd_name = cmd[0]
self.shell_app = getattr(sh, cmd_name)
if not shell_app_data:
return {}

args: list[str] = KNOWN_SHELL_APP_ARGS.get(cmd_name, [])
self.shell_args = args + cmd[1:]
shell_app_default = 'xonsh'
tmp_suffix_default = '.makim'

shell_config: AppConfigType = {}

if isinstance(shell_app_data, str):
cmd = shell_app_data.split(' ')
app_name = cmd[0]
args: list[str] = KNOWN_SHELL_APP_ARGS.get(app_name, [])
shell_config['app'] = cmd[0]
shell_config['suffix'] = KNOWN_SHELL_APP_FILE_SUFFIX.get(
app_name, tmp_suffix_default
)
shell_config['args'] = args + cmd[1:]
elif isinstance(shell_app_data, dict):
app_name = str(shell_app_data.get('app', shell_app_default))
shell_config['app'] = app_name
shell_tmp_suffix_default = KNOWN_SHELL_APP_FILE_SUFFIX.get(
app_name, tmp_suffix_default
)
shell_config['suffix'] = shell_app_data.get(
'suffix', shell_tmp_suffix_default
)
shell_config['args'] = shell_app_data.get('args', [])
return shell_config

def _load_shell_app(self) -> None:
"""Load the shell app."""
shell_config: AppConfigType = {
'app': 'xonsh',
'args': [],
'suffix': '.makim',
}
tmp_suffix_default = '.makim'

for scoped_data in [
self.global_data,
self.group_data,
self.target_data,
]:
tmp_config: AppConfigType = self._extract_shell_app_config(
scoped_data
)
if tmp_config:
shell_config = tmp_config

cmd_name = str(shell_config.get('app', ''))
cmd_args: list[str] = cast(list[str], shell_config.get('args', []))
cmd_tmp_suffix: str = str(
shell_config.get('suffix', tmp_suffix_default)
)

if not cmd_name:
MakimLogs.raise_error(
'The shell command is invalid',
MakimError.MAKIM_CONFIG_FILE_INVALID,
)

print('=' * 80)
print(cmd_name, cmd_args, cmd_tmp_suffix)

self.shell_app = getattr(sh, cmd_name)
self.shell_args = cmd_args
self.tmp_suffix = cmd_tmp_suffix

def _load_dotenv(self, data_scope: dict) -> dict[str, str]:
env_file = data_scope.get('env-file')
Expand Down Expand Up @@ -537,7 +601,7 @@ def load(self, file: str, dry_run: bool = False, verbose: bool = False):

self._load_config_data()
self._verify_config()
self._load_shell_app()
# self._load_shell_app()
self.env = self._load_dotenv(self.global_data)

def run(self, args: dict):
Expand Down
2 changes: 2 additions & 0 deletions src/makim/logs.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Classes and function for handling logs."""

import os

from enum import Enum
Expand All @@ -18,6 +19,7 @@ class MakimError(Enum):
MAKIM_VARS_ATTRIBUTE_INVALID = 7
MAKIM_ARGUMENT_REQUIRED = 8
MAKIM_ENV_FILE_NOT_FOUND = 9
MAKIM_CONFIG_FILE_INVALID = 10


class MakimLogs:
Expand Down
15 changes: 15 additions & 0 deletions tests/smoke/.makim-interpreters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,21 @@ groups:
help: Test using nodejs
shell: node
run: console.log("Hello, World!");

nox:
help: Test using nox
shell:
app: nox
args: ["--noxfile"]
suffix: .nox.py

run: |
import nox
@nox.session
def test(session):
print("Hello, World!")
perl:
help: Test using perl
shell: perl
Expand Down

0 comments on commit cb8e55c

Please sign in to comment.