-
-
Notifications
You must be signed in to change notification settings - Fork 203
Map unmatched node_modules files
#796
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
9a31374
f29a406
745140b
adfe55a
57000c9
0a950c9
8355ab1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -989,3 +989,102 @@ def flag_processed_archives(project): | |
| continue | ||
|
|
||
| to_archive.update(status=flag.ARCHIVE_PROCESSED) | ||
|
|
||
|
|
||
| def map_javascript_npm_lookup(project, logger=None): | ||
| """Map unmatched ``node_modules`` files.""" | ||
| project_directories = project.codebaseresources.directories() | ||
| project_files = project.codebaseresources.files() | ||
|
|
||
| to_directories_key = ( | ||
| project_directories.to_codebase() | ||
| .no_status() | ||
| .filter(path__regex=r"^.*\/node_modules\/(?!.*\/)") | ||
| .distinct() | ||
| ) | ||
|
|
||
| to_resources = ( | ||
| project_files.to_codebase() | ||
| .no_status() | ||
| .filter(path__regex=r"^.*\/node_modules\/.*$") | ||
| ) | ||
|
|
||
| if not to_directories_key: | ||
| logger("No unmatched ``node_modules`` file is available. Skipping.") | ||
| return | ||
|
|
||
| resource_count = to_resources.count() | ||
|
|
||
| if logger: | ||
| logger( | ||
| f"Mapping {resource_count:,d} to/ resources using javascript map " | ||
| f"against from/ codebase" | ||
| ) | ||
|
|
||
| to_resources_index = pathmap.build_index( | ||
| to_resources.values_list("id", "path"), with_subpaths=True | ||
| ) | ||
|
|
||
| resource_iterator = to_directories_key.iterator(chunk_size=2000) | ||
| last_percent = 0 | ||
| map_count = 0 | ||
| start_time = timer() | ||
|
|
||
| for resource_index, to_directory in enumerate(resource_iterator): | ||
| last_percent = pipes.log_progress( | ||
| logger, | ||
| resource_index, | ||
| resource_count, | ||
| last_percent, | ||
| increment_percent=10, | ||
| start_time=start_time, | ||
| ) | ||
| map_count += _map_javascript_npm_lookup_resource( | ||
| to_directory, | ||
| to_resources, | ||
| to_resources_index, | ||
| project, | ||
| ) | ||
|
|
||
| logger(f"{map_count:,d} resource(s) mapped") | ||
|
|
||
|
|
||
| def _map_javascript_npm_lookup_resource( | ||
| to_directory, | ||
| to_resources, | ||
| to_resources_index, | ||
| project, | ||
| ): | ||
| """Map unmatched ``node_modules`` files.""" | ||
| purl = js.get_purl_from_node_module(to_directory.path) | ||
| matched = to_resources.filter(path__startswith=to_directory.path) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if we have nested |
||
| matched_count = matched.count() | ||
|
|
||
| if not matched: | ||
| return 0 | ||
|
|
||
| package = project.discoveredpackages.filter( | ||
| type=purl.type, | ||
| namespace="" if not purl.namespace else purl.namespace, | ||
| name=purl.name, | ||
| version=purl.version, | ||
| ).first() | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this first() call may be problematic.... this may be a package that is for completely unrelated resources, and we may end-up assigning the wrong resources to a package or the resources to the wrong package
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also since we are doing something to create a package, would we ever be in a case where we have an existing package for the same resources that exists? IMHO it would never exist, otherwise why would be doing this work in the first place? |
||
|
|
||
| if package: | ||
| package.add_resources(matched) | ||
| else: | ||
| if results := purldb.fetch_package(purl=str(purl)): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure about depending on a purldb call deep within a d2d pipe.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How is this different? Is this not mostly a purldb step?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or would you want to have a separate step?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok I get the problem.... @keshav-space @tdruez here my suggestion:
|
||
| package_data = results[0] | ||
| package_data.pop("uuid", None) | ||
| package_data.pop("dependencies", None) | ||
|
|
||
| package = pipes.update_or_create_package( | ||
| project=project, | ||
| package_data=package_data, | ||
| codebase_resources=matched, | ||
| ) | ||
| else: | ||
| return 0 | ||
|
|
||
| matched.update(status=flag.NPM_LOOKUP) | ||
| return matched_count | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,6 +28,8 @@ | |
| from django.core.exceptions import MultipleObjectsReturned | ||
| from django.core.exceptions import ObjectDoesNotExist | ||
|
|
||
| from packageurl import PackageURL | ||
|
|
||
| from scanpipe import pipes | ||
| from scanpipe.models import CodebaseResource | ||
| from scanpipe.pipes import flag | ||
|
|
@@ -261,3 +263,21 @@ def map_related_files(to_resources, to_resource, from_resource, map_type, extra_ | |
| match.update(status=flag.MAPPED) | ||
|
|
||
| return len(transpiled) | ||
|
|
||
|
|
||
| def get_purl_from_node_module(node_module_directory): | ||
| """Return PURL for given a `node_modules` package directory.""" | ||
|
tdruez marked this conversation as resolved.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we have some examples of the paths in the docstring? |
||
| path = Path(node_module_directory) | ||
| path_parts = path.parts | ||
|
|
||
| npm_package = path_parts[-1] | ||
|
|
||
| if "$" in npm_package: | ||
| _, npm_package = npm_package.split("$") | ||
|
|
||
| # Handle the scoped pacakage. | ||
| if "%2F" in npm_package: | ||
| npm_package = npm_package.replace("%2F", "/") | ||
| npm_package = f"%40{npm_package}" | ||
|
|
||
| return PackageURL.from_string(f"pkg:npm/{npm_package}") | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line should come after "if not matched" below at https://github.com/nexB/scancode.io/pull/796/files#diff-5b5fd8c312dacbb59edb7017b5e11bfb2809d756ae5632d7f48a4e3488c6b0d8R1063