Skip to content

Commit

Permalink
Add is_direct attribute to dependency model #3780
Browse files Browse the repository at this point in the history
Adds is_direct attribute to differentiate between direct
dependecy relationships and dependencies listed in lockfiles
which have both direct and transitive dependencies together,
which will have is_direct as False.

Reference: #3780
Signed-off-by: Ayan Sinha Mahapatra <[email protected]>
  • Loading branch information
AyanSinhaMahapatra committed Jun 4, 2024
1 parent 69ea6b7 commit 02e83da
Show file tree
Hide file tree
Showing 6 changed files with 1,268 additions and 1 deletion.
19 changes: 19 additions & 0 deletions src/packagedcode/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,14 @@ class DependentPackage(ModelMixin):
'been resolved and this dependency url points to an '
'exact version.')

is_direct = Boolean(
default=True,
label='is direct flag',
help='True if this dependency version requirement is '
'a direct dependency relation between two packages '
'as opposed to a transitive dependency relation, '
'which are present in lockfiles/dependency list.')

resolved_package = Mapping(
label='resolved package data',
help='A mapping of resolved package data for this dependent package, '
Expand Down Expand Up @@ -1072,6 +1080,17 @@ def is_datafile(cls, location, filetypes=tuple(), _bare_filename=False):
actual_type = T.filetype_file.lower()
return any(ft in actual_type for ft in filetypes)

@classmethod
def is_lockfile(cls):
"""
Return True if this is a lockfile, False otherwise.
This has to be implemented by datafile handlers classes
of lockfiles, to return True, in contrast to the default
value False.
"""
return False

@classmethod
def parse(cls, location, package_only=False):
"""
Expand Down
31 changes: 30 additions & 1 deletion src/packagedcode/npm.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ def update_dependencies_by_purl(
is_runtime=False,
is_optional=False,
is_resolved=False,
is_direct=True,
):

metadata_deps = ['peerDependenciesMeta', 'dependenciesMeta']
Expand All @@ -221,6 +222,7 @@ def update_dependencies_by_purl(
is_runtime=is_runtime,
is_optional=is_optional,
is_resolved=is_resolved,
is_direct=is_direct,
)
dependecies_by_purl[dep_purl] = dep_package

Expand All @@ -244,6 +246,7 @@ def update_dependencies_by_purl(
is_runtime=is_runtime,
is_optional=metadata.get("optional"),
is_resolved=is_resolved,
is_direct=is_direct,
)
dependecies_by_purl[dep_purl] = dep_package
continue
Expand All @@ -264,6 +267,7 @@ def update_dependencies_by_purl(
is_runtime=is_runtime,
is_optional=is_optional,
is_resolved=is_resolved,
is_direct=is_direct,
)
dependecies_by_purl[dep_purl] = dep_package

Expand Down Expand Up @@ -476,6 +480,10 @@ def parse(cls, location, package_only=False):

class BaseNpmLockHandler(BaseNpmHandler):

@classmethod
def is_lockfile(cls):
return True

@classmethod
def parse(cls, location, package_only=False):

Expand Down Expand Up @@ -590,6 +598,7 @@ def parse(cls, location, package_only=False):
is_runtime=is_runtime,
is_optional=is_optional,
is_resolved=True,
is_direct=False,
)

# URLs and checksums
Expand Down Expand Up @@ -638,6 +647,7 @@ def parse(cls, location, package_only=False):
is_runtime=is_runtime,
is_optional=is_optional,
is_resolved=False,
is_direct=True,
)

resolved_package.dependencies = [
Expand Down Expand Up @@ -723,6 +733,10 @@ class YarnLockV2Handler(BaseNpmHandler):
def is_datafile(cls, location, filetypes=tuple()):
return super().is_datafile(location, filetypes=filetypes) and is_yarn_v2(location)

@classmethod
def is_lockfile(cls):
return True

@classmethod
def parse(cls, location, package_only=False):
"""
Expand Down Expand Up @@ -833,6 +847,10 @@ class YarnLockV1Handler(BaseNpmHandler):
description = 'yarn.lock lockfile v1 format'
documentation_url = 'https://classic.yarnpkg.com/lang/en/docs/yarn-lock/'

@classmethod
def is_lockfile(cls):
return True

@classmethod
def is_datafile(cls, location, filetypes=tuple()):
return super().is_datafile(location, filetypes=filetypes) and not is_yarn_v2(location)
Expand Down Expand Up @@ -953,6 +971,7 @@ def parse(cls, location, package_only=False):
scope='dependencies',
is_optional=False,
is_runtime=True,
is_direct=True,
)
resolved_package_data.dependencies.append(subdep)

Expand All @@ -972,6 +991,7 @@ def parse(cls, location, package_only=False):
scope='dependencies',
is_optional=False,
is_runtime=True,
is_direct=False,
resolved_package=resolved_package_data.to_dict(),
)
dependencies.append(dep.to_dict())
Expand All @@ -988,6 +1008,10 @@ def parse(cls, location, package_only=False):

class BasePnpmLockHandler(BaseNpmHandler):

@classmethod
def is_lockfile(cls):
return True

@classmethod
def parse(cls, location, package_only=False):
"""
Expand Down Expand Up @@ -1063,19 +1087,22 @@ def parse(cls, location, package_only=False):
scope='dependencies',
dependecies_by_purl=deps_for_resolved_by_purl,
is_resolved=True,
is_direct=False,
)
cls.update_dependencies_by_purl(
dependencies=peer_dependencies,
scope='peerDependencies',
dependecies_by_purl=deps_for_resolved_by_purl,
is_optional=True,
is_direct=False,
)
cls.update_dependencies_by_purl(
dependencies=optional_dependencies,
scope='optionalDependencies',
dependecies_by_purl=deps_for_resolved_by_purl,
is_resolved=True,
is_optional=True,
is_direct=False,
)
cls.update_dependencies_by_purl(
dependencies=peer_dependencies_meta,
Expand Down Expand Up @@ -1122,6 +1149,7 @@ def parse(cls, location, package_only=False):
is_optional=is_optional,
is_runtime=is_runtime,
is_resolved=True,
is_direct=True,
resolved_package=resolved_package.to_dict(),
extra_data=extra_data_deps,
)
Expand Down Expand Up @@ -1577,7 +1605,7 @@ def bundle_deps_mapper(bundle_deps, package):
return package


def deps_mapper(deps, package, field_name):
def deps_mapper(deps, package, field_name, is_direct=True):
"""
Handle deps such as dependencies, devDependencies, peerDependencies, optionalDependencies
return a tuple of (dep type, list of deps)
Expand Down Expand Up @@ -1630,6 +1658,7 @@ def deps_mapper(deps, package, field_name):
purl=purl,
scope=field_name,
extracted_requirement=requirement,
is_direct=is_direct,
**dependency_attributes
)
dependencies.append(dep)
Expand Down
Loading

0 comments on commit 02e83da

Please sign in to comment.