Skip to content

Commit a830f08

Browse files
Fix strip_root not stripping root from Resource paths in return_codebase mode
When using cli.run_scan() with strip_root=True and return_codebase=True, the root directory was not stripped from Resource paths. This adds path stripping logic for the return_codebase branch and patches parent() for direct children of root. Adds tests for stripped paths, single file behavior, parent traversal, and regression guard. Fixes: #2985 Signed-off-by: Kaushik <kaushikrjpm10@gmail.com>
1 parent 92b4396 commit a830f08

2 files changed

Lines changed: 92 additions & 0 deletions

File tree

src/scancode/cli.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,6 +1070,24 @@ def echo_func(*_args, **_kwargs):
10701070
results = get_results(codebase, as_list=True, **requested_options)
10711071
elif return_codebase:
10721072
results = codebase
1073+
# Strip root from Resource paths. See #2985
1074+
if strip_root and not codebase.has_single_resource:
1075+
from commoncode.resource import strip_first_path_segment
1076+
new_resources_by_path = {}
1077+
for old_path, resource in list(codebase.resources_by_path.items()):
1078+
stripped_path = strip_first_path_segment(old_path)
1079+
resource.path = stripped_path
1080+
new_resources_by_path[stripped_path] = resource
1081+
codebase.resources_by_path = new_resources_by_path
1082+
1083+
# Patch parent() for direct children of root with empty parent path.
1084+
original_parent = codebase.resource_class.parent
1085+
def patched_parent(self, codebase_arg):
1086+
parent_path = self.parent_path()
1087+
if parent_path == '':
1088+
return codebase_arg.root
1089+
return original_parent(self, codebase_arg)
1090+
codebase.resource_class.parent = patched_parent
10731091

10741092
finally:
10751093
# remove temporary files

tests/scancode/test_cli.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,80 @@ def test_run_scan_includes_outdated_in_extra():
120120
assert results['headers'][0]['extra_data']['OUTDATED'] == 'out of date'
121121

122122

123+
def test_run_scan_return_codebase_with_strip_root_strips_paths():
124+
from scancode.cli import run_scan
125+
test_dir = test_env.extract_test_tar('info/basic.tgz')
126+
rc, codebase = run_scan(
127+
test_dir,
128+
info=True,
129+
strip_root=True,
130+
return_results=False,
131+
return_codebase=True,
132+
)
133+
assert rc
134+
assert codebase.root.path == ''
135+
paths = [r.path for r in codebase.walk(skip_root=True)]
136+
root_dir_name = os.path.basename(test_dir)
137+
assert all(not p.startswith(root_dir_name) for p in paths)
138+
assert 'basic' in paths
139+
assert 'basic/main.c' in paths
140+
141+
142+
def test_run_scan_return_codebase_with_strip_root_single_file_does_not_strip():
143+
from scancode.cli import run_scan
144+
test_file = test_env.get_test_loc('single/iproute.c')
145+
rc, codebase = run_scan(
146+
test_file,
147+
info=True,
148+
strip_root=True,
149+
return_results=False,
150+
return_codebase=True,
151+
)
152+
assert rc
153+
assert codebase.root.path != ''
154+
assert 'iproute.c' in codebase.root.path
155+
156+
157+
def test_run_scan_return_codebase_with_strip_root_parent_traversal_works():
158+
from scancode.cli import run_scan
159+
test_dir = test_env.extract_test_tar('info/basic.tgz')
160+
rc, codebase = run_scan(
161+
test_dir,
162+
info=True,
163+
strip_root=True,
164+
return_results=False,
165+
return_codebase=True,
166+
)
167+
assert rc
168+
basic_resource = codebase.get_resource('basic')
169+
assert basic_resource is not None
170+
parent = basic_resource.parent(codebase)
171+
assert parent is not None
172+
assert parent.is_root
173+
174+
main_c = codebase.get_resource('basic/main.c')
175+
assert main_c is not None
176+
main_parent = main_c.parent(codebase)
177+
assert main_parent is not None
178+
assert main_parent.path == 'basic'
179+
180+
181+
def test_run_scan_return_codebase_without_strip_root_keeps_original_paths():
182+
from scancode.cli import run_scan
183+
test_dir = test_env.extract_test_tar('info/basic.tgz')
184+
rc, codebase = run_scan(
185+
test_dir,
186+
info=True,
187+
return_results=False,
188+
return_codebase=True,
189+
)
190+
assert rc
191+
root_path = codebase.root.path
192+
assert root_path != ''
193+
paths = [r.path for r in codebase.walk(skip_root=True)]
194+
assert all(p.startswith(root_path) for p in paths)
195+
196+
123197
def test_no_version_check_run_is_successful():
124198
test_file = test_env.get_test_loc('single/iproute.c')
125199
result_file = test_env.get_temp_file('json')

0 commit comments

Comments
 (0)