diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f442f61..d71ccd1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,18 +11,44 @@ on: types: - published - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - jobs: + build: + name: Build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-python@v4 + name: Install Python + with: + python-version: "3.11" + + - name: Install dependencies + run: | + python -m pip install build + + - name: Build + run: | + python -m build peakrdl-cli -o dist/ + python -m build peakrdl -o dist/ + + - uses: actions/upload-artifact@v4 + with: + name: dist + path: | + dist/*.tar.gz + dist/*.whl +#------------------------------------------------------------------------------- test: + needs: + - build strategy: matrix: python-version: - - 3.6 - - 3.7 - - 3.8 - - 3.9 + - "3.6" + - "3.7" + - "3.8" + - "3.9" - "3.10" - "3.11" - "3.12" @@ -33,40 +59,35 @@ jobs: - python-version: 3.6 os: ubuntu-20.04 + - python-version: "3.7" + os: ubuntu-22.04 + + - python-version: "3.8" + os: ubuntu-22.04 + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 - - name: Set up Python 3.7 to bootstrap py3.6 - if: ${{ matrix.python-version == '3.6' }} - uses: actions/setup-python@v4 - with: - python-version: 3.7 - - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install -U -r test/requirements.txt + - uses: actions/download-artifact@v4 + with: + name: dist + path: dist - # Python 3.6 cannot install directly from a pyproject.toml - # Instead, build a wheel from py3.7 and then install it - - name: Install via wheel - if: ${{ matrix.python-version == '3.6' }} + - name: Install dependencies run: | - python3.7 -m pip install build - python3.7 -m build - python --version - python -m pip install ./dist/*.whl + python -m pip install -r test/requirements.txt - name: Install - if: ${{ matrix.python-version != '3.6' }} run: | - python -m pip install . + python -m pip install dist/peakrdl_cli-*.whl + python -m pip install dist/peakrdl-*.whl - name: Test run: | @@ -100,28 +121,37 @@ jobs: #------------------------------------------------------------------------------- lint: + needs: + - build runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Set up Python uses: actions/setup-python@v4 with: - python-version: "3.10" + python-version: "3.11" + + - uses: actions/download-artifact@v4 + with: + name: dist + path: dist - name: Install dependencies run: | - python -m pip install -U pylint + python -m pip install -r test/requirements.txt - name: Install run: | - python -m pip install . + python -m pip install dist/peakrdl_cli-*.whl - name: Run Lint run: | - pylint --rcfile test/pylint.rc peakrdl + pylint --rcfile test/pylint.rc peakrdl-cli/src/peakrdl #------------------------------------------------------------------------------- mypy: + needs: + - build runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -130,48 +160,29 @@ jobs: with: python-version: "3.10" + - uses: actions/download-artifact@v4 + with: + name: dist + path: dist + - name: Install dependencies run: | - python -m pip install -U mypy + python -m pip install -r test/requirements.txt + + - name: Install + run: | + python -m pip install dist/peakrdl_cli-*.whl - name: Type Check run: | - mypy --config-file test/mypy.ini src/peakrdl + mypy --config-file test/mypy.ini peakrdl-cli/src/peakrdl #------------------------------------------------------------------------------- - build: + deploy: needs: - test - lint - mypy - name: Build distributions - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - uses: actions/setup-python@v4 - name: Install Python - with: - python-version: "3.10" - - - name: Install dependencies - run: | - python -m pip install -U build - - - name: Build - run: python -m build - - - uses: actions/upload-artifact@v4 - with: - name: dist - path: | - dist/*.tar.gz - dist/*.whl - -#------------------------------------------------------------------------------- - deploy: - needs: - - build runs-on: ubuntu-latest environment: release diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 354c013..037b972 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -14,4 +14,4 @@ python: install: - requirements: docs/requirements.txt - method: pip - path: . + path: peakrdl-cli/ diff --git a/peakrdl-cli/LICENSE b/peakrdl-cli/LICENSE new file mode 120000 index 0000000..ea5b606 --- /dev/null +++ b/peakrdl-cli/LICENSE @@ -0,0 +1 @@ +../LICENSE \ No newline at end of file diff --git a/peakrdl-cli/README.md b/peakrdl-cli/README.md new file mode 100644 index 0000000..0255051 --- /dev/null +++ b/peakrdl-cli/README.md @@ -0,0 +1,5 @@ +# PeakRDL command-line interface +This package implements the command-line interface for the PeakRDL toolchain. + +## Documentation +See the [PeakRDL Documentation](http://peakrdl.readthedocs.io) for more details. diff --git a/pyproject.toml b/peakrdl-cli/pyproject.toml similarity index 88% rename from pyproject.toml rename to peakrdl-cli/pyproject.toml index fbeea39..f740621 100644 --- a/pyproject.toml +++ b/peakrdl-cli/pyproject.toml @@ -3,17 +3,11 @@ requires = ["setuptools", "setuptools-scm"] build-backend = "setuptools.build_meta" [project] -name = "peakrdl" +name = "peakrdl-cli" dynamic = ["version"] requires-python = ">=3.6" dependencies = [ "systemrdl-compiler >= 1.27.1, < 2", - "peakrdl-html >= 2.10.1, < 3", - "peakrdl-ipxact >= 3.4.1, < 4", - "peakrdl-regblock >= 0.19.0, < 2", - "peakrdl-systemrdl >= 0.3.0, < 2", - "peakrdl-uvm >= 2.3.0, < 3", - "peakrdl-cheader >= 1.0.0, < 2", "tomli;python_version<'3.11'", ] diff --git a/peakrdl-cli/src/peakrdl/__about__.py b/peakrdl-cli/src/peakrdl/__about__.py new file mode 100644 index 0000000..c68196d --- /dev/null +++ b/peakrdl-cli/src/peakrdl/__about__.py @@ -0,0 +1 @@ +__version__ = "1.2.0" diff --git a/src/peakrdl/__init__.py b/peakrdl-cli/src/peakrdl/__init__.py similarity index 100% rename from src/peakrdl/__init__.py rename to peakrdl-cli/src/peakrdl/__init__.py diff --git a/src/peakrdl/__main__.py b/peakrdl-cli/src/peakrdl/__main__.py similarity index 100% rename from src/peakrdl/__main__.py rename to peakrdl-cli/src/peakrdl/__main__.py diff --git a/src/peakrdl/cmd/__init__.py b/peakrdl-cli/src/peakrdl/cmd/__init__.py similarity index 100% rename from src/peakrdl/cmd/__init__.py rename to peakrdl-cli/src/peakrdl/cmd/__init__.py diff --git a/src/peakrdl/cmd/dump.py b/peakrdl-cli/src/peakrdl/cmd/dump.py similarity index 100% rename from src/peakrdl/cmd/dump.py rename to peakrdl-cli/src/peakrdl/cmd/dump.py diff --git a/src/peakrdl/cmd/list_globals.py b/peakrdl-cli/src/peakrdl/cmd/list_globals.py similarity index 100% rename from src/peakrdl/cmd/list_globals.py rename to peakrdl-cli/src/peakrdl/cmd/list_globals.py diff --git a/src/peakrdl/cmd/preprocess.py b/peakrdl-cli/src/peakrdl/cmd/preprocess.py similarity index 100% rename from src/peakrdl/cmd/preprocess.py rename to peakrdl-cli/src/peakrdl/cmd/preprocess.py diff --git a/src/peakrdl/config/__init__.py b/peakrdl-cli/src/peakrdl/config/__init__.py similarity index 100% rename from src/peakrdl/config/__init__.py rename to peakrdl-cli/src/peakrdl/config/__init__.py diff --git a/src/peakrdl/config/loader.py b/peakrdl-cli/src/peakrdl/config/loader.py similarity index 99% rename from src/peakrdl/config/loader.py rename to peakrdl-cli/src/peakrdl/config/loader.py index 27c116a..38274cc 100644 --- a/src/peakrdl/config/loader.py +++ b/peakrdl-cli/src/peakrdl/config/loader.py @@ -100,6 +100,7 @@ def load_cfg(argv: List[str]) -> AppConfig: if path is None: # Nope. Still no config file. Provide empty data raw_data = {} + path = "" else: if not os.path.isfile(path): print(f"error: invalid config file path: {path}", file=sys.stderr) diff --git a/src/peakrdl/config/schema.py b/peakrdl-cli/src/peakrdl/config/schema.py similarity index 100% rename from src/peakrdl/config/schema.py rename to peakrdl-cli/src/peakrdl/config/schema.py diff --git a/src/peakrdl/importer.py b/peakrdl-cli/src/peakrdl/importer.py similarity index 100% rename from src/peakrdl/importer.py rename to peakrdl-cli/src/peakrdl/importer.py diff --git a/src/peakrdl/main.py b/peakrdl-cli/src/peakrdl/main.py similarity index 100% rename from src/peakrdl/main.py rename to peakrdl-cli/src/peakrdl/main.py diff --git a/src/peakrdl/plugins/__init__.py b/peakrdl-cli/src/peakrdl/plugins/__init__.py similarity index 100% rename from src/peakrdl/plugins/__init__.py rename to peakrdl-cli/src/peakrdl/plugins/__init__.py diff --git a/src/peakrdl/plugins/entry_points.py b/peakrdl-cli/src/peakrdl/plugins/entry_points.py similarity index 87% rename from src/peakrdl/plugins/entry_points.py rename to peakrdl-cli/src/peakrdl/plugins/entry_points.py index 54fabae..3faed54 100644 --- a/src/peakrdl/plugins/entry_points.py +++ b/peakrdl-cli/src/peakrdl/plugins/entry_points.py @@ -1,5 +1,5 @@ import sys -from typing import List, Tuple, TYPE_CHECKING +from typing import List, Tuple, TYPE_CHECKING, Optional if TYPE_CHECKING: from importlib.metadata import EntryPoint, Distribution @@ -7,7 +7,7 @@ if sys.version_info >= (3,10,0): from importlib import metadata - def _get_entry_points(group_name: str) -> List[Tuple['EntryPoint', 'Distribution']]: + def _get_entry_points(group_name: str) -> List[Tuple['EntryPoint', Optional['Distribution']]]: eps = [] for ep in metadata.entry_points().select(group=group_name): eps.append((ep, ep.dist)) @@ -19,8 +19,8 @@ def _get_name_from_dist(dist: 'Distribution') -> str: elif sys.version_info >= (3,8,0): # pragma: no cover from importlib import metadata - def _get_entry_points(group_name: str) -> List[Tuple['EntryPoint', 'Distribution']]: - eps = [] + def _get_entry_points(group_name: str) -> List[Tuple['EntryPoint', Optional['Distribution']]]: + eps = [] # type: List[Tuple[EntryPoint, Optional[Distribution]]] dist_names = set() for dist in metadata.distributions(): # Due to a bug in importlib.metadata's distributions iterator, in @@ -42,7 +42,7 @@ def _get_name_from_dist(dist: 'Distribution') -> str: else: # pragma: no cover import pkg_resources # type: ignore - def _get_entry_points(group_name: str) -> List[Tuple['EntryPoint', 'Distribution']]: + def _get_entry_points(group_name: str) -> List[Tuple['EntryPoint', Optional['Distribution']]]: eps = [] for ep in pkg_resources.iter_entry_points(group_name): eps.append((ep, ep.dist)) @@ -52,7 +52,7 @@ def _get_name_from_dist(dist: 'Distribution') -> str: return dist.project_name # type: ignore -def get_entry_points(group_name: str) -> List[Tuple['EntryPoint', 'Distribution']]: +def get_entry_points(group_name: str) -> List[Tuple['EntryPoint', Optional['Distribution']]]: return _get_entry_points(group_name) def get_name_from_dist(dist: 'Distribution') -> str: diff --git a/src/peakrdl/plugins/exporter.py b/peakrdl-cli/src/peakrdl/plugins/exporter.py similarity index 92% rename from src/peakrdl/plugins/exporter.py rename to peakrdl-cli/src/peakrdl/plugins/exporter.py index 9c78bee..d064bcc 100644 --- a/src/peakrdl/plugins/exporter.py +++ b/peakrdl-cli/src/peakrdl/plugins/exporter.py @@ -42,12 +42,17 @@ def get_exporter_plugins(cfg: 'AppConfig') -> List[ExporterSubcommandPlugin]: # Get exporter plugins from entry-points for ep, dist in get_entry_points("peakrdl.exporters"): cls = ep.load() - dist_name = get_name_from_dist(dist) + if dist: + dist_name = get_name_from_dist(dist) + dist_version = dist.version + else: + dist_name = None + dist_version = None if issubclass(cls, ExporterSubcommandPlugin): # Override name - always use entry point's name cls.name = ep.name - exporter = cls(dist_name=dist_name, dist_version=dist.version) + exporter = cls(dist_name=dist_name, dist_version=dist_version) else: raise RuntimeError(f"Exporter class {cls} is expected to be extended from peakrdl.plugins.exporter.ExporterSubcommandPlugin") exporters.append(exporter) diff --git a/src/peakrdl/plugins/importer.py b/peakrdl-cli/src/peakrdl/plugins/importer.py similarity index 91% rename from src/peakrdl/plugins/importer.py rename to peakrdl-cli/src/peakrdl/plugins/importer.py index a8a930e..60b5482 100644 --- a/src/peakrdl/plugins/importer.py +++ b/peakrdl-cli/src/peakrdl/plugins/importer.py @@ -42,12 +42,17 @@ def get_importer_plugins(cfg: 'AppConfig') -> List[ImporterPlugin]: # Get importer plugins from entry-points for ep, dist in get_entry_points("peakrdl.importers"): cls = ep.load() - dist_name = get_name_from_dist(dist) + if dist: + dist_name = get_name_from_dist(dist) + dist_version = dist.version + else: + dist_name = None + dist_version = None if issubclass(cls, ImporterPlugin): # Override name - always use entry point's name cls.name = ep.name - importer = cls(dist_name=dist_name, dist_version=dist.version) + importer = cls(dist_name=dist_name, dist_version=dist_version) else: raise RuntimeError(f"Importer class {cls} is expected to be extended from peakrdl.plugins.importer.ImporterPlugin") importers.append(importer) diff --git a/src/peakrdl/process_input.py b/peakrdl-cli/src/peakrdl/process_input.py similarity index 92% rename from src/peakrdl/process_input.py rename to peakrdl-cli/src/peakrdl/process_input.py index a533e54..216a3d1 100644 --- a/src/peakrdl/process_input.py +++ b/peakrdl-cli/src/peakrdl/process_input.py @@ -6,7 +6,7 @@ if TYPE_CHECKING: import argparse - from typing import Sequence + from typing import Sequence, Optional from systemrdl import RDLCompiler, AddrmapNode from .importer import Importer @@ -73,6 +73,7 @@ def parse_parameters(rdlc: 'RDLCompiler', parameter_options: List[str]) -> Dict[ m = re.fullmatch(r"(\w+)=(.+)", raw_param) if not m: rdlc.msg.fatal(f"Invalid parameter argument: {raw_param}") + raise ValueError p_name = m.group(1) try: @@ -89,6 +90,7 @@ def parse_defines(rdlc: 'RDLCompiler', define_options: List[str]) -> Dict[str, s m = re.fullmatch(r"(\w+)(?:=(.+))?", raw_def) if not m: rdlc.msg.fatal(f"Invalid define argument: {raw_def}") + raise ValueError k = m.group(1) v = m.group(2) or "" @@ -116,12 +118,11 @@ def process_input(rdlc: 'RDLCompiler', importers: 'Sequence[Importer]', input_fi # Search which importer to use by extension first importer_candidates = [] # type: List[Importer] - for importer in importers: - if ext in importer.file_extensions: - importer_candidates.append(importer) + for imp in importers: + if ext in imp.file_extensions: + importer_candidates.append(imp) # Do 2nd pass if needed - importer = None if len(importer_candidates) == 1: importer = importer_candidates[0] elif len(importer_candidates) > 1: @@ -131,12 +132,17 @@ def process_input(rdlc: 'RDLCompiler', importers: 'Sequence[Importer]', input_fi if importer_candidate.is_compatible(file): importer = importer_candidate break + else: + importer = None + else: + importer = None if not importer: rdlc.msg.fatal( "Unknown file type. Could not find any importers capable of reading this file.", FileSourceRef(file) ) + raise ValueError importer.do_import(rdlc, options, file) diff --git a/src/peakrdl/py.typed b/peakrdl-cli/src/peakrdl/py.typed similarity index 100% rename from src/peakrdl/py.typed rename to peakrdl-cli/src/peakrdl/py.typed diff --git a/src/peakrdl/subcommand.py b/peakrdl-cli/src/peakrdl/subcommand.py similarity index 100% rename from src/peakrdl/subcommand.py rename to peakrdl-cli/src/peakrdl/subcommand.py diff --git a/peakrdl/LICENSE b/peakrdl/LICENSE new file mode 120000 index 0000000..ea5b606 --- /dev/null +++ b/peakrdl/LICENSE @@ -0,0 +1 @@ +../LICENSE \ No newline at end of file diff --git a/peakrdl/README.md b/peakrdl/README.md new file mode 120000 index 0000000..32d46ee --- /dev/null +++ b/peakrdl/README.md @@ -0,0 +1 @@ +../README.md \ No newline at end of file diff --git a/peakrdl/peakrdl_toolchain.py b/peakrdl/peakrdl_toolchain.py new file mode 120000 index 0000000..ca63299 --- /dev/null +++ b/peakrdl/peakrdl_toolchain.py @@ -0,0 +1 @@ +../peakrdl-cli/src/peakrdl/__about__.py \ No newline at end of file diff --git a/peakrdl/pyproject.toml b/peakrdl/pyproject.toml new file mode 100644 index 0000000..1c2f97e --- /dev/null +++ b/peakrdl/pyproject.toml @@ -0,0 +1,55 @@ +[build-system] +requires = ["setuptools", "setuptools-scm"] +build-backend = "setuptools.build_meta" + +[project] +name = "peakrdl" +dynamic = ["version"] +requires-python = ">=3.6" +dependencies = [ + "peakrdl-cli", + "peakrdl-html >= 2.10.1, < 3", + "peakrdl-ipxact >= 3.4.1, < 4", + "peakrdl-regblock >= 0.19.0, < 2", + "peakrdl-systemrdl >= 0.3.0, < 2", + "peakrdl-uvm >= 2.3.0, < 3", + "peakrdl-cheader >= 1.0.0, < 2", +] + +authors = [ + {name="Alex Mykyta"}, +] +description = "Toolchain for control/status register automation and code generation." +readme = "README.md" +license = {file = "LICENSE"} +keywords = [ + "SystemRDL", "PeakRDL", "CSR", "compiler", "tool", "registers", "generator", + "C", "header", "software", "Verilog", "SystemVerilog", "register abstraction layer", + "FPGA", "ASIC", +] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3 :: Only", + "Intended Audience :: Developers", + "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", + "Operating System :: OS Independent", + "Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)", +] + +[project.urls] +Source = "https://github.com/SystemRDL/PeakRDL" +Tracker = "https://github.com/SystemRDL/PeakRDL/issues" +Changelog = "https://github.com/SystemRDL/PeakRDL/releases" +Documentation = "https://peakrdl.readthedocs.io/" + +[tool.setuptools.dynamic] +version = {attr = "peakrdl_toolchain.__version__"} diff --git a/src/peakrdl/__about__.py b/src/peakrdl/__about__.py deleted file mode 100644 index 6849410..0000000 --- a/src/peakrdl/__about__.py +++ /dev/null @@ -1 +0,0 @@ -__version__ = "1.1.0" diff --git a/test/run.sh b/test/run.sh index 4e1169b..6b08814 100755 --- a/test/run.sh +++ b/test/run.sh @@ -1,31 +1,27 @@ #!/bin/bash set -e - -this_dir="$( cd "$(dirname "$0")" ; pwd -P )" +cd "$(dirname "$0")" # Initialize venv -venv_bin=$this_dir/.venv/bin -python3 -m venv $this_dir/.venv -source $venv_bin/activate +python3 -m venv .venv +source .venv/bin/activate # Install test dependencies -python -m pip install -U pip setuptools wheel -python -m pip install -U pytest pytest-cov coverage pylint mypy +python -m pip install -r requirements.txt -# Install dut -cd $this_dir/../ -python -m pip install . -cd $this_dir +# Install CLI first, then bundle toolchain pkg +python -m pip install ../peakrdl-cli/ +python -m pip install ../peakrdl/ # Run unit tests while collecting coverage pytest --cov=peakrdl # Generate coverage report -coverage html -i -d $this_dir/htmlcov +coverage html -i -d htmlcov # Run lint -pylint --rcfile $this_dir/pylint.rc ../src/peakrdl +pylint --rcfile pylint.rc ../peakrdl-cli/src/peakrdl # Run static type checking -mypy $this_dir/../src/peakrdl +mypy ../peakrdl-cli/src/peakrdl diff --git a/test/test_core_commands.py b/test/test_core_commands.py index 06b160e..06a7a75 100644 --- a/test/test_core_commands.py +++ b/test/test_core_commands.py @@ -156,38 +156,6 @@ def test_globals(self): ]) self.assertEqual(captured.out, expected) - def test_uvm(self): - path = self.get_output_dir() - self.run_commandline([ - 'uvm', - os.path.join(self.testdata_dir, "structural.rdl"), - '-o', os.path.join(path, "out.sv"), - ]) - - def test_regblock(self): - path = self.get_output_dir() - self.run_commandline([ - 'regblock', - os.path.join(self.testdata_dir, "structural.rdl"), - '-o', path, - ]) - - def test_ipxact(self): - path = self.get_output_dir() - self.run_commandline([ - 'ip-xact', - os.path.join(self.testdata_dir, "structural.rdl"), - '-o', os.path.join(path, "out.xml"), - ]) - - def test_html(self): - path = self.get_output_dir() - self.run_commandline([ - 'html', - os.path.join(self.testdata_dir, "structural.rdl"), - '-o', path, - ]) - def test_preprocess(self): path = self.get_output_dir() self.run_commandline([