Skip to content

Commit 8186fa1

Browse files
committed
Merge remote-tracking branch 'upstream/736-resource-class' into develop
2 parents 4940064 + 720cae5 commit 8186fa1

3 files changed

Lines changed: 62 additions & 30 deletions

File tree

src/scancode/api.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,50 @@
2828

2929
from collections import OrderedDict
3030

31+
from commoncode.fileutils import as_posixpath
3132
from commoncode.fileutils import path_to_bytes
3233
from commoncode.fileutils import path_to_unicode
3334
from commoncode.system import on_linux
35+
from scancode.utils import get_relative_path
3436

3537

3638
"""
3739
Main scanning functions.
3840
Note: this API is unstable and still evolving.
3941
"""
4042

43+
class Resource(object):
44+
"""
45+
Store scanned details for a single resource (file or a directory)
46+
such as infos and path
47+
"""
48+
49+
def __init__(self, scan_cache_class, abs_path, base_is_dir, len_base_path):
50+
self.scan_cache_class = scan_cache_class()
51+
self.is_cached = False
52+
self.abs_path = abs_path
53+
self.base_is_dir = base_is_dir
54+
posix_path = as_posixpath(abs_path)
55+
# fix paths: keep the path as relative to the original
56+
# base_path. This is always Unicode
57+
self.rel_path = get_relative_path(posix_path, len_base_path, base_is_dir)
58+
self.infos = OrderedDict()
59+
self.infos['path'] = self.rel_path
60+
61+
def put_info(self, infos):
62+
"""
63+
Cache file info and set `is_cached` to True if already cached or false otherwise.
64+
"""
65+
self.infos.update(infos)
66+
self.is_cached = self.scan_cache_class.put_info(self.rel_path, self.infos)
67+
68+
def get_info(self):
69+
"""
70+
Retrieve info from cache.
71+
"""
72+
return self.scan_cache_class.get_info(self.rel_path)
73+
74+
4175
def extract_archives(location, recurse=True):
4276
"""
4377
Extract any archives found at `location` and yield ExtractEvents. If

src/scancode/cli.py

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
from scancode.api import get_licenses
6969
from scancode.api import get_package_infos
7070
from scancode.api import get_urls
71+
from scancode.api import Resource
7172

7273
from scancode.cache import get_scans_cache_class
7374
from scancode.cache import ScanFileCache
@@ -80,7 +81,6 @@
8081
from scancode.utils import BaseCommand
8182
from scancode.utils import compute_fn_max_len
8283
from scancode.utils import fixed_width_file_name
83-
from scancode.utils import get_relative_path
8484
from scancode.utils import progressmanager
8585

8686

@@ -578,7 +578,7 @@ def scan(input_path,
578578

579579
pool = None
580580

581-
resources = resource_paths(input_path, pre_scan_plugins=pre_scan_plugins)
581+
resources = resource_paths(input_path, diag, scans_cache_class, pre_scan_plugins=pre_scan_plugins)
582582
paths_with_error = []
583583
files_count = 0
584584

@@ -731,26 +731,19 @@ def _resource_logger(logfile_fd, resources):
731731
yield back the resources.
732732
"""
733733
file_logger = ScanFileCache.log_file_path
734-
for posix_path, rel_path in resources:
735-
file_logger(logfile_fd, rel_path)
736-
yield posix_path, rel_path
734+
for resource in resources:
735+
file_logger(logfile_fd, resource.rel_path)
736+
yield resource
737737

738738

739-
def _scanit(paths, scanners, scans_cache_class, diag, timeout=DEFAULT_TIMEOUT, processes=1):
739+
def _scanit(resource, scanners, scans_cache_class, diag, timeout=DEFAULT_TIMEOUT, processes=1):
740740
"""
741741
Run scans and cache results on disk. Return a tuple of (success, scanned relative
742742
path) where sucess is True on success, False on error. Note that this is really
743743
only a wrapper function used as an execution unit for parallel processing.
744744
"""
745-
abs_path, rel_path = paths
746-
# always fetch infos and cache.
747-
infos = OrderedDict()
748-
infos['path'] = rel_path
749-
infos.update(scan_infos(abs_path, diag=diag))
750-
751745
success = True
752746
scans_cache = scans_cache_class()
753-
is_cached = scans_cache.put_info(rel_path, infos)
754747

