Skip to content

Commit

Permalink
Add support for file comments in spdx
Browse files Browse the repository at this point in the history
Add initial support for comments on single files, allowed both by dep5
and spdx specs:
- add 'comment' field to SpdxInfo
- add support for conversion of dep5 Files:Comment fields into SPDX
  FileComment fields

Signed-off-by: Alberto Pianon <[email protected]>
  • Loading branch information
alpianon committed Nov 15, 2022
1 parent 2b0d470 commit 1cfb0b2
Show file tree
Hide file tree
Showing 7 changed files with 41 additions and 25 deletions.
6 changes: 5 additions & 1 deletion src/reuse/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,11 @@
#: The two iterables MUST be sets.
SpdxInfo = NamedTuple(
"SpdxInfo",
[("spdx_expressions", Set[Expression]), ("copyright_lines", Set[str])],
[
("spdx_expressions", Set[Expression]),
("copyright_lines", Set[str]),
("comment", str)
],
)


Expand Down
5 changes: 3 additions & 2 deletions src/reuse/_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,11 +204,12 @@ def _copyright_from_dep5(path: PathLike, dep5_copyright: Copyright) -> SpdxInfo:
result = dep5_copyright.find_files_paragraph(Path(path).as_posix())

if result is None:
return SpdxInfo(set(), set())
return SpdxInfo(set(), set(), "")

return SpdxInfo(
set(map(_LICENSING.parse, [result.license.synopsis])),
set(map(str.strip, result.copyright.splitlines())),
" ".join(result.comment.split()) if result.comment else ""
)


Expand Down Expand Up @@ -302,7 +303,7 @@ def extract_spdx_info(text: str) -> SpdxInfo:
copyright_matches.add(match.groupdict()["copyright"].strip())
break

return SpdxInfo(expressions, copyright_matches)
return SpdxInfo(expressions, copyright_matches, "")


def find_license_identifiers(text: str) -> Iterator[str]:
Expand Down
3 changes: 2 additions & 1 deletion src/reuse/header.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ def create_header(
spdx_info = SpdxInfo(
spdx_info.spdx_expressions.union(existing_spdx.spdx_expressions),
spdx_copyrights,
""
)

new_header += _create_new_header(
Expand Down Expand Up @@ -703,7 +704,7 @@ def run(args, project: Project, out=sys.stdout) -> int:
else set()
)

spdx_info = SpdxInfo(expressions, copyright_lines)
spdx_info = SpdxInfo(expressions, copyright_lines, "")

result = 0
for path in paths:
Expand Down
5 changes: 3 additions & 2 deletions src/reuse/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,8 @@ def spdx_info_of(self, path: PathLike) -> SpdxInfo:
path = _determine_license_path(path)
_LOGGER.debug(f"searching '{path}' for SPDX information")

dep5_result = SpdxInfo(set(), set())
file_result = SpdxInfo(set(), set())
dep5_result = SpdxInfo(set(), set(), "")
file_result = SpdxInfo(set(), set(), "")

# Search the .reuse/dep5 file for SPDX information.
if self._copyright:
Expand Down Expand Up @@ -172,6 +172,7 @@ def spdx_info_of(self, path: PathLike) -> SpdxInfo:
return SpdxInfo(
dep5_result.spdx_expressions.union(file_result.spdx_expressions),
dep5_result.copyright_lines.union(file_result.copyright_lines),
dep5_result.comment
)

def relative_from_root(self, path: Path) -> Path:
Expand Down
11 changes: 10 additions & 1 deletion src/reuse/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from pathlib import Path
from typing import Iterable, List, NamedTuple, Optional, Set
from uuid import uuid4
from textwrap import fill

from . import __version__
from ._util import _LICENSING, _checksum
Expand Down Expand Up @@ -158,6 +159,12 @@ def bill_of_materials(self) -> str:
)
else:
out.write("FileCopyrightText: NONE\n")
if report.spdxfile.comment:
out.write(
f"FileComment: <text>\n"
f"{fill(report.spdxfile.comment, width=72)}\n"
f"</text>\n"
)

