diff --git a/cuda_core/cuda/core/_include/layout.hpp b/cuda_core/cuda/core/_include/layout.hpp index ad3a2c6ffd..b5da219df3 100644 --- a/cuda_core/cuda/core/_include/layout.hpp +++ b/cuda_core/cuda/core/_include/layout.hpp @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. // All rights reserved. // -// SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +// SPDX-License-Identifier: Apache-2.0 #ifndef CUDA_CORE_LAYOUT_HPP #define CUDA_CORE_LAYOUT_HPP diff --git a/cuda_core/cuda/core/_include/utility.hpp b/cuda_core/cuda/core/_include/utility.hpp index aa83a465e3..64b357ac32 100644 --- a/cuda_core/cuda/core/_include/utility.hpp +++ b/cuda_core/cuda/core/_include/utility.hpp @@ -1,6 +1,6 @@ // SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // -// SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +// SPDX-License-Identifier: Apache-2.0 #pragma once diff --git a/cuda_core/cuda/core/_utils/__init__.py b/cuda_core/cuda/core/_utils/__init__.py index bd8faf14fa..79599c77db 100644 --- a/cuda_core/cuda/core/_utils/__init__.py +++ b/cuda_core/cuda/core/_utils/__init__.py @@ -1,3 +1,3 @@ # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 diff --git a/cuda_core/cuda/core/_utils/clear_error_support.py b/cuda_core/cuda/core/_utils/clear_error_support.py index 0410e7aa2f..56c74ea955 100644 --- a/cuda_core/cuda/core/_utils/clear_error_support.py +++ b/cuda_core/cuda/core/_utils/clear_error_support.py @@ -1,6 +1,6 @@ # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 def assert_type(obj, expected_type): diff --git a/cuda_core/cuda/core/_utils/driver_cu_result_explanations.py b/cuda_core/cuda/core/_utils/driver_cu_result_explanations.py index f4894d7563..76c6cc534a 100644 --- a/cuda_core/cuda/core/_utils/driver_cu_result_explanations.py +++ b/cuda_core/cuda/core/_utils/driver_cu_result_explanations.py @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 from cuda.bindings import driver from cuda.core._utils.enum_explanations_helpers import get_best_available_explanations diff --git a/cuda_core/cuda/core/_utils/driver_cu_result_explanations_frozen.py b/cuda_core/cuda/core/_utils/driver_cu_result_explanations_frozen.py index e396afaa79..567b969038 100644 --- a/cuda_core/cuda/core/_utils/driver_cu_result_explanations_frozen.py +++ b/cuda_core/cuda/core/_utils/driver_cu_result_explanations_frozen.py @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 # CUDA Toolkit v13.1.1 _FALLBACK_EXPLANATIONS = { diff --git a/cuda_core/cuda/core/_utils/enum_explanations_helpers.py b/cuda_core/cuda/core/_utils/enum_explanations_helpers.py index a176de73d1..c7927e71e4 100644 --- a/cuda_core/cuda/core/_utils/enum_explanations_helpers.py +++ b/cuda_core/cuda/core/_utils/enum_explanations_helpers.py @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 """Internal support for error-enum explanations. diff --git a/cuda_core/cuda/core/_utils/runtime_cuda_error_explanations.py b/cuda_core/cuda/core/_utils/runtime_cuda_error_explanations.py index ab5be10e2d..1fa2226c54 100644 --- a/cuda_core/cuda/core/_utils/runtime_cuda_error_explanations.py +++ b/cuda_core/cuda/core/_utils/runtime_cuda_error_explanations.py @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 from cuda.bindings import runtime from cuda.core._utils.enum_explanations_helpers import get_best_available_explanations diff --git a/cuda_core/cuda/core/_utils/runtime_cuda_error_explanations_frozen.py b/cuda_core/cuda/core/_utils/runtime_cuda_error_explanations_frozen.py index 497b2ad20d..017c408740 100644 --- a/cuda_core/cuda/core/_utils/runtime_cuda_error_explanations_frozen.py +++ b/cuda_core/cuda/core/_utils/runtime_cuda_error_explanations_frozen.py @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 # CUDA Toolkit v13.1.1 _FALLBACK_EXPLANATIONS = { diff --git a/cuda_core/pytest.ini b/cuda_core/pytest.ini index df1963f383..41bf0d9c4f 100644 --- a/cuda_core/pytest.ini +++ b/cuda_core/pytest.ini @@ -1,6 +1,6 @@ # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 [pytest] addopts = --showlocals diff --git a/cuda_core/tests/cython/test_cython.py b/cuda_core/tests/cython/test_cython.py index a118249043..87b97e8a2a 100644 --- a/cuda_core/tests/cython/test_cython.py +++ b/cuda_core/tests/cython/test_cython.py @@ -1,6 +1,6 @@ # SPDX-FileCopyrightText: Copyright (c) 2021-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 import functools import importlib diff --git a/cuda_core/tests/cython/test_get_cuda_native_handle.pyx b/cuda_core/tests/cython/test_get_cuda_native_handle.pyx index 2b105e13ae..1480a3b96b 100644 --- a/cuda_core/tests/cython/test_get_cuda_native_handle.pyx +++ b/cuda_core/tests/cython/test_get_cuda_native_handle.pyx @@ -1,6 +1,6 @@ # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 # distutils: language = c++ # distutils: extra_compile_args = -std=c++17 diff --git a/cuda_core/tests/graph/test_device_launch.py b/cuda_core/tests/graph/test_device_launch.py index 21e58cb673..0bd4ba1263 100644 --- a/cuda_core/tests/graph/test_device_launch.py +++ b/cuda_core/tests/graph/test_device_launch.py @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 """Tests for device-side graph launch (GPU kernel launching a CUDA graph).""" diff --git a/cuda_core/tests/graph/test_graph_builder.py b/cuda_core/tests/graph/test_graph_builder.py index 3f9b8e91d1..aca5a83ecf 100644 --- a/cuda_core/tests/graph/test_graph_builder.py +++ b/cuda_core/tests/graph/test_graph_builder.py @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 """GraphBuilder stream capture tests.""" diff --git a/cuda_core/tests/graph/test_graph_builder_conditional.py b/cuda_core/tests/graph/test_graph_builder_conditional.py index e34186fb14..1446b8b3c4 100644 --- a/cuda_core/tests/graph/test_graph_builder_conditional.py +++ b/cuda_core/tests/graph/test_graph_builder_conditional.py @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 """Tests for GraphBuilder conditional node capture (if, if-else, switch, while).""" diff --git a/cuda_core/tests/graph/test_graph_memory_resource.py b/cuda_core/tests/graph/test_graph_memory_resource.py index fe47ef2d68..13e6745d74 100644 --- a/cuda_core/tests/graph/test_graph_memory_resource.py +++ b/cuda_core/tests/graph/test_graph_memory_resource.py @@ -1,6 +1,6 @@ # SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 """Tests for GraphMemoryResource allocation and attributes during graph capture.""" diff --git a/cuda_core/tests/graph/test_graph_update.py b/cuda_core/tests/graph/test_graph_update.py index 8e7881f8e9..d06333afff 100644 --- a/cuda_core/tests/graph/test_graph_update.py +++ b/cuda_core/tests/graph/test_graph_update.py @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 """Tests for whole-graph update (Graph.update).""" diff --git a/cuda_core/tests/graph/test_graphdef.py b/cuda_core/tests/graph/test_graphdef.py index b5c76013bd..e81c0b03b9 100644 --- a/cuda_core/tests/graph/test_graphdef.py +++ b/cuda_core/tests/graph/test_graphdef.py @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 """Tests for GraphDef topology, node types, instantiation, and execution.""" diff --git a/cuda_core/tests/graph/test_graphdef_errors.py b/cuda_core/tests/graph/test_graphdef_errors.py index b8fe1f6dc5..54b28d7a5c 100644 --- a/cuda_core/tests/graph/test_graphdef_errors.py +++ b/cuda_core/tests/graph/test_graphdef_errors.py @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 """Tests for GraphDef input validation, error handling, and edge cases.""" diff --git a/cuda_core/tests/graph/test_graphdef_integration.py b/cuda_core/tests/graph/test_graphdef_integration.py index 243c93433c..3fc0263c95 100644 --- a/cuda_core/tests/graph/test_graphdef_integration.py +++ b/cuda_core/tests/graph/test_graphdef_integration.py @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 """End-to-end integration tests exercising all GraphDef node types in realistic scenarios.""" diff --git a/cuda_core/tests/graph/test_graphdef_lifetime.py b/cuda_core/tests/graph/test_graphdef_lifetime.py index 21d519bb89..a9b3003077 100644 --- a/cuda_core/tests/graph/test_graphdef_lifetime.py +++ b/cuda_core/tests/graph/test_graphdef_lifetime.py @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 """Tests for GraphDef resource lifetime management and RAII correctness.""" diff --git a/cuda_core/tests/graph/test_graphdef_mutation.py b/cuda_core/tests/graph/test_graphdef_mutation.py index 5c8d9434dd..2f9dd442da 100644 --- a/cuda_core/tests/graph/test_graphdef_mutation.py +++ b/cuda_core/tests/graph/test_graphdef_mutation.py @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 """Tests for mutating a graph definition (edge changes, node removal).""" diff --git a/cuda_core/tests/graph/test_options.py b/cuda_core/tests/graph/test_options.py index 33d647f6fe..0d10db459d 100644 --- a/cuda_core/tests/graph/test_options.py +++ b/cuda_core/tests/graph/test_options.py @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 """Graph options and build mode tests.""" diff --git a/cuda_core/tests/helpers/collection_interface_testers.py b/cuda_core/tests/helpers/collection_interface_testers.py index d9b5ee2cd0..5197e475c1 100644 --- a/cuda_core/tests/helpers/collection_interface_testers.py +++ b/cuda_core/tests/helpers/collection_interface_testers.py @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 """Reusable helpers to verify collections.abc protocol conformance.""" diff --git a/cuda_core/tests/helpers/graph_kernels.py b/cuda_core/tests/helpers/graph_kernels.py index 657d7509b2..c7d0ed766a 100644 --- a/cuda_core/tests/helpers/graph_kernels.py +++ b/cuda_core/tests/helpers/graph_kernels.py @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 """Shared kernel compilation helpers for graph tests.""" diff --git a/cuda_core/tests/helpers/marks.py b/cuda_core/tests/helpers/marks.py index 5474c862ba..53fcc544eb 100644 --- a/cuda_core/tests/helpers/marks.py +++ b/cuda_core/tests/helpers/marks.py @@ -1,5 +1,5 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 """Reusable pytest marks for cuda_core tests.""" diff --git a/cuda_core/tests/test_cuda_utils.py b/cuda_core/tests/test_cuda_utils.py index 1357ca3a12..be22e57998 100644 --- a/cuda_core/tests/test_cuda_utils.py +++ b/cuda_core/tests/test_cuda_utils.py @@ -1,6 +1,6 @@ # SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 import dataclasses diff --git a/cuda_core/tests/test_helpers.py b/cuda_core/tests/test_helpers.py index bd13ed5067..23a5b71c85 100644 --- a/cuda_core/tests/test_helpers.py +++ b/cuda_core/tests/test_helpers.py @@ -1,6 +1,6 @@ # SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 import time diff --git a/cuda_core/tests/test_linker.py b/cuda_core/tests/test_linker.py index c36903ab32..30a6a03349 100644 --- a/cuda_core/tests/test_linker.py +++ b/cuda_core/tests/test_linker.py @@ -1,6 +1,6 @@ # SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 import pytest diff --git a/cuda_core/tests/test_optional_dependency_imports.py b/cuda_core/tests/test_optional_dependency_imports.py index 730c6e7834..02edcc9839 100644 --- a/cuda_core/tests/test_optional_dependency_imports.py +++ b/cuda_core/tests/test_optional_dependency_imports.py @@ -1,6 +1,6 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 import pytest diff --git a/cuda_core/tests/test_program.py b/cuda_core/tests/test_program.py index ac40fb735d..a062f3714e 100644 --- a/cuda_core/tests/test_program.py +++ b/cuda_core/tests/test_program.py @@ -1,6 +1,6 @@ # SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 import contextlib import re diff --git a/cuda_core/tests/test_utils.py b/cuda_core/tests/test_utils.py index 59829f8fb3..4bdebcbde3 100644 --- a/cuda_core/tests/test_utils.py +++ b/cuda_core/tests/test_utils.py @@ -1,6 +1,6 @@ # SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 import ctypes import math diff --git a/cuda_core/tests/test_utils_enum_explanations_helpers.py b/cuda_core/tests/test_utils_enum_explanations_helpers.py index d46355aefd..6d4c9e32b8 100644 --- a/cuda_core/tests/test_utils_enum_explanations_helpers.py +++ b/cuda_core/tests/test_utils_enum_explanations_helpers.py @@ -1,6 +1,6 @@ # SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # -# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE +# SPDX-License-Identifier: Apache-2.0 import importlib import sys diff --git a/toolshed/check_spdx.py b/toolshed/check_spdx.py index b404b78e30..292637817e 100644 --- a/toolshed/check_spdx.py +++ b/toolshed/check_spdx.py @@ -6,15 +6,18 @@ import re import subprocess import sys +from pathlib import PureWindowsPath 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: ")), -) +# Intentionally puzzling together SPDX prefixes so that we don't overlook if the +# identifiers are missing in this file. +SPDX_LICENSE_IDENTIFIER_PREFIX = b"-".join((b"SPDX", b"License", b"Identifier: ")) +SPDX_FILE_COPYRIGHT_TEXT_PREFIX = b"-".join((b"SPDX", b"FileCopyrightText: ")) + +LICENSE_IDENTIFIER_REGEX = re.compile(re.escape(SPDX_LICENSE_IDENTIFIER_PREFIX) + rb"(?P[^\r\n]+)") + +EXPECTED_LICENSE_IDENTIFIERS = (("cuda_core/", "Apache-2.0"),) SPDX_IGNORE_FILENAME = ".spdx-ignore" @@ -47,6 +50,92 @@ def is_staged(filepath): return process.stdout.strip() != "" +def normalize_repo_path(filepath): + # We compare against repo prefixes like "cuda_core/" regardless of host OS. + # os.path.normpath is host-dependent: on POSIX it leaves "\" untouched, and + # on Windows it normalizes to "\" separators, so neither gives a stable + # forward-slash form for this prefix check. + return PureWindowsPath(filepath).as_posix() + + +def get_expected_license_identifier(filepath): + normalized_path = normalize_repo_path(filepath) + for prefix, license_identifier in EXPECTED_LICENSE_IDENTIFIERS: + if normalized_path.startswith(prefix): + return license_identifier + return None + + +def validate_required_spdx_field(filepath, blob, expected_bytes): + if expected_bytes in blob: + return True + print(f"MISSING {expected_bytes.decode()}{filepath!r}") + return False + + +def extract_license_identifier(blob): + match = LICENSE_IDENTIFIER_REGEX.search(blob) + if match is None: + return None + try: + return match.group("license_identifier").decode("ascii") + except UnicodeDecodeError: + return None + + +def validate_license_identifier(filepath, blob): + license_identifier = extract_license_identifier(blob) + if license_identifier is None: + print(f"MISSING valid SPDX license identifier in {filepath!r}") + return False + + expected_license_identifier = get_expected_license_identifier(filepath) + if expected_license_identifier is None: + return True + + if license_identifier != expected_license_identifier: + print( + f"INVALID SPDX license identifier {license_identifier!r} " + f"(expected {expected_license_identifier!r}) in {filepath!r}" + ) + return False + + return True + + +def validate_or_fix_copyright(filepath, blob, fix): + match = re.search(COPYRIGHT_REGEX, blob) + if match is None: + print(f"MISSING valid copyright line in {filepath!r}") + return False, blob + + years = match.group("years").decode() + if "-" in years: + start_year, end_year = years.split("-", 1) + if int(start_year) > int(end_year): + print(f"INVALID copyright years {years!r} in {filepath!r}") + return False, blob + else: + start_year = end_year = years + + if not is_staged(filepath) or int(end_year) >= int(CURRENT_YEAR): + return True, blob + + print(f"OUTDATED copyright {years!r} (expected {CURRENT_YEAR!r}) in {filepath!r}") + if not fix: + return False, blob + + new_years = f"{start_year}-{CURRENT_YEAR}" + return ( + False, + re.sub( + COPYRIGHT_REGEX, + COPYRIGHT_SUB.format(new_years).encode("ascii"), + blob, + ), + ) + + def find_or_fix_spdx(filepath, fix): with open(filepath, "rb") as f: blob = f.read() @@ -54,44 +143,22 @@ def find_or_fix_spdx(filepath, fix): 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 - continue - - match = re.search(COPYRIGHT_REGEX, blob) - if match is None: - print(f"MISSING valid copyright line in {filepath!r}") - good = False - continue + has_license_identifier = validate_required_spdx_field(filepath, blob, SPDX_LICENSE_IDENTIFIER_PREFIX) + has_copyright = validate_required_spdx_field(filepath, blob, SPDX_FILE_COPYRIGHT_TEXT_PREFIX) - years = match.group("years").decode() - if "-" in years: - start_year, end_year = years.split("-", 1) - if int(start_year) > int(end_year): - print(f"INVALID copyright years {years!r} in {filepath!r}") - good = False - continue - else: - start_year = end_year = years + if not has_license_identifier or not validate_license_identifier(filepath, blob): + good = False - staged = is_staged(filepath) - - if staged and int(end_year) < int(CURRENT_YEAR): - print(f"OUTDATED copyright {years!r} (expected {CURRENT_YEAR!r}) in {filepath!r}") + if not has_copyright: + good = False + else: + copyright_ok, updated_blob = validate_or_fix_copyright(filepath, blob, fix) + if updated_blob != blob: + with open(filepath, "wb") as f: + f.write(updated_blob) + if not copyright_ok: good = False - if fix: - new_years = f"{start_year}-{CURRENT_YEAR}" - blob = re.sub( - COPYRIGHT_REGEX, - COPYRIGHT_SUB.format(new_years).encode("ascii"), - blob, - ) - with open(filepath, "wb") as f: - f.write(blob) - return good