diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index bae679c8e..777969cc3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,3 +24,11 @@ repos: - id: ruff args: [--fix] - id: ruff-format +- repo: local + hooks: + - id: check-spdx + name: Check SPDX Headers + entry: python ./toolshed/check_spdx.py + language: python + additional_dependencies: + - pathspec==0.12.1 diff --git a/.spdx-ignore b/.spdx-ignore new file mode 100644 index 000000000..276bc5cd5 --- /dev/null +++ b/.spdx-ignore @@ -0,0 +1,34 @@ +LICENSE +LICENSE.numba +*.html +*.json +*.md +*.png +*.svg +*.rst +*.txt +*.ptx +*.pyc +requirements*.txt + +# Documentation build artifacts +docs/build/* + +# Binary files +*.so +*.dll + +# Build artifacts and egg-info +build/* +dist/* +*.egg-info/* + +# Version files +numba_cuda/VERSION + +# External CUDA SDK headers +numba_cuda/numba/cuda/include/*/cuda_*.h +numba_cuda/numba/cuda/include/*/cuda_*.hpp + +# GitHub configuration files +.github/CODEOWNERS diff --git a/numba_cuda/numba/cuda/core/bytecode.py b/numba_cuda/numba/cuda/core/bytecode.py index cdef26dd0..ce5d0ba85 100644 --- a/numba_cuda/numba/cuda/core/bytecode.py +++ b/numba_cuda/numba/cuda/core/bytecode.py @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-2-Clause + from collections import namedtuple, OrderedDict import dis import inspect diff --git a/numba_cuda/numba/cuda/core/environment.py b/numba_cuda/numba/cuda/core/environment.py index a1d318e04..f58c669f0 100644 --- a/numba_cuda/numba/cuda/core/environment.py +++ b/numba_cuda/numba/cuda/core/environment.py @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-2-Clause + import weakref import importlib diff --git a/toolshed/check_spdx.py b/toolshed/check_spdx.py new file mode 100644 index 000000000..619840ebf --- /dev/null +++ b/toolshed/check_spdx.py @@ -0,0 +1,57 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-2-Clause + +import os +import sys + +import pathspec + +# Intentionally puzzling together EXPECTED_SPDX_BYTES so that we don't overlook +# if the identifiers are missing in this file. +EXPECTED_SPDX_BYTES = ( + b"-".join((b"SPDX", b"License", b"Identifier: ")), + b"-".join((b"SPDX", b"FileCopyrightText: ")), +) + +SPDX_IGNORE_FILENAME = ".spdx-ignore" + + +def load_spdx_ignore(): + if os.path.exists(SPDX_IGNORE_FILENAME): + with open(SPDX_IGNORE_FILENAME, "r", encoding="utf-8") as f: + lines = f.readlines() + else: + lines = [] + lines.append(SPDX_IGNORE_FILENAME + "\n") + return pathspec.PathSpec.from_lines("gitwildmatch", lines) + + +def has_spdx_or_is_empty(filepath): + with open(filepath, "rb") as f: + blob = f.read() + if len(blob.strip()) == 0: + return True + good = True + for expected_bytes in EXPECTED_SPDX_BYTES: + if expected_bytes not in blob: + print(f"MISSING {expected_bytes.decode()}{filepath!r}") + good = False + return good + + +def main(args): + assert args, "filepaths expected to be passed from pre-commit" + + ignore_spec = load_spdx_ignore() + + returncode = 0 + for filepath in args: + if ignore_spec.match_file(filepath): + continue + if not has_spdx_or_is_empty(filepath): + returncode = 1 + return returncode + + +if __name__ == "__main__": + sys.exit(main(sys.argv[1:]))