Skip to content

Commit 4895e0b

Browse files
authored
Merge pull request #2988 from nexB/reimplement-get-installed-packages
Reimplement get installed packages
2 parents a94d414 + f2fcc3b commit 4895e0b

10 files changed

Lines changed: 586 additions & 7 deletions

File tree

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ commoncode==31.0.0b4
1313
construct==2.10.68
1414
container-inspector==31.0.0
1515
cryptography==36.0.2
16-
debian-inspector==30.0.0
16+
debian-inspector==31.0.0b1
1717
dockerfile-parse==1.2.0
1818
dparse2==0.6.1
1919
extractcode==31.0.0

setup-mini.cfg

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ install_requires =
7171
colorama >= 0.3.9
7272
commoncode==31.0.0b4
7373
container-inspector >= 31.0.0
74-
debian-inspector >= 30.0.0
74+
debian-inspector >= 31.0.0b1
7575
dparse2 >= 0.6.1
7676
fasteners
7777
fingerprints >= 0.6.0
@@ -112,6 +112,8 @@ install_requires =
112112
xmltodict >= 0.11.0
113113
zipp >= 3.0.0; python_version < "3.9"
114114
typecode >= 30.0.0
115+
# typecode[full] >= 30.0.0
116+
# extractcode[full] >= 31.0.0
115117

116118

117119
[options.packages.find]
@@ -128,6 +130,8 @@ testing =
128130
pytest-xdist >= 2
129131
aboutcode-toolkit >= 7.0.2
130132
twine
133+
black
134+
isort
131135

132136
docs =
133137
Sphinx >= 3.3.1

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ install_requires =
7171
colorama >= 0.3.9
7272
commoncode==31.0.0b4
7373
container-inspector >= 31.0.0
74-
debian-inspector >= 30.0.0
74+
debian-inspector >= 31.0.0b1
7575
dparse2 >= 0.6.1
7676
fasteners
7777
fingerprints >= 0.6.0

src/packagedcode/alpine.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1772,4 +1772,3 @@ def detect_licenses(locin, locout):
17721772
# get_apkindex_licenses(loc, 'alpine-licenses.csv')
17731773
get_apkbuild_licenses(loc, 'alpine-licenses.csv')
17741774
detect_licenses('alpine-licenses.csv', 'alpine-licenses-detection.csv')
1775-

src/packagedcode/models.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from commoncode.datautils import Mapping
2626
from commoncode.datautils import String
2727
from commoncode.fileutils import as_posixpath
28+
from commoncode.resource import Resource
2829
from typecode import contenttype
2930

3031
"""
@@ -1201,7 +1202,7 @@ def __attrs_post_init__(self, *args, **kwargs):
12011202
self.package_uid = build_package_uid(self.purl)
12021203

12031204
def to_dict(self):
1204-
return super().to_dict(with_details=False)
1205+
return super().to_dict(with_details=False)
12051206

12061207
@classmethod
12071208
def from_package_data(cls, package_data, datafile_path):
@@ -1340,6 +1341,24 @@ def get_packages_files(self, codebase):
13401341
yield resource
13411342

13421343

1344+
@attr.attributes(slots=True)
1345+
class PackageWithResources(Package):
1346+
"""
1347+
A Package with Resources.
1348+
"""
1349+
1350+
resources = List(
1351+
item_type=Resource,
1352+
label='List of Resources',
1353+
help='List of Resources for this package.',
1354+
)
1355+
1356+
def to_dict(self):
1357+
package_data = super().to_dict()
1358+
package_data['resources'] = [resource.to_dict() for resource in self.resources]
1359+
return package_data
1360+
1361+
13431362
def get_files_for_packages(codebase):
13441363
"""
13451364
Yield tuple of (Resource, package_uid) for all resources in codebase that are

src/packagedcode/plugin_package.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from packagedcode.models import Dependency
2626
from packagedcode.models import Package
2727
from packagedcode.models import PackageData
28+
from packagedcode.models import PackageWithResources
2829

2930
TRACE = os.environ.get('SCANCODE_DEBUG_PACKAGE', False)
3031

@@ -153,6 +154,36 @@ def process_codebase(self, codebase, strip_root=False, **kwargs):
153154
create_package_and_deps(codebase, strip_root=strip_root, **kwargs)
154155

155156

157+
def get_installed_packages(root_dir, processes=2, **kwargs):
158+
"""
159+
Yield Package and their Resources as they are found in `root_dir`
160+
"""
161+
from scancode import cli
162+
163+
_, codebase = cli.run_scan(
164+
input=root_dir,
165+
processes=processes,
166+
quiet=True,
167+
verbose=False,
168+
max_in_memory=0,
169+
return_results=False,
170+
return_codebase=True,
171+
system_package=True,
172+
)
173+
174+
packages_by_uid = {}
175+
for package in codebase.attributes.packages:
176+
p = PackageWithResources.from_dict(package)
177+
packages_by_uid[p.package_uid] = p
178+
179+
for resource in codebase.walk():
180+
for package_uid in resource.for_packages:
181+
p = packages_by_uid[package_uid]
182+
p.resources.append(resource)
183+
184+
yield from packages_by_uid.values()
185+
186+
156187
def create_package_and_deps(codebase, strip_root=False, **kwargs):
157188
"""
158189
Create and save top-level Package and Dependency from the parsed

src/scancode/cli.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,9 @@ def run_scan(
504504
echo_func=None,
505505
timing=False,
506506
keep_temp_files=False,
507+
# TODO: Review return_results as it does not return Packages and Dependencies
507508
return_results=True,
509+
return_codebase=False,
508510
test_mode=False,
509511
test_slow_mode=False,
510512
test_error_mode=False,
@@ -522,6 +524,12 @@ def run_scan(
522524
error. See scancode() for arguments details.
523525
"""
524526

527+
assert not (return_results is True and return_codebase is True), 'Only one of return_results and return_codebase can be True'
528+
529+
if return_codebase and max_in_memory > 0:
530+
# We're keeping temp files otherwise the codebase is gone
531+
keep_temp_files = True
532+
525533
plugins_option_defaults = {clio.name: clio.default for clio in plugin_options}
526534
requested_options = dict(plugins_option_defaults)
527535
requested_options.update(kwargs)
@@ -667,7 +675,7 @@ def echo_func(*_args, **_kwargs):
667675
'selected when using only scan data.')
668676
raise ScancodeCliUsageError(msg)
669677

670-
if not output_plugins and not return_results:
678+
if not output_plugins and not (return_results or return_codebase):
671679
msg = ('ERROR: Missing output option(s): at least one output '
672680
'option is required to save scan results.')
673681
raise ScancodeCliUsageError(msg)
@@ -1002,6 +1010,8 @@ def echo_func(*_args, **_kwargs):
10021010
# the structure is exactly the same as the JSON output
10031011
from formattedcode.output_json import get_results
10041012
results = get_results(codebase, as_list=True, **requested_options)
1013+
elif return_codebase:
1014+
results = codebase
10051015

10061016
finally:
10071017
# remove temporary files
@@ -1657,3 +1667,9 @@ def get_pretty_params(ctx, generic_paths=False):
16571667
options.append((cli_opt, value))
16581668

16591669
return dict(sorted(args) + sorted(options))
1670+
1671+
1672+
if __name__ == '__main__':
1673+
# We have this __main__ block so that we can run scancode as a script.
1674+
# This is needed so we can use the Python debugging features in VSCode.
1675+
scancode()

0 commit comments

Comments
 (0)