diff --git a/.github/workflows/Dockerfile b/.github/workflows/Dockerfile new file mode 100644 index 0000000..547ae88 --- /dev/null +++ b/.github/workflows/Dockerfile @@ -0,0 +1,9 @@ +ARG BASEOS=slim-bullseye +FROM python:3.11-${BASEOS} + +ARG PLATFORM=manylinux +ENV CI=1 +COPY test /src/test +COPY wheelhouse/clang*${PLATFORM}*.whl /tmp +RUN python -m pip install pytest /tmp/*whl \ + && pytest -vs /src/test diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1f17b71..4106d39 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,12 +31,22 @@ jobs: strategy: matrix: include: - - os: ubuntu-20.04 + - os: ubuntu-22.04 arch: "x86_64" use_qemu: false - - os: ubuntu-20.04 + skip: "*manylinux*" + - os: ubuntu-22.04 + arch: "x86_64" + use_qemu: false + skip: "*musllinux*" + - os: ubuntu-22.04 arch: "i686" use_qemu: false + skip: "*manylinux*" + - os: ubuntu-22.04 + arch: "i686" + use_qemu: false + skip: "*musllinux*" # These take too long to build on Github #- os: ubuntu-20.04 #arch: "aarch64" @@ -47,15 +57,18 @@ jobs: #- os: ubuntu-20.04 #arch: "s390x" #use_qemu: true - - os: windows-2019 + - os: windows-2022 arch: "AMD64" use_qemu: false - - os: windows-2019 + skip: "" + - os: windows-2022 arch: "x86" use_qemu: false - - os: macos-10.15 + skip: "" + - os: macos-12 arch: "universal2" use_qemu: false + skip: "" steps: - uses: actions/checkout@v3 @@ -65,6 +78,10 @@ jobs: if: runner.os == 'Windows' && ((!matrix.use_qemu) || fromJSON(env.USE_QEMU)) run: git config --system core.longpaths true + - name: Export macOS SDKROOT + if: runner.os == 'macOS' + run: echo SDKROOT=$(xcrun --sdk macosx --show-sdk-path) >> $GITHUB_ENV + - name: Override LLVM version (${{ github.event.inputs.llvm_version }}) if: github.event.inputs.llvm_version run: | @@ -76,11 +93,22 @@ jobs: if: runner.os == 'Linux' && ((matrix.use_qemu) && fromJSON(env.USE_QEMU)) - name: Build wheels - uses: pypa/cibuildwheel@v2.7.0 + uses: pypa/cibuildwheel@v2.8.1 if: (!matrix.use_qemu) || fromJSON(env.USE_QEMU) env: CIBW_ARCHS: "${{ matrix.arch }}" - + CIBW_BEFORE_TEST: rm -rf {package}/clang_tidy + CIBW_TEST_SKIP: "*linux*" + CIBW_SKIP: "${{matrix.skip}}" + # clang-tidy simply does not want to cooperate with the github linux image + - name: Test Linux Wheel + if: runner.os == 'Linux' && !(matrix.use_qemu) && matrix.arch == 'x86_64' + run: | + if [[ "${{matrix.skip}}" == "*manylinux*" ]] ; then + docker build --build-arg BASEOS=alpine3.16 --build-arg PLATFORM=musllinux -f .github/workflows/Dockerfile . + else + docker build --build-arg BASEOS=slim-bullseye --build-arg PLATFORM=manylinux -f .github/workflows/Dockerfile . + fi - uses: actions/upload-artifact@v3 if: (!matrix.use_qemu) || fromJSON(env.USE_QEMU) with: @@ -88,7 +116,7 @@ jobs: build-sdist: name: Build source distribution - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v3 @@ -109,7 +137,7 @@ jobs: test-sdist: name: Test build from source distribution needs: [build-sdist] - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v3 @@ -125,7 +153,9 @@ jobs: path: sdist - name: Install from SDist - run: + run: | + # make sure the test will not pick this up + rm -r clang_tidy pip install sdist/*.tar.gz - name: Install test requirements @@ -139,7 +169,7 @@ jobs: upload_pypi: name: Upload to PyPI needs: [build-wheels, build-sdist, test-sdist] - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 if: github.repository_owner == 'ssciwr' steps: diff --git a/.gitignore b/.gitignore index e26b198..0f2ecc0 100644 --- a/.gitignore +++ b/.gitignore @@ -180,3 +180,8 @@ install_manifest.txt compile_commands.json CTestTestfile.cmake _deps + +# scikit-build cache +_skbuild/ + +clang_tidy/data/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 53297cd..d0fa8ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,3 +41,9 @@ install( ${clang-tidy-executable} DESTINATION clang_tidy/data/bin ) + +install( + DIRECTORY + ${CMAKE_BINARY_DIR}/llvm/lib/clang/${CLANG_TIDY_VERSION}/include + DESTINATION clang_tidy/data/lib/clang/${CLANG_TIDY_VERSION} +) diff --git a/clang_tidy/__init__.py b/clang_tidy/__init__.py index 21d036f..d5d33eb 100644 --- a/clang_tidy/__init__.py +++ b/clang_tidy/__init__.py @@ -1,20 +1,39 @@ -import os import subprocess import sys +from pathlib import Path +import functools +import pkg_resources + + +@functools.lru_cache(maxsize=None) +def _get_executable(name:str) -> Path: + possibles = [Path(pkg_resources.resource_filename('clang_tidy', f"data/bin/{name}{s}")) + for s in ("", ".exe", ".bin", ".dmg")] + for exe in possibles: + if exe.exists(): + print(f'Resource filename: {exe} ') + return exe + + raise FileNotFoundError(f"No executable found for {name} at\n{possibles}") + +def _run(name, *args): + command = [_get_executable(name)] + if args: + command += list(args) + else: + command += sys.argv[1:] + return subprocess.call(command) + +def _run_python(name, *args): + command = [sys.executable, _get_executable(name)] + if args: + command += list(args) + else: + command += sys.argv[1:] - -def _get_executable(name): - return os.path.join(os.path.dirname(__file__), "data", "bin", name) - -def _run(name): - executable = _get_executable(name) - return subprocess.call([executable] + sys.argv[1:]) - -def _run_python(name): - script = _get_executable(name) # as MS Windows is not able to run Python scripts directly by name, # we have to call the interpreter and pass the script as parameter - return subprocess.call([sys.executable, script] + sys.argv[1:]) + return subprocess.call(command) def clang_tidy(): diff --git a/test/test_empty.py b/test/test_empty.py deleted file mode 100644 index a3e981b..0000000 --- a/test/test_empty.py +++ /dev/null @@ -1,2 +0,0 @@ -def test_nothing(): - pass diff --git a/test/test_executable.py b/test/test_executable.py new file mode 100644 index 0000000..36f8317 --- /dev/null +++ b/test/test_executable.py @@ -0,0 +1,52 @@ +import os +import sys +import tempfile +from pathlib import Path + +import pytest + + +@pytest.fixture(autouse=True) +def ensure_tidy_from_wheel(monkeypatch): + """test the installed clang_tidy package, not the local one""" + this_dir = Path(__file__).resolve().absolute().parent + for pd in (this_dir, this_dir / ".."): + try: + new_path = sys.path.remove(pd) + monkeypatch.setattr(sys, "path", new_path) + except ValueError: + pass + monkeypatch.delitem(sys.modules, "clang_tidy", raising=False) + + +def test_executable_file(): + import clang_tidy + + exe = clang_tidy._get_executable("clang-tidy") + assert os.path.exists(exe) + assert os.access(exe, os.X_OK) + + +def _test_code(code: str): + import clang_tidy + + fd, compilation_unit = tempfile.mkstemp(suffix=".cpp") + os.close(fd) + with open(compilation_unit, "w") as ostr: + ostr.write(code) + try: + assert clang_tidy._run("clang-tidy", "--extra-arg=-v", compilation_unit) == 0 + finally: + os.remove(compilation_unit) + + +@pytest.mark.skipif( + os.environ.get("CI", None) and "linux" in sys.platform, + reason="https://github.com/ssciwr/clang-tidy-wheel/issues/30", +) +def test_include_iostream(): + _test_code("#include \n") + + +def test_main(): + _test_code("int main() { return 0;}\n")