Repository: vmware/tern
Pull request #578 (2020-03-11 03:19:11)

Update FileData object and scancode executor
This is work towards #480

The first commit fixes execution of the scancode extension.
The second commit adds a new method to the FileData
class along with a test.

Signed-off-by: Nisha K nishak@vmware.com


Patch:
diff --git a/tern/classes/file_data.py b/tern/classes/file_data.py
index 933dfdb..3bb5961 100644
--- a/tern/classes/file_data.py
+++ b/tern/classes/file_data.py
@@ -39,7 +39,8 @@ class FileData:
         to_dict: returns a dictionary representation of the instance
         set_version: set the version of the file given the version control
         system used
-        set_checksum: set the checksum of the file given the checksum type'''
+        set_checksum: set the checksum of the file given the checksum type
+        fill: fill data into the object instance from a dictionary'''
     def __init__(self,
                  name,
                  path,
@@ -194,3 +195,27 @@ class FileData:
         else:
             success = False
         return success
+
+    def merge(self, other):
+        '''Compare another FileData object to this instance. If the file path
+        is the same, we fill in the rest of the data excluding the checksum,
+        version control data and the extended attributes. This method can
+        be used in situations where an external scanner is used to collect
+        file level data that we don't collect ourselves'''
+        if not isinstance(other, FileData):
+            return False
+        if (self.path == other.path):
+            self.date = other.date
+            self.file_type = other.file_type
+            self.licenses = other.licenses
+            self.license_expressions = other.license_expressions
+            self.copyrights = other.copyrights
+            self.authors = other.authors
+            self.packages = other.packages
+            self.urls = other.urls
+            # collect notices
+            for o in other.origins.origins:
+                for n in o.notices:
+                    self.origins.add_notice_to_origins(o.origin_str, n)
+            return True
+        return False
diff --git a/tern/extensions/scancode/executor.py b/tern/extensions/scancode/executor.py
index f891429..f75677a 100644
--- a/tern/extensions/scancode/executor.py
+++ b/tern/extensions/scancode/executor.py
@@ -75,7 +75,7 @@ def analyze_file(layer_obj):
     # run scancode against each file
     command = 'scancode -ilpcu --quiet --json -'
     for fd in layer_obj.files:
-        full_cmd = get_file_command(layer_obj.tar_file, fd.path, command)
+        full_cmd = get_file_command(layer_obj.tar_file, fd, command)
         origin_file = 'File: ' + fd.path
         result, error = rootfs.shell_command(True, full_cmd)
         if not result:


Test patch:
diff --git a/tests/test_class_file_data.py b/tests/test_class_file_data.py
index f82b67f..30ef358 100644
--- a/tests/test_class_file_data.py
+++ b/tests/test_class_file_data.py
@@ -6,6 +6,7 @@
 import unittest
 
 from tern.classes.file_data import FileData
+from tern.classes.notice import Notice
 from test_fixtures import TestTemplate1
 from test_fixtures import TestTemplate2
 
@@ -121,6 +122,46 @@ class TestClassFileData(unittest.TestCase):
         self.assertEqual(f.origins.origins[0].notices[2].message,
                          'No metadata for key: version_control')
 
+    def testMerge(self):
+        file1 = FileData('switch_root', 'sbin/switch_root')
+        file1.set_checksum('sha256', '123abc456def')
+        file1.extattrs = '-rwxr-xr-x|1000|1000|14408|1'
+        file2 = FileData('switch_root', 'sbin/switch_root')
+        file2.set_checksum('sha256', '123abc456def')
+        file2.extattrs = '-rwxr-xr-x|1000|1000|14408|1'
+        file2.date = '2012-02-02'
+        file2.file_type = 'binary'
+        file2.licenses = ['MIT', 'GPL']
+        file2.license_expressions = ['MIT or GPL']
+        file2.copyrights = ['copyrights']
+        file2.authors = ['author1', 'author2']
+        file2.packages = ['package1', 'package2']
+        file2.urls = ['url1', 'url2']
+        file2.origins.add_notice_to_origins(
+            'scanning', Notice('something happened', 'error'))
+        file3 = FileData('switch_root', 'sbin/switch_root')
+        file3.set_checksum('sha1', '456def123abc')
+        file4 = FileData('e2image', 'sbin/e2image')
+        self.assertFalse(file1.merge(file4))
+        self.assertTrue(file1.merge(file3))
+        self.assertEqual(file1.checksum, '123abc456def')
+        self.assertEqual(file1.extattrs, '-rwxr-xr-x|1000|1000|14408|1')
+        self.assertFalse(file1.merge('astring'))
+        self.assertTrue(file1.merge(file2))
+        self.assertEqual(file1.date, '2012-02-02')
+        self.assertEqual(file1.file_type, 'binary')
+        self.assertEqual(file1.licenses, ['MIT', 'GPL'])
+        self.assertEqual(file1.license_expressions, ['MIT or GPL'])
+        self.assertEqual(file1.copyrights, ['copyrights'])
+        self.assertEqual(file1.authors, ['author1', 'author2'])
+        self.assertEqual(file1.packages, ['package1', 'package2'])
+        self.assertEqual(file1.urls, ['url1', 'url2'])
+        self.assertEqual(len(file1.origins.origins), 1)
+        self.assertEqual(file1.origins.origins[0].origin_str, 'scanning')
+        self.assertEqual(len(file1.origins.origins[0].notices), 1)
+        self.assertEqual(
+            file1.origins.origins[0].notices[0].message, 'something happened')
+
 
 if __name__ == '__main__':
     unittest.main()