Skip to content

Commit

Permalink
Add 'spdx_id' field to the 'File' class
Browse files Browse the repository at this point in the history
Signed-off-by: Yash Nisar <yash.nisar@somaiya.edu>
  • Loading branch information
yash-nisar committed Aug 7, 2018
1 parent 0a79680 commit dca1bcd
Show file tree
Hide file tree
Showing 17 changed files with 120 additions and 33 deletions.
4 changes: 2 additions & 2 deletions data/SPDXRdfExample.rdf
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
</ExternalDocumentRef>
</externalDocumentRef>
<referencesFile>
<File rdf:nodeID="A0">
<File rdf:about="https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301#SPDXRef-File1">>
<licenseConcluded>
<ExtractedLicensingInfo rdf:nodeID="A1">
<extractedText>/*
Expand Down Expand Up @@ -97,7 +97,7 @@
</Review>
</reviewed>
<referencesFile>
<File rdf:nodeID="A2">
<File rdf:about="https://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301#SPDXRef-File2">
<copyrightText>Copyright 2010, 2011 Source Auditor Inc.</copyrightText>
<licenseComments></licenseComments>
<licenseInfoInFile rdf:resource="http://spdx.org/licenses/Apache-2.0"/>
Expand Down
1 change: 1 addition & 0 deletions data/SPDXSimpleTag.tag
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ PackageLicenseComments: <text>License Comments</text>
# File Info

FileName: testfile.java
SPDXID: SPDXRef-File
FileType: SOURCE
FileChecksum: SHA1: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12
LicenseConcluded: Apache-2.0
Expand Down
2 changes: 2 additions & 0 deletions data/SPDXTagExample.tag
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,15 @@ PackageLicenseComments: <text>The declared license information can be found in t

## File Information
FileName: src/org/spdx/parser/DOAPProject.java
SPDXID: SPDXRef-File1
FileType: SOURCE
FileChecksum: SHA1: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12
LicenseConcluded: Apache-2.0
LicenseInfoInFile: Apache-2.0
FileCopyrightText: <text>Copyright 2010, 2011 Source Auditor Inc.</text>

FileName: Jenna-2.6.3/jena-2.6.3-sources.jar
SPDXID: SPDXRef-File2
FileType: ARCHIVE
FileChecksum: SHA1: 3ab4e1c67a2d28fced849ee1bb76e7391b93f125
LicenseConcluded: LicenseRef-1
Expand Down
18 changes: 16 additions & 2 deletions spdx/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ class File(object):
Represent an SPDX file.
Fields:
- name: File name, str mandatory one.
- spdx_id: Uniquely identify any element in an SPDX document which may be
referenced by other elements. Mandatory, one. Type: str.
- comment: File comment str, Optional zero or one.
- type: one of FileType.SOURCE, FileType.BINARY, FileType.ARCHIVE
and FileType.OTHER, optional zero or one.
Expand All @@ -54,8 +56,9 @@ class File(object):
- artifact_of_project_uri: list of project uris, possibly empty.
"""

def __init__(self, name, chk_sum=None):
def __init__(self, name, spdx_id=None, chk_sum=None):
self.name = name
self.spdx_id = spdx_id
self.comment = None
self.type = None
self.chk_sum = chk_sum
Expand Down Expand Up @@ -105,7 +108,18 @@ def validate(self, messages=None):
and self.validate_chksum(messages)
and self.validate_licenses_in_file(messages)
and self.validate_copyright(messages)
and self.validate_artifacts(messages))
and self.validate_artifacts(messages)
and self.validate_spdx_id(messages))

def validate_spdx_id(self, messages=None):
# FIXME: messages should be returned
messages = messages if messages is not None else []

if self.spdx_id is None:
messages.append('File has no SPDX Identifier.')
return False
else:
return True

def validate_copyright(self, messages=None):
# FIXME: messages should be returned
Expand Down
2 changes: 1 addition & 1 deletion spdx/parsers/lexers/tagvalue.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class Lexer(object):
'SPDXVersion': 'DOC_VERSION',
'DataLicense': 'DOC_LICENSE',
'DocumentName': 'DOC_NAME',
'SPDXID': 'DOC_SPDX_ID',
'SPDXID': 'SPDX_ID',
'DocumentComment': 'DOC_COMMENT',
'DocumentNamespace': 'DOC_NAMESPACE',
'ExternalDocumentRef': 'EXT_DOC_REF',
Expand Down
12 changes: 12 additions & 0 deletions spdx/parsers/rdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
'LICS_LIST_MEMBER' : 'Declaritive or Conjunctive license set member must be a license url or identifier',
'PKG_SINGLE_LICS' : 'Package concluded license must be a license url or spdx:noassertion or spdx:none.',
'PKG_LICS_INFO_FILES' : 'Package licenseInfoFromFiles must be a license or spdx:none or spdx:noassertion',
'FILE_SPDX_ID_VALUE': 'SPDXID must be "SPDXRef-[idstring]" where [idstring] is a unique string containing '
'letters, numbers, ".", "-".',
'FILE_TYPE' : 'File type must be binary, other, source or archive term.',
'FILE_SINGLE_LICS': 'File concluded license must be a license url or spdx:noassertion or spdx:none.',
'REVIEWER_VALUE' : 'Invalid reviewer value \'{0}\' must be Organization, Tool or Person.',
Expand Down Expand Up @@ -515,6 +517,7 @@ def parse_file(self, f_term):
for _, _, name in self.graph.triples((f_term, self.spdx_namespace['fileName'], None)):
self.builder.set_file_name(self.doc, six.text_type(name))

self.p_file_spdx_id(f_term, self.spdx_namespace['File'])
self.p_file_type(f_term, self.spdx_namespace['fileType'])
self.p_file_chk_sum(f_term, self.spdx_namespace['checksum'])
self.p_file_lic_conc(f_term, self.spdx_namespace['licenseConcluded'])
Expand Down Expand Up @@ -613,6 +616,15 @@ def p_file_lic_info(self, f_term, predicate):
if lic is not None:
self.builder.set_file_license_in_file(self.doc, lic)

def p_file_spdx_id(self, f_term, predicate):
try:
try:
self.builder.set_file_spdx_id(self.doc, f_term)
except SPDXValueError:
self.value_error('FILE_SPDX_ID_VALUE', f_term)
except CardinalityError:
self.more_than_one_error('FILE_SPDX_ID_VALUE')

def p_file_type(self, f_term, predicate):
"""Sets file type."""
try:
Expand Down
55 changes: 34 additions & 21 deletions spdx/parsers/tagvalue.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@
'FILE_NAME_VALUE': 'FileName must be a single line of text, line: {0}',
'FILE_COMMENT_VALUE': 'FileComment must be free form text, line:{0}',
'FILE_TYPE_VALUE': 'FileType must be one of OTHER, BINARY, SOURCE or ARCHIVE, line: {0}',
'FILE_SPDX_ID_VALUE': 'SPDXID must be "SPDXRef-[idstring]" where [idstring] is a unique string containing '
'letters, numbers, ".", "-".',
'FILE_CHKSUM_VALUE': 'FileChecksum must be a single line of text starting with \'SHA1:\', line:{0}',
'FILE_LICS_CONC_VALUE': 'LicenseConcluded must be NOASSERTION, NONE, license identifier or license list, line:{0}',
'FILE_LICS_INFO_VALUE': 'LicenseInfoInFile must be NOASSERTION, NONE or license identifier, line: {0}',
Expand Down Expand Up @@ -113,9 +115,9 @@ def p_start_2(self, p):

def p_attrib(self, p):
"""attrib : spdx_version
| spdx_id
| data_lics
| doc_name
| doc_spdx_id
| ext_doc_ref
| doc_comment
| doc_namespace
Expand Down Expand Up @@ -539,6 +541,17 @@ def p_file_name_2(self, p):
msg = ERROR_MESSAGES['FILE_NAME_VALUE'].format(p.lineno(1))
self.logger.log(msg)

def p_spdx_id(self, p):
"""spdx_id : SPDX_ID LINE"""
if six.PY2:
value = p[2].decode(encoding='utf-8')
else:
value = p[2]
if not self.builder.doc_spdx_id_set:
self.builder.set_doc_spdx_id(self.document, value)
else:
self.builder.set_file_spdx_id(self.document, value)

def p_file_comment_1(self, p):
"""file_comment : FILE_COMMENT TEXT"""
try:
Expand Down Expand Up @@ -1148,26 +1161,26 @@ def p_doc_name_2(self, p):
msg = ERROR_MESSAGES['DOC_NAME_VALUE'].format(p.lineno(1))
self.logger.log(msg)

def p_doc_spdx_id_1(self, p):
"""doc_spdx_id : DOC_SPDX_ID LINE"""
try:
if six.PY2:
value = p[2].decode(encoding='utf-8')
else:
value = p[2]
self.builder.set_doc_spdx_id(self.document, value)
except SPDXValueError:
self.error = True
msg = ERROR_MESSAGES['DOC_SPDX_ID_VALUE'].format(p.lineno(2))
self.logger.log(msg)
except CardinalityError:
self.more_than_one_error('SPDXID', p.lineno(1))

def p_doc_spdx_id_2(self, p):
"""doc_spdx_id : DOC_SPDX_ID error"""
self.error = True
msg = ERROR_MESSAGES['DOC_SPDX_ID_VALUE'].format(p.lineno(1))
self.logger.log(msg)
# def p_doc_spdx_id_1(self, p):
# """doc_spdx_id : DOC_SPDX_ID LINE"""
# try:
# if six.PY2:
# value = p[2].decode(encoding='utf-8')
# else:
# value = p[2]
# self.builder.set_doc_spdx_id(self.document, value)
# except SPDXValueError:
# self.error = True
# msg = ERROR_MESSAGES['DOC_SPDX_ID_VALUE'].format(p.lineno(2))
# self.logger.log(msg)
# except CardinalityError:
# self.more_than_one_error('SPDXID', p.lineno(1))
#
# def p_doc_spdx_id_2(self, p):
# """doc_spdx_id : DOC_SPDX_ID error"""
# self.error = True
# msg = ERROR_MESSAGES['DOC_SPDX_ID_VALUE'].format(p.lineno(1))
# self.logger.log(msg)

def p_ext_doc_refs_1(self, p):
"""ext_doc_ref : EXT_DOC_REF DOC_REF_ID DOC_URI EXT_DOC_REF_CHKSUM"""
Expand Down
21 changes: 21 additions & 0 deletions spdx/parsers/tagvaluebuilders.py
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,26 @@ def set_file_name(self, doc, name):
else:
raise OrderError('File::Name')

def set_file_spdx_id(self, doc, spdx_id):
"""
Sets the file SPDX Identifier.
Raises OrderError if no package or no file defined.
Raises SPDXValueError if malformed value.
Raises CardinalityError if more than one spdx_id set.
"""
if self.has_package(doc) and self.has_file(doc):
if not self.file_spdx_id_set:
self.file_spdx_id_set = True
if validations.validate_file_spdx_id(spdx_id):
self.file(doc).spdx_id = spdx_id
return True
else:
raise SPDXValueError('File::SPDXID')
else:
raise CardinalityError('File::SPDXID')
else:
raise OrderError('File::SPDXID')

def set_file_comment(self, doc, text):
"""
Raises OrderError if no package or no file defined.
Expand Down Expand Up @@ -916,6 +936,7 @@ def has_package(self, doc):
def reset_file_stat(self):
"""Resets the builder's state to enable building new files."""
# FIXME: this state does not make sense
self.file_spdx_id_set = False
self.file_comment_set = False
self.file_type_set = False
self.file_chksum_set = False
Expand Down
9 changes: 9 additions & 0 deletions spdx/parsers/validations.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,15 @@ def validate_pkg_lics_comment(value, optional=False):
return validate_is_free_form_text(value, optional)


def validate_file_spdx_id(value, optional=False):
value = value.split('#')[-1]
TEXT_RE = re.compile(r'SPDXRef-([A-Za-z0-9.\-]+)', re.UNICODE)
if value is None:
return optional
else:
return TEXT_RE.match(value) is not None


def validate_file_comment(value, optional=False):
return validate_is_free_form_text(value, optional)

Expand Down
3 changes: 2 additions & 1 deletion spdx/writers/rdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals
import uuid

from rdflib import BNode
from rdflib import Graph
Expand Down Expand Up @@ -208,7 +209,7 @@ def create_file_node(self, doc_file):
"""
Create a node for spdx.file.
"""
file_node = BNode()
file_node = URIRef('http://www.spdx.org/files#' + str(doc_file.spdx_id))
type_triple = (file_node, RDF.type, self.spdx_namespace.File)
self.graph.add(type_triple)

Expand Down
1 change: 1 addition & 0 deletions spdx/writers/tagvalue.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ def write_file(spdx_file, out):
"""
out.write('# File\n\n')
write_value('FileName', spdx_file.name, out)
write_value('SPDXID', spdx_file.spdx_id, out)
if spdx_file.has_optional_field('type'):
write_file_type(spdx_file.type, out)
write_value('FileChecksum', spdx_file.chk_sum.to_tv(), out)
Expand Down
5 changes: 4 additions & 1 deletion tests/data/doc_write/rdf-simple-plus.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
"ns1:SpdxDocument": {
"ns1:describesPackage": {
"ns1:Package": {
"ns1:hasFile": null,
"ns1:hasFile": {
"@rdf:resource": "http://www.spdx.org/files#SPDXRef-File"
},
"ns1:name": "some/path",
"ns1:licenseDeclared": {
"@rdf:resource": "http://spdx.org/rdf/terms#noassertion"
Expand All @@ -31,6 +33,7 @@
},
"ns1:referencesFile": {
"ns1:File": {
"@rdf:about": "http://www.spdx.org/files#SPDXRef-File",
"ns1:fileName": "./some/path/tofile",
"ns1:checksum": {
"ns1:Checksum": {
Expand Down
11 changes: 7 additions & 4 deletions tests/data/doc_write/rdf-simple.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
"ns1:SpdxDocument": {
"ns1:describesPackage": {
"ns1:Package": {
"ns1:hasFile": null,
"ns1:hasFile": {
"@rdf:resource": "http://www.spdx.org/files#SPDXRef-File"
},
"ns1:downloadLocation": {
"@rdf:resource": "http://spdx.org/rdf/terms#noassertion"
},
Expand All @@ -31,15 +33,16 @@
},
"ns1:referencesFile": {
"ns1:File": {
"@rdf:about": "http://www.spdx.org/files#SPDXRef-File",
"ns1:licenseInfoInFile": {
"@rdf:resource": "http://spdx.org/licenses/LGPL-2.1"
},
},
"ns1:checksum": {
"ns1:Checksum": {
"ns1:checksumValue": "SOME-SHA1",
"ns1:checksumValue": "SOME-SHA1",
"ns1:algorithm": "SHA1"
}
},
},
"ns1:licenseConcluded": {
"@rdf:resource": "http://spdx.org/rdf/terms#noassertion"
},
Expand Down
1 change: 1 addition & 0 deletions tests/data/doc_write/tv-simple-plus.tv
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ PackageLicenseInfoFromFiles: LGPL-2.1+
PackageCopyrightText: <text>Some copyrught</text>
# File
FileName: ./some/path/tofile
SPDXID: SPDXRef-File
FileChecksum: SHA1: SOME-SHA1
LicenseConcluded: NOASSERTION
LicenseInfoInFile: LGPL-2.1+
Expand Down
1 change: 1 addition & 0 deletions tests/data/doc_write/tv-simple.tv
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ PackageLicenseInfoFromFiles: LGPL-2.1
PackageCopyrightText: <text>Some copyrught</text>
# File
FileName: ./some/path/tofile
SPDXID: SPDXRef-File
FileChecksum: SHA1: SOME-SHA1
LicenseConcluded: NOASSERTION
LicenseInfoInFile: LGPL-2.1
Expand Down
3 changes: 3 additions & 0 deletions tests/test_document.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ def test_document_validate_failures_returns_informative_messages(self):
pack = doc.package = Package('some/path', NoAssert())
file1 = File('./some/path/tofile')
file1.name = './some/path/tofile'
file1.spdx_id = 'SPDXRef-File'
file1.chk_sum = Algorithm('SHA1', 'SOME-SHA1')
lic1 = License.from_identifier('LGPL-2.1')
file1.add_lics(lic1)
Expand Down Expand Up @@ -108,6 +109,7 @@ def test_document_is_valid_when_using_or_later_licenses(self):

file1 = File('./some/path/tofile')
file1.name = './some/path/tofile'
file1.spdx_id = 'SPDXRef-File'
file1.chk_sum = Algorithm('SHA1', 'SOME-SHA1')
file1.conc_lics = NoAssert()
file1.copyright = NoAssert()
Expand Down Expand Up @@ -140,6 +142,7 @@ def _get_lgpl_doc(self, or_later=False):

file1 = File('./some/path/tofile')
file1.name = './some/path/tofile'
file1.spdx_id = 'SPDXRef-File'
file1.chk_sum = Algorithm('SHA1', 'SOME-SHA1')
file1.conc_lics = NoAssert()
file1.copyright = NoAssert()
Expand Down
4 changes: 3 additions & 1 deletion tests/test_tag_value_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def test_document(self):
self.token_assert_helper(self.l.token(), 'DOC_NAME', 'DocumentName', 5)
self.token_assert_helper(self.l.token(), 'LINE', 'Sample_Document-V2.1',
5)
self.token_assert_helper(self.l.token(), 'DOC_SPDX_ID', 'SPDXID', 6)
self.token_assert_helper(self.l.token(), 'SPDX_ID', 'SPDXID', 6)
self.token_assert_helper(self.l.token(), 'LINE', 'SPDXRef-DOCUMENT', 6)
self.token_assert_helper(self.l.token(), 'DOC_NAMESPACE',
'DocumentNamespace', 7)
Expand Down Expand Up @@ -188,6 +188,7 @@ class TestParser(TestCase):

file_str = '\n'.join([
'FileName: testfile.java',
'SPDXID: SPDXRef-File',
'FileType: SOURCE',
'FileChecksum: SHA1: 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12',
'LicenseConcluded: Apache-2.0',
Expand Down Expand Up @@ -248,6 +249,7 @@ def test_file(self):
assert len(document.package.files) == 1
spdx_file = document.package.files[0]
assert spdx_file.name == 'testfile.java'
assert spdx_file.spdx_id == 'SPDXRef-File'
assert spdx_file.type == spdx.file.FileType.SOURCE
assert len(spdx_file.artifact_of_project_name) == 1
assert len(spdx_file.artifact_of_project_home) == 1
Expand Down

0 comments on commit dca1bcd

Please sign in to comment.