Skip to content

Commit

Permalink
cmake ctest support (#6)
Browse files Browse the repository at this point in the history
* cmake ctest support
  • Loading branch information
PhilipDeegan authored Dec 19, 2023
1 parent 837bb1c commit 6467c50
Show file tree
Hide file tree
Showing 31 changed files with 824 additions and 297 deletions.
2 changes: 2 additions & 0 deletions .pylintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[TYPECHECK]
ignored-classes=ValDict
6 changes: 6 additions & 0 deletions ISSUES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# ISSUES.md

## type hints

Python 3.8 doesn't support `dict[str,str]`
Python 3.8 is EOL October 2024
5 changes: 5 additions & 0 deletions phlop/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#
#
#
#
#
17 changes: 17 additions & 0 deletions phlop/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#
#
#
#
#


available_modules = """Available:
phlop.app
phlop.os
phlop.proc
phlop.reflection
phlop.run
phlop.string
phlop.testing"""

print(available_modules)
89 changes: 5 additions & 84 deletions phlop/app/__init__.py
Original file line number Diff line number Diff line change
@@ -1,84 +1,5 @@
def decode_bytes(input):
return input.decode("ascii", errors="ignore")


def run(cmd, shell=True, capture_output=True, check=False, print_cmd=True, **kwargs):
"""
https://docs.python.org/3/library/subprocess.html
"""
import subprocess

if print_cmd:
print(f"running: {cmd}")
try:
return subprocess.run(
cmd, shell=shell, capture_output=capture_output, check=check, **kwargs
)
except subprocess.CalledProcessError as e: # only triggers on failure if check=True
print(f"run failed with error: {e}\n\t{e.stdout}\n\t{e.stderr} ")
raise RuntimeError(decode_bytes(e.stderr))


def run_mp(cmds, N_CORES=None, **kwargs):
"""
spawns N_CORES threads (default=len(cmds)) running commands and waiting for results
https://docs.python.org/3/library/concurrent.futures.html
"""
import concurrent.futures

if N_CORES is None:
N_CORES = len(cmds)

with concurrent.futures.ThreadPoolExecutor(max_workers=N_CORES) as executor:
jobs = [executor.submit(run, cmd, **kwargs) for cmd in cmds]
results = []
for future in concurrent.futures.as_completed(jobs):
try:
results += [future.result()]
if future.exception() is not None:
raise future.exception()
except Exception as exc:
if kwargs.get("check", False):
executor.shutdown(wait=False, cancel_futures=True)
raise exc
else:
print(f"run_mp generated an exception: {exc}")
return results


def binary_exists_on_path(bin):
"""
https://linux.die.net/man/1/which
"""
return run(f"which {bin}").returncode == 0


def scan_dir(path, files_only=False, dirs_only=False, drop=[]):
import os

assert os.path.exists(path)
checks = [
lambda entry: not files_only or (files_only and entry.is_file()),
lambda entry: not dirs_only or (dirs_only and entry.is_dir()),
lambda entry: entry.name not in drop,
]
return [
entry.name
for entry in os.scandir(path)
if all([check(entry) for check in checks])
]


import contextlib


@contextlib.contextmanager
def pushd(new_cwd):
import os

cwd = os.getcwd()
os.chdir(new_cwd)
try:
yield
finally:
os.chdir(cwd)
#
#
#
#
#
14 changes: 14 additions & 0 deletions phlop/app/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#
#
#
#
#


available_modules = """Available:
phlop.app.cmake
phlop.app.test_cases
phlop.app.git
phlop.app.perf"""

print(available_modules)
104 changes: 104 additions & 0 deletions phlop/app/cmake.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#
#
#
#
#


import json
from dataclasses import dataclass, field

from phlop.proc import run
from phlop.string import decode_bytes


def version():
pass


def make_config_str(path, cxx_flags=None, use_ninja=False, use_ccache=False, extra=""):
cxx_flags = "" if cxx_flags is None else f'-DCMAKE_CXX_FLAGS="{cxx_flags}"'
ccache = "" if use_ccache is False else "-DCMAKE_CXX_COMPILER_LAUNCHER=ccache"
ninja = "" if not use_ninja else "-G Ninja"

return f"cmake {path} {cxx_flags} {ninja} {ccache} {extra}"


def config(path, cxx_flags=None, use_ninja=False, use_ccache=False, extra=""):
cmd = make_config_str(path, cxx_flags, use_ninja, extra)
run(cmd, capture_output=False)


def build(use_ninja=False, threads=1):
run("ninja" if use_ninja else f"make -j{threads}", capture_output=False)


@dataclass
class CTest_test:
backtrace: int # care?
command: list # list[str] # eventually
# [
# "/opt/py/py/bin/python3",
# "-u",
# "test_particles_advance_2d.py"
# ],
name: str # "py3_advance-2d-particles",
properties: list = field(default_factory=lambda: [{}]) # list[dict] # eventually

env: dict = field(default_factory=lambda: {}) # dict[str, str] # eventually
working_dir: str = field(default_factory=lambda: None)

def __post_init__(self):
for p in self.properties:
if p["name"] == "ENVIRONMENT":
for item in p["value"]:
bits = item.split("=")
self.env.update({bits[0]: "=".join(bits[1:])})
elif p["name"] == "WORKING_DIRECTORY":
self.working_dir = p["value"]

# [
# {
# "name" : "ENVIRONMENT",
# "value" :
# [
# "PYTHONPATH=/home/p/git/phare/master/build:/home/p/git/phare/master/pyphare",
# "ASAN_OPTIONS=detect_leaks=0"
# ]
# },
# {
# "name" : "WORKING_DIRECTORY",
# "value" : "/home/p/git/phare/master/build/tests/simulator/advance"
# }
# ]


def list_tests(build_dir=None):
cmd = "".join(
[
s
for s in [
"ctest ",
f"--test-dir {build_dir} " if build_dir else "",
"--show-only=json-v1",
]
if s
]
)
return [
CTest_test(**test)
for test in json.loads(decode_bytes(run(cmd, capture_output=True).stdout))[
"tests"
]
]


def test_cmd(test, verbose=False):
cmd = f"ctest -R {test}"
if verbose:
cmd = f"{cmd} -V"
return cmd


if __name__ == "__main__":
list_tests("build")
13 changes: 8 additions & 5 deletions phlop/app/git.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
#
#
#
#
#


import atexit
import subprocess

Expand Down Expand Up @@ -26,11 +33,7 @@ def branch_exists(branch):
return True


def checkout(branch, create=False, recreate=False):
if recreate:
delete_branch(branch)
create = True

def checkout(branch, create=False):
if create and not branch_exists(branch):
run(f"git checkout -b {branch}", check=True)
else:
Expand Down
11 changes: 9 additions & 2 deletions phlop/app/perf.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
#
#
#
#
#


import csv
import os

Expand All @@ -6,10 +13,10 @@

def version():
# validated on perf version: 5.19
proc = run("perf -v", shell=True, capture_output=True)
proc = run("perf -v", shell=True, capture_output=True).out()
if " " not in proc or "." not in proc:
raise ValueError("Unparsable result from 'perf -v'")
return [int(digit) for digit in proc.split(" ").split(".")]
return [int(digit) for digit in proc.split(" ")[-1].split(".")]


def check(force_kernel_space=False):
Expand Down
14 changes: 14 additions & 0 deletions phlop/app/sleep.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#
#
#
#
#

import sys
import time

if __name__ == "__main__":
t = sys.argv[1]
if not t:
t = 1
time.sleep(int(t))
Loading

0 comments on commit 6467c50

Please sign in to comment.