# Licenses
for lic, path in sorted(self.licenses.items()):
Expand Down Expand Up @@ -307,6 +314,7 @@ def __init__(self, name, spdx_id=None, chk_sum=None):
self.chk_sum: str = chk_sum
self.licenses_in_file: List[str] = []
self.copyright: str = None
self.comment: str = None


class FileReport:
Expand Down Expand Up @@ -378,8 +386,9 @@ def generate(
# Add license to report.
report.spdxfile.licenses_in_file.append(identifier)

# Copyright text
# Copyright text and comment
report.spdxfile.copyright = "\n".join(sorted(spdx_info.copyright_lines))
report.spdxfile.comment = spdx_info.comment

return report

Expand Down
34 changes: 17 additions & 17 deletions tests/test_header.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
def test_create_header_simple():
"""Create a super simple header."""
spdx_info = SpdxInfo(
{"GPL-3.0-or-later"}, {"SPDX-FileCopyrightText: Jane Doe"}
{"GPL-3.0-or-later"}, {"SPDX-FileCopyrightText: Jane Doe"}, ""
)
expected = cleandoc(
"""
Expand All @@ -37,7 +37,7 @@ def test_create_header_simple():
def test_create_header_template_simple(template_simple):
"""Create a header with a simple template."""
spdx_info = SpdxInfo(
{"GPL-3.0-or-later"}, {"SPDX-FileCopyrightText: Jane Doe"}
{"GPL-3.0-or-later"}, {"SPDX-FileCopyrightText: Jane Doe"}, ""
)
expected = cleandoc(
"""
Expand All @@ -57,7 +57,7 @@ def test_create_header_template_simple(template_simple):
def test_create_header_template_no_spdx(template_no_spdx):
"""Create a header with a template that does not have all SPDX info."""
spdx_info = SpdxInfo(
{"GPL-3.0-or-later"}, {"SPDX-FileCopyrightText: Jane Doe"}
{"GPL-3.0-or-later"}, {"SPDX-FileCopyrightText: Jane Doe"}, ""
)

with pytest.raises(MissingSpdxInfo):
Expand All @@ -67,7 +67,7 @@ def test_create_header_template_no_spdx(template_no_spdx):
def test_create_header_template_commented(template_commented):
"""Create a header with an already-commented template."""
spdx_info = SpdxInfo(
{"GPL-3.0-or-later"}, {"SPDX-FileCopyrightText: Jane Doe"}
{"GPL-3.0-or-later"}, {"SPDX-FileCopyrightText: Jane Doe"}, ""
)
expected = cleandoc(
"""
Expand All @@ -93,7 +93,7 @@ def test_create_header_template_commented(template_commented):
def test_create_header_already_contains_spdx():
"""Create a new header from a header that already contains SPDX info."""
spdx_info = SpdxInfo(
{"GPL-3.0-or-later"}, {"SPDX-FileCopyrightText: Jane Doe"}
{"GPL-3.0-or-later"}, {"SPDX-FileCopyrightText: Jane Doe"}, ""
)
existing = cleandoc(
"""
Expand All @@ -118,7 +118,7 @@ def test_create_header_already_contains_spdx():
def test_create_header_existing_is_wrong():
"""If the existing header contains errors, raise a CommentCreateError."""
spdx_info = SpdxInfo(
{"GPL-3.0-or-later"}, {"SPDX-FileCopyrightText: Jane Doe"}
{"GPL-3.0-or-later"}, {"SPDX-FileCopyrightText: Jane Doe"}, ""
)
existing = cleandoc(
"""
Expand All @@ -134,7 +134,7 @@ def test_create_header_existing_is_wrong():

def test_create_header_old_syntax():
"""Old copyright syntax is preserved when creating a new header."""
spdx_info = SpdxInfo({"GPL-3.0-or-later"}, set())
spdx_info = SpdxInfo({"GPL-3.0-or-later"}, set(), "")
existing = cleandoc(
"""
# Copyright John Doe
Expand All @@ -153,7 +153,7 @@ def test_create_header_old_syntax():

def test_create_header_remove_fluff():
"""Any stuff that isn't SPDX info is removed when using create_header."""
spdx_info = SpdxInfo({"GPL-3.0-or-later"}, set())
spdx_info = SpdxInfo({"GPL-3.0-or-later"}, set(), "")
existing = cleandoc(
"""
# SPDX-FileCopyrightText: John Doe
Expand All @@ -177,7 +177,7 @@ def test_create_header_remove_fluff():
def test_find_and_replace_no_header():
"""Given text without header, add a header."""
spdx_info = SpdxInfo(
{"GPL-3.0-or-later"}, {"SPDX-FileCopyrightText: Jane Doe"}
{"GPL-3.0-or-later"}, {"SPDX-FileCopyrightText: Jane Doe"}, ""
)
text = "pass"
expected = cleandoc(
Expand All @@ -195,7 +195,7 @@ def test_find_and_replace_no_header():

def test_find_and_replace_verbatim():
"""Replace a header with itself."""
spdx_info = SpdxInfo(set(), set())
spdx_info = SpdxInfo(set(), set(), "")
text = cleandoc(
"""
# SPDX-FileCopyrightText: Jane Doe
Expand All @@ -214,7 +214,7 @@ def test_find_and_replace_newline_before_header():
preceding whitespace.
"""
spdx_info = SpdxInfo(
{"GPL-3.0-or-later"}, {"SPDX-FileCopyrightText: John Doe"}
{"GPL-3.0-or-later"}, {"SPDX-FileCopyrightText: John Doe"}, ""
)
text = cleandoc(
"""
Expand All @@ -241,7 +241,7 @@ def test_find_and_replace_newline_before_header():
def test_find_and_replace_preserve_preceding():
"""When the SPDX header is in the middle of the file, keep it there."""
spdx_info = SpdxInfo(
{"GPL-3.0-or-later"}, {"SPDX-FileCopyrightText: John Doe"}
{"GPL-3.0-or-later"}, {"SPDX-FileCopyrightText: John Doe"}, ""
)
text = cleandoc(
"""
Expand Down Expand Up @@ -279,7 +279,7 @@ def test_find_and_replace_keep_shebang():
it.
"""
spdx_info = SpdxInfo(
{"GPL-3.0-or-later"}, {"SPDX-FileCopyrightText: John Doe"}
{"GPL-3.0-or-later"}, {"SPDX-FileCopyrightText: John Doe"}, ""
)
text = cleandoc(
"""
Expand Down Expand Up @@ -310,7 +310,7 @@ def test_find_and_replace_separate_shebang():
"""When the shebang is part of the same comment as the SPDX comment,
separate the two.
"""
spdx_info = SpdxInfo({"GPL-3.0-or-later"}, set())
spdx_info = SpdxInfo({"GPL-3.0-or-later"}, set(), "")
text = cleandoc(
"""
#!/usr/bin/env python3
Expand Down Expand Up @@ -338,7 +338,7 @@ def test_find_and_replace_separate_shebang():

def test_find_and_replace_only_shebang():
"""When the file only contains a shebang, keep it at the top of the file."""
spdx_info = SpdxInfo({"GPL-3.0-or-later"}, set())
spdx_info = SpdxInfo({"GPL-3.0-or-later"}, set(), "")
text = cleandoc(
"""
#!/usr/bin/env python3
Expand Down Expand Up @@ -368,7 +368,7 @@ def test_find_and_replace_keep_old_comment():
licensing information, preserve it below the REUSE header.
"""
spdx_info = SpdxInfo(
{"GPL-3.0-or-later"}, {"SPDX-FileCopyrightText: Jane Doe"}
{"GPL-3.0-or-later"}, {"SPDX-FileCopyrightText: Jane Doe"}, ""
)
text = cleandoc(
"""
Expand All @@ -395,7 +395,7 @@ def test_find_and_replace_keep_old_comment():
def test_find_and_replace_preserve_newline():
"""If the file content ends with a newline, don't remove it."""

spdx_info = SpdxInfo(set(), set())
spdx_info = SpdxInfo(set(), set(), "")
text = (
cleandoc(
"""
Expand Down
2 changes: 1 addition & 1 deletion tests/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def test_extract_no_info():
object.
"""
result = _util.extract_spdx_info("")
assert result == _util.SpdxInfo(set(), set())
assert result == _util.SpdxInfo(set(), set(), "")


def test_extract_tab():
Expand Down

0 comments on commit 1cfb0b2

Please sign in to comment.