755748
# note: "flag and function" expressions return the function if flag is True
756749
# note: the order of the scans matters to show things in logical order
@@ -766,23 +759,23 @@ def _scanit(paths, scanners, scans_cache_class, diag, timeout=DEFAULT_TIMEOUT, p
766759
if any(scanner_functions):
767760
# Skip other scans if already cached
768761
# FIXME: ENSURE we only do this for files not directories
769-
if not is_cached:
762+
if not resource.is_cached:
770763
# run the scan as an interruptiple task
771-
scans_runner = partial(scan_one, abs_path, scanners, diag)
764+
scans_runner = partial(scan_one, resource.abs_path, scanners, diag)
772765
success, scan_result = interrupter(scans_runner, timeout=timeout)
773766
if not success:
774767
# Use scan errors as the scan result for that file on failure this is
775768
# a top-level error not attachedd to a specific scanner, hence the
776769
# "scan" key is used for these errors
777770
scan_result = {'scan_errors': [scan_result]}
778771

779-
scans_cache.put_scan(rel_path, infos, scan_result)
772+
scans_cache.put_scan(resource.rel_path, resource.get_info(), scan_result)
780773

781774
# do not report success if some other errors happened
782775
if scan_result.get('scan_errors'):
783776
success = False
784777

785-
return success, rel_path
778+
return success, resource.rel_path
786779

787780

788781
def build_ignorer(ignores, unignores):
@@ -801,10 +794,10 @@ def build_ignorer(ignores, unignores):
801794
return partial(ignore.is_ignored, ignores=ignores, unignores=unignores)
802795

803796

804-
def resource_paths(base_path, pre_scan_plugins=()):
797+
def resource_paths(base_path, diag, scans_cache_class, pre_scan_plugins=()):
805798
"""
806-
Yield tuples of (absolute path, base_path-relative path) for all the files found
807-
at base_path (either a directory or file) given an absolute base_path. Only yield
799+
Yield `Resource` objects for all the files found at base_path
800+
(either a directory or file) given an absolute base_path. Only yield
808801
Files, not directories.
809802
absolute path is a native OS path.
810803
base_path-relative path is a POSIX path.
@@ -831,11 +824,10 @@ def resource_paths(base_path, pre_scan_plugins=()):
831824
resources = fileutils.resource_iter(base_path, ignored=ignorer)
832825

833826
for abs_path in resources:
834-
posix_path = fileutils.as_posixpath(abs_path)
835-
# fix paths: keep the path as relative to the original
836-
# base_path. This is always Unicode
837-
rel_path = get_relative_path(posix_path, len_base_path, base_is_dir)
838-
yield abs_path, rel_path
827+
resource = Resource(scans_cache_class, abs_path, base_is_dir, len_base_path)
828+
# always fetch infos and cache.
829+
resource.put_info(scan_infos(abs_path, diag=diag))
830+
yield resource
839831

840832

841833
def scan_infos(input_file, diag=False):

tests/scancode/test_ignore_files.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
from commoncode.testcase import FileBasedTesting
3131
from commoncode.ignore import is_ignored
32+
from scancode.cache import get_scans_cache_class
3233
from scancode.cli import resource_paths
3334
from scancode.plugin_ignore import ProcessIgnore
3435

@@ -72,6 +73,7 @@ def test_ignore_glob_file(self):
7273
def test_resource_paths_with_single_file(self):
7374
test_dir = self.extract_test_tar('ignore/user.tgz')
7475
test_plugin = ProcessIgnore(('sample.doc',))
76+
scan_cache_class = get_scans_cache_class(self.get_temp_dir())
7577
expected = [
7678
'user',
7779
'user/ignore.doc',
@@ -80,48 +82,52 @@ def test_resource_paths_with_single_file(self):
8082
'user/src/test',
8183
'user/src/test/sample.txt'
8284
]
83-
test = [rel_path for abs_path, rel_path in resource_paths(test_dir, [test_plugin])]
85+
test = [resource.rel_path for resource in resource_paths(test_dir, False, scan_cache_class, [test_plugin])]
8486
assert expected == sorted(test)
8587

8688
def test_resource_paths_with_multiple_files(self):
8789
test_dir = self.extract_test_tar('ignore/user.tgz')
8890
test_plugin = ProcessIgnore(('ignore.doc',))
91+
scan_cache_class = get_scans_cache_class(self.get_temp_dir())
8992
expected = [
9093
'user',
9194
'user/src',
9295
'user/src/test',
9396
'user/src/test/sample.doc',
9497
'user/src/test/sample.txt'
9598
]
96-
test = [rel_path for abs_path, rel_path in resource_paths(test_dir, [test_plugin])]
99+
test = [resource.rel_path for resource in resource_paths(test_dir, False, scan_cache_class, [test_plugin])]
97100
assert expected == sorted(test)
98101

99102
def test_resource_paths_with_glob_file(self):
100103
test_dir = self.extract_test_tar('ignore/user.tgz')
101104
test_plugin = ProcessIgnore(('*.doc',))
105+
scan_cache_class = get_scans_cache_class(self.get_temp_dir())
102106
expected = [
103107
'user',
104108
'user/src',
105109
'user/src/test',
106110
'user/src/test/sample.txt'
107111
]
108-
test = [rel_path for abs_path, rel_path in resource_paths(test_dir, [test_plugin])]
112+
test = [resource.rel_path for resource in resource_paths(test_dir, False, scan_cache_class, [test_plugin])]
109113
assert expected == sorted(test)
110114

111115
def test_resource_paths_with_glob_path(self):
112116
test_dir = self.extract_test_tar('ignore/user.tgz')
113117
test_plugin = ProcessIgnore(('*/src/test',))
118+
scan_cache_class = get_scans_cache_class(self.get_temp_dir())
114119
expected = [
115120
'user',
116121
'user/ignore.doc',
117122
'user/src',
118123
'user/src/ignore.doc'
119124
]
120-
test = [rel_path for abs_path, rel_path in resource_paths(test_dir, [test_plugin])]
125+
test = [resource.rel_path for resource in resource_paths(test_dir, False, scan_cache_class, [test_plugin])]
121126
assert expected == sorted(test)
122127

123128
def test_resource_paths_with_multiple_plugins(self):
124129
test_dir = self.extract_test_tar('ignore/user.tgz')
130+
scan_cache_class = get_scans_cache_class(self.get_temp_dir())
125131
test_plugins = [
126132
ProcessIgnore(('*.doc',)),
127133
ProcessIgnore(('*/src/test/*',))
@@ -131,5 +137,5 @@ def test_resource_paths_with_multiple_plugins(self):
131137
'user/src',
132138
'user/src/test'
133139
]
134-
test = [rel_path for abs_path, rel_path in resource_paths(test_dir, test_plugins)]
140+
test = [resource.rel_path for resource in resource_paths(test_dir, False, scan_cache_class, test_plugins)]
135141
assert expected == sorted(test)

0 commit comments

Comments
 (0)