Skip to content

Commit

Permalink
Linting the toolchain (MFlowCode#230)
Browse files Browse the repository at this point in the history
  • Loading branch information
henryleberre committed Jan 5, 2024
1 parent e80a3f7 commit 4c2450b
Show file tree
Hide file tree
Showing 22 changed files with 169 additions and 146 deletions.
19 changes: 19 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Lint

on:
push:

pull_request:

workflow_dispatch:

jobs:
docs:
name: Lint
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Lint
run: ./mfc.sh lint
8 changes: 8 additions & 0 deletions mfc.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ fi
# If the user wishes to run the "load" script
if [ "$1" == 'load' ]; then
shift; . "$(pwd)/toolchain/bootstrap/modules.sh" $@; return
elif [ "$1" == "lint" ]; then
. "$(pwd)/toolchain/bootstrap/python.sh"

shift; . "$(pwd)/toolchain/bootstrap/lint.sh" $@; exit 0
elif [ "$1" == "format" ]; then
. "$(pwd)/toolchain/bootstrap/python.sh"

Expand All @@ -37,10 +41,14 @@ mkdir -p "$(pwd)/build"
. "$(pwd)/toolchain/bootstrap/cmake.sh"
. "$(pwd)/toolchain/bootstrap/python.sh"

echo

# Run the main.py bootstrap script
python3 "$(pwd)/toolchain/mfc.py" "$@"
code=$?

echo

if [ $code -ne 0 ]; then
error "mfc.py finished with a $code exit code."
fi
Expand Down
11 changes: 5 additions & 6 deletions toolchain/mfc.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,13 @@

def __print_greeting():
MFC_LOGO_LINES = MFC_LOGO.splitlines()
max_logo_line_length = max([ len(line) for line in MFC_LOGO_LINES ])
max_logo_line_length = max(len(line) for line in MFC_LOGO_LINES)

host_line = f"{getpass.getuser()}@{platform.node()} [{platform.system()}]"
targets_line = f"[bold]--targets {format_list_to_string(ARG('targets'), 'magenta', 'None')}[/bold]"
help_line = "$ ./mfc.sh \[build, run, test, clean, count, packer] --help"
help_line = "$ ./mfc.sh (build, run, test, clean, count, packer) --help"

MFC_SIDEBAR_LINES = [
"",
f"[bold]{host_line}[/bold]",
'-' * len(host_line),
f"[bold]--jobs [magenta]{ARG('jobs')}[/magenta][/bold]"
Expand All @@ -35,7 +34,7 @@ def __print_greeting():
lhs = a.ljust(max_logo_line_length)
rhs = b if b is not None else ''
cons.print(
f"[bold] {lhs} [/bold] {rhs}",
f"[bold]{lhs}[/bold] | {rhs}",
highlight=False
)

Expand All @@ -47,7 +46,7 @@ def __checks():
raise MFCException("CMake is required to build MFC but couldn't be located on your system. Please ensure it installed and discoverable (e.g in your system's $PATH).")


def __run():
def __run():
{"test": test.test, "run": run.run, "build": build.build,
"clean": build.clean, "bench": bench.bench, "count": count.count,
"packer": packer.packer
Expand All @@ -60,7 +59,7 @@ def __run():
state.gARG = args.parse(state.gCFG)

lock.switch(state.MFCConfig.from_dict(state.gARG))

__print_greeting()
__checks()
__run()
Expand Down
8 changes: 4 additions & 4 deletions toolchain/mfc/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ def parse(config):
bench = parsers.add_parser(name="bench", help="Benchmark MFC (for CI).", formatter_class=argparse.ArgumentDefaultsHelpFormatter)
count = parsers.add_parser(name="count", help="Count LOC in MFC.", formatter_class=argparse.ArgumentDefaultsHelpFormatter)
packer = parsers.add_parser(name="packer", help="Packer utility (pack/unpack/compare)", formatter_class=argparse.ArgumentDefaultsHelpFormatter)

packers = packer.add_subparsers(dest="packer")
pack = packers.add_parser(name="pack", help="Pack a case into a single file.", formatter_class=argparse.ArgumentDefaultsHelpFormatter)
pack.add_argument("input", metavar="INPUT", type=str, default="", help="Input file of case to pack.")
pack.add_argument("-o", "--output", metavar="OUTPUT", type=str, default=None, help="Base name of output file.")

compare = packers.add_parser(name="compare", help="Compare two cases.", formatter_class=argparse.ArgumentDefaultsHelpFormatter)
compare.add_argument("input1", metavar="INPUT1", type=str, default=None, help="First pack file.")
compare.add_argument("input2", metavar="INPUT2", type=str, default=None, help="Second pack file.")
Expand All @@ -54,7 +54,7 @@ def add_common_arguments(p, mask = None):
p.add_argument(f"--no-{f.name}", action="store_false", dest=f.name, help=f"Turn the {f.name} option OFF.")

p.set_defaults(**{ f.name: getattr(config, f.name) for f in dataclasses.fields(config) })

if "j" not in mask:
p.add_argument("-j", "--jobs", metavar="JOBS", type=int, default=1, help="Allows for JOBS concurrent jobs.")

Expand Down Expand Up @@ -152,7 +152,7 @@ def add_common_arguments(p, mask = None):
# build's --case-optimization and --input depend on each other
if args["command"] == "build":
if (args["input"] is not None) ^ args["case_optimization"] :
raise MFCException(f"./mfc.sh build's --case-optimization requires --input")
raise MFCException("./mfc.sh build's --case-optimization requires --input")

# Input files to absolute paths
for e in ["input", "input1", "input2"]:
Expand Down
29 changes: 16 additions & 13 deletions toolchain/mfc/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def get_install_dirpath(self) -> str:
"install",
'dependencies' if self.isDependency else CFG().make_slug()
])

def get_install_binpath(self) -> str:
# <root>/install/<slug>/bin/<target>
return os.sep.join([self.get_install_dirpath(), "bin", self.name])
Expand Down Expand Up @@ -104,17 +104,21 @@ def configure(self):
build_dirpath = self.get_build_dirpath()
cmake_dirpath = self.get_cmake_dirpath()
install_dirpath = self.get_install_dirpath()

install_prefixes = ';'.join([install_dirpath, get_dependency_install_dirpath()])

flags: list = self.flags.copy() + [
# Disable CMake warnings intended for developers (us).
# See: https://cmake.org/cmake/help/latest/manual/cmake.1.html.
f"-Wno-dev",
"-Wno-dev",
# Disable warnings about unused command line arguments. This is
# useful for passing arguments to CMake that are not used by the
# current target.
"--no-warn-unused-cli",
# Save a compile_commands.json file with the compile commands used to
# build the configured targets. This is mostly useful for debugging.
# See: https://cmake.org/cmake/help/latest/variable/CMAKE_EXPORT_COMPILE_COMMANDS.html.
f"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON",
"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON",
# Set build type (e.g Debug, Release, etc.).
# See: https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html
f"-DCMAKE_BUILD_TYPE={'Debug' if ARG('debug') else 'Release'}",
Expand Down Expand Up @@ -143,14 +147,13 @@ def configure(self):
if system(configure, no_exception=True) != 0:
raise MFCException(f"Failed to configure the [bold magenta]{self.name}[/bold magenta] target.")


def build(self):
input.load({}).generate_fpp(self)

build = ["cmake", "--build", self.get_build_dirpath(),
"--target", self.name,
"-j", ARG("jobs"),
"--config", 'Debug' if ARG('debug') else 'Release']
build = ["cmake", "--build", self.get_build_dirpath(),
"--target", self.name,
"--parallel", ARG("jobs"),
"--config", 'Debug' if ARG('debug') else 'Release']
if ARG('verbose'):
build.append("--verbose")

Expand All @@ -160,7 +163,7 @@ def install(self):
install = ["cmake", "--install", self.get_build_dirpath()]

system(install, exception_text=f"Failed to install the [bold magenta]{self.name}[/bold magenta] target.")

def clean(self):
build_dirpath = self.get_build_dirpath()

Expand Down Expand Up @@ -196,7 +199,7 @@ def clean(self):
def get_target(target: typing.Union[str, MFCTarget]) -> MFCTarget:
if isinstance(target, MFCTarget):
return target

if target in TARGET_MAP:
return TARGET_MAP[target]

Expand All @@ -218,7 +221,7 @@ def build_target(target: typing.Union[MFCTarget, str], history: typing.Set[str]
history = set()

t = get_target(target)

if t.name in history or not t.is_buildable():
return

Expand All @@ -245,7 +248,7 @@ def clean_target(target: typing.Union[MFCTarget, str], history: typing.Set[str]
history = set()

t = get_target(target)

if t.name in history or not t.is_buildable():
return

Expand Down
2 changes: 1 addition & 1 deletion toolchain/mfc/case.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class Case:

def __init__(self, params: dict) -> None:
self.params = copy.deepcopy(params)

def get_parameters(self) -> str:
return self.params.keys()

Expand Down
32 changes: 15 additions & 17 deletions toolchain/mfc/common.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
import os, yaml, typing, shutil, subprocess, dataclasses

from datetime import datetime
import os, re, yaml, typing, shutil, subprocess

from .printer import cons

from os.path import abspath, normpath, dirname, realpath


MFC_ROOTDIR = normpath(f"{dirname(realpath(__file__))}/../..")
MFC_TESTDIR = abspath(f"{MFC_ROOTDIR}/tests")
MFC_SUBDIR = abspath(f"{MFC_ROOTDIR}/build")
MFC_DEV_FILEPATH = abspath(f"{MFC_ROOTDIR}/toolchain/mfc.dev.yaml")
MFC_USER_FILEPATH = abspath(f"{MFC_ROOTDIR}/defaults.yaml")
MFC_LOCK_FILEPATH = abspath(f"{MFC_SUBDIR}/lock.yaml")
MFC_ROOTDIR = normpath(f"{dirname(realpath(__file__))}/../..")
MFC_TESTDIR = abspath(f"{MFC_ROOTDIR}/tests")
MFC_SUBDIR = abspath(f"{MFC_ROOTDIR}/build")
MFC_LOCK_FILEPATH = abspath(f"{MFC_SUBDIR}/lock.yaml")
MFC_BENCH_FILEPATH = abspath(f"{MFC_ROOTDIR}/toolchain/bench.yaml")

MFC_LOGO = f"""
MFC_LOGO = """\
.=++*: -+*+=.
:+ -*- == =* .
:*+ == ++ .+-
Expand All @@ -23,7 +20,7 @@
.:++=----------====+*= ==..:%.....
.:-=++++===--==+=-+= +. :=
+#=::::::::=%=. -+: =+ *:
.*=-=*=.. :=+*+: -...--
.*=-=*=.. :=+*+: -...--\
"""


Expand All @@ -41,7 +38,7 @@ def system(command: typing.List[str], no_exception: bool = False, exception_text
cons.print(no_indent=True)

cons.print(f"$ {' '.join(cmd)}")

if stdout != subprocess.DEVNULL:
cons.print(no_indent=True)

Expand Down Expand Up @@ -122,7 +119,7 @@ def get_program_output(arguments: typing.List[str] = None, cwd=None):
return (proc.communicate()[0].decode(), proc.returncode)


def get_py_program_output(filepath: str, arguments: typing.List[str] = None):
def get_py_program_output(filepath: str, arguments: typing.List[str] = None):
dirpath = os.path.abspath (os.path.dirname(filepath))
filename = os.path.basename(filepath)

Expand Down Expand Up @@ -157,12 +154,12 @@ def does_command_exist(s: str) -> bool:
def format_list_to_string(arr: list, item_style=None, empty=None):
if empty is None:
empty = "nothing"

pre, post = "", ""
if item_style is not None:
pre = f"[{item_style}]"
post = f"[/{item_style}]"

if len(arr) == 0:
return f"{pre}{empty}{post}"

Expand Down Expand Up @@ -190,6 +187,7 @@ def find(predicate, arr: list):
return None, None


# pylint: disable=redefined-builtin
def quit(sig):
os.kill(os.getpid(), sig)

Expand All @@ -213,10 +211,10 @@ def get_loaded_modules() -> typing.List[str]:
def is_number(x: str) -> bool:
if x is None:
return False

if isinstance(x, int) or isinstance(x, float):
return True

try:
float(x)
return True
Expand Down
8 changes: 4 additions & 4 deletions toolchain/mfc/count.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@ def count():

cons.print(f"[bold]Counting lines of code in {target_str_list}[/bold] (excluding whitespace lines)")
cons.indent()

total = 0
for codedir in ['common'] + ARG("targets"):
dirfiles, dircount = handle_dir(os.path.join(MFC_ROOTDIR, 'src', codedir))
dirfiles, dircount = handle_dir(os.path.join(MFC_ROOTDIR, 'src', codedir))
table = rich.table.Table(show_header=True, box=rich.table.box.SIMPLE)
table.add_column(f"File (in [magenta]{codedir}[/magenta])", justify="left")
table.add_column(f"Lines ([cyan]{dircount}[/cyan])", justify="right")

for filepath, count in dirfiles:
table.add_row(f"{os.path.basename(filepath)}", f"[bold cyan]{count}[/bold cyan]")

total += dircount

cons.raw.print(table)
Expand Down
10 changes: 5 additions & 5 deletions toolchain/mfc/lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class MFCLockData:

def init():
global data

if not os.path.exists(common.MFC_LOCK_FILEPATH):
config = MFCConfig()
data = MFCLockData(config, MFC_LOCK_CURRENT_VERSION)
Expand All @@ -33,9 +33,9 @@ def init():

def load():
global data

d = common.file_load_yaml(common.MFC_LOCK_FILEPATH)

# 0 is the default version in order to accommodate versions of mfc.sh
# prior to the introduction of the "version" attribute to the lock file.

Expand All @@ -52,13 +52,13 @@ def load():

def write():
global data

common.file_dump_yaml(common.MFC_LOCK_FILEPATH, dataclasses.asdict(data))


def switch(to: MFCConfig):
global data

if to == data.config:
return

Expand Down
2 changes: 1 addition & 1 deletion toolchain/mfc/packer/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,4 @@ def push(self, error: Error) -> None:
self.count += 1

def __repr__(self) -> str:
return self.get().__repr__()
return self.get().__repr__()
Loading

0 comments on commit 4c2450b

Please sign in to comment.