From 89be0e67373b34203200cf5a5071d0cd514b5ce0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Nguyen?= Date: Tue, 26 Jul 2022 13:01:31 +0200 Subject: [PATCH] Add support for remote builds over SSH. The Amaranth build system already supports remote builds over SSH. This commit integrates it to the 'build' command. Also: * update dependencies * add paramiko as a dependency (the SSH library used by amaranth) --- poetry.lock | 128 +++++++++++++++++++++++++++++++++---- power_fv/check/__init__.py | 19 +++++- pyproject.toml | 1 + 3 files changed, 131 insertions(+), 17 deletions(-) diff --git a/poetry.lock b/poetry.lock index ccce1fe..ce6dbae 100644 --- a/poetry.lock +++ b/poetry.lock @@ -40,9 +40,54 @@ url = "https://github.com/amaranth-lang/amaranth-soc.git" reference = "main" resolved_reference = "217d4ea76ad3b3bbf146980d168bc7b3b9d95a18" +[[package]] +name = "bcrypt" +version = "3.2.2" +description = "Modern password hashing for your software and your servers" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +cffi = ">=1.1" + +[package.extras] +tests = ["pytest (>=3.2.1,!=3.3.0)"] +typecheck = ["mypy"] + +[[package]] +name = "cffi" +version = "1.15.1" +description = "Foreign Function Interface for Python calling C code." +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "cryptography" +version = "37.0.4" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +cffi = ">=1.12" + +[package.extras] +docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"] +docstest = ["pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"] +pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"] +sdist = ["setuptools_rust (>=0.11.4)"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-subtests", "pytest-xdist", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,!=3.79.2)"] + [[package]] name = "importlib-resources" -version = "5.8.0" +version = "5.9.0" description = "Read resources from Python packages" category = "main" optional = false @@ -52,8 +97,8 @@ python-versions = ">=3.7" zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} [package.extras] -docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"] +docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "jaraco.tidelift (>=1.4)"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"] [[package]] name = "jinja2" @@ -77,6 +122,49 @@ category = "main" optional = false python-versions = ">=3.7" +[[package]] +name = "paramiko" +version = "2.11.0" +description = "SSH2 protocol library" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +bcrypt = ">=3.1.3" +cryptography = ">=2.5" +pynacl = ">=1.0.1" +six = "*" + +[package.extras] +all = ["pyasn1 (>=0.1.7)", "pynacl (>=1.0.1)", "bcrypt (>=3.1.3)", "invoke (>=1.3)", "gssapi (>=1.4.1)", "pywin32 (>=2.1.8)"] +ed25519 = ["pynacl (>=1.0.1)", "bcrypt (>=3.1.3)"] +gssapi = ["pyasn1 (>=0.1.7)", "gssapi (>=1.4.1)", "pywin32 (>=2.1.8)"] +invoke = ["invoke (>=1.3)"] + +[[package]] +name = "pycparser" +version = "2.21" +description = "C parser in Python" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "pynacl" +version = "1.5.0" +description = "Python binding to the Networking and Cryptography (NaCl) library" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +cffi = ">=1.4.1" + +[package.extras] +docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"] +tests = ["pytest (>=3.2.1,!=3.3.0)", "hypothesis (>=3.27.0)"] + [[package]] name = "pyvcd" version = "0.3.0" @@ -85,30 +173,38 @@ category = "main" optional = false python-versions = ">=3.6" +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" + [[package]] name = "zipp" -version = "3.8.0" +version = "3.8.1" description = "Backport of pathlib-compatible object wrapper for zip files" category = "main" optional = false python-versions = ">=3.7" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"] +docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "jaraco.tidelift (>=1.4)"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.3)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"] [metadata] lock-version = "1.1" python-versions = "^3.8" -content-hash = "1c881976fce28a8b6924ba8df05bfa648b0c6098b5489df50523e968a6bfce73" +content-hash = "dbe5d4b6f3f9f50a181376ba964a74b5b4bffa75f0cbc0dd1ca7e23c81d5506a" [metadata.files] amaranth = [] amaranth-soc = [] -importlib-resources = [ - {file = "importlib_resources-5.8.0-py3-none-any.whl", hash = "sha256:7952325ffd516c05a8ad0858c74dff2c3343f136fe66a6002b2623dd1d43f223"}, - {file = "importlib_resources-5.8.0.tar.gz", hash = "sha256:568c9f16cb204f9decc8d6d24a572eeea27dacbb4cee9e6b03a8025736769751"}, -] +bcrypt = [] +cffi = [] +cryptography = [] +importlib-resources = [] jinja2 = [ {file = "Jinja2-3.0.3-py3-none-any.whl", hash = "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8"}, {file = "Jinja2-3.0.3.tar.gz", hash = "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7"}, @@ -155,11 +251,15 @@ markupsafe = [ {file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"}, {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"}, ] +paramiko = [] +pycparser = [] +pynacl = [] pyvcd = [ {file = "pyvcd-0.3.0-py2.py3-none-any.whl", hash = "sha256:971dfe5a3e68663115c6edf3f0b611ff9e8427513db16281eb4516ebcd65a336"}, {file = "pyvcd-0.3.0.tar.gz", hash = "sha256:ec4d9198bd20f9e07d78f6558ff8bcd45b172ee332e7e8a4588727eeb6a362bc"}, ] -zipp = [ - {file = "zipp-3.8.0-py3-none-any.whl", hash = "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099"}, - {file = "zipp-3.8.0.tar.gz", hash = "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad"}, +six = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] +zipp = [] diff --git a/power_fv/check/__init__.py b/power_fv/check/__init__.py index 881f8ad..e181d25 100644 --- a/power_fv/check/__init__.py +++ b/power_fv/check/__init__.py @@ -1,3 +1,5 @@ +import json + from abc import ABCMeta, abstractmethod from pathlib import Path @@ -53,6 +55,10 @@ class PowerFVCheck(metaclass=PowerFVCheckMeta): parser.add_argument( "--build-dir", type=Path, default=Path("./build"), help="output directory (default: %(default)s)") + parser.add_argument( + "--connect-to", type=json.loads, required=False, + help="execute the build plan on a remote server using SSH " + "(JSON string of arguments passed to paramiko's SSHClient.connect)") def __init__(self, *, depth, skip, cover, core, **kwargs): self.depth = depth @@ -65,15 +71,22 @@ class PowerFVCheck(metaclass=PowerFVCheckMeta): def testbench(self): raise NotImplementedError - def build(self, *, build_dir, **kwargs): + def build(self, *, build_dir, connect_to=None, **kwargs): platform = sby.SymbiYosysPlatform() self.core.add_files(platform, self.dut, **kwargs) top = self.testbench() - build_dir = build_dir / top.name + build_dir = str(build_dir / top.name) overrides = {key: str(value) for key, value in kwargs.items()} overrides["depth"] = str(self.depth) overrides["skip"] = str(self.skip) overrides["mode"] = "cover" if self.cover else "bmc" - return platform.build(top, name=top.name, build_dir=build_dir, **overrides) + plan = platform.build(top, name=top.name, build_dir=build_dir, do_build=False, **overrides) + + if connect_to is not None: + products = plan.execute_remote_ssh(connect_to=connect_to, root=build_dir) + else: + products = plan.execute_local(build_dir) + + return products diff --git a/pyproject.toml b/pyproject.toml index 4a9b1d2..6f62656 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,6 +8,7 @@ license = "BSD" [tool.poetry.dependencies] python = "^3.8" jinja2 = "~3.0" +paramiko = "~2.11" amaranth = {git = "https://github.com/amaranth-lang/amaranth.git", branch="main"} amaranth_soc = {git = "https://github.com/amaranth-lang/amaranth-soc.git", branch="main"}