Skip to content

Commit 6cfd5e4

Browse files
committed
packagedcode: handle Bazel module lockfiles
Signed-off-by: kumarasantosh <santosh.pulikond02@gmail.com>
1 parent 5257b7c commit 6cfd5e4

File tree

10 files changed

+616
-3
lines changed

10 files changed

+616
-3
lines changed

src/packagedcode/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
build.AutotoolsConfigureHandler,
5757
build.BazelBuildHandler,
5858
build.BazelModuleHandler,
59+
build.BazelModuleLockHandler,
5960
build.BuckMetadataBzlHandler,
6061
build.BuckPackageHandler,
6162
cargo.CargoLockHandler,

src/packagedcode/build.py

Lines changed: 94 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@
77
# See https://aboutcode.org for more information about nexB OSS projects.
88
#
99

10-
import os
11-
import logging
1210
import ast
11+
import json
12+
import logging
13+
import os
1314
from collections import defaultdict
1415
import re
1516

@@ -444,7 +445,58 @@ def assign_package_to_resources(cls, package, resource, codebase, package_adder)
444445
)
445446

446447

447-
class BazelModuleHandler(models.DatafileHandler):
448+
class BaseBazelModuleHandler(models.DatafileHandler):
449+
@classmethod
450+
def assemble(cls, package_data, resource, codebase, package_adder):
451+
if resource.has_parent():
452+
directory = resource.parent(codebase)
453+
else:
454+
directory = resource
455+
456+
if not directory:
457+
yield from super().assemble(
458+
package_data=package_data,
459+
resource=resource,
460+
codebase=codebase,
461+
package_adder=package_adder,
462+
)
463+
return
464+
465+
if not codebase.has_single_resource:
466+
siblings = list(directory.children(codebase))
467+
else:
468+
siblings = [directory]
469+
470+
pkgdata_resources = []
471+
for datafile_name in ("MODULE.bazel", "MODULE.bazel.lock"):
472+
for sibling in siblings:
473+
if sibling.name != datafile_name:
474+
continue
475+
476+
for sibling_package_data in sibling.package_data:
477+
pkgdata_resources.append(
478+
(models.PackageData.from_dict(sibling_package_data), sibling)
479+
)
480+
481+
if pkgdata_resources:
482+
yield from cls.assemble_from_many(
483+
pkgdata_resources=pkgdata_resources,
484+
codebase=codebase,
485+
package_adder=package_adder,
486+
ignore_name_check=True,
487+
parent_resource=directory,
488+
)
489+
return
490+
491+
yield from super().assemble(
492+
package_data=package_data,
493+
resource=resource,
494+
codebase=codebase,
495+
package_adder=package_adder,
496+
)
497+
498+
499+
class BazelModuleHandler(BaseBazelModuleHandler):
448500
"""
449501
Handle Bazel MODULE.bazel module manifest files used by Bzlmod.
450502
See: https://bazel.build/external/module
@@ -474,6 +526,11 @@ def parse(cls, location, package_only=False):
474526
name = _extract_starlark_kwarg(block, "name")
475527
version = _extract_starlark_kwarg(block, "version")
476528

529+
# Root Bazel modules can omit module(), so fall back to the enclosing
530+
# directory name to keep the manifest assemblable.
531+
if not name:
532+
name = fileutils.file_name(fileutils.parent_directory(location))
533+
477534
# --- Extract bazel_dep() declarations ---
478535
dependencies = []
479536
for dep_match in re.finditer(
@@ -510,3 +567,37 @@ def parse(cls, location, package_only=False):
510567
version=version,
511568
dependencies=dependencies,
512569
)
570+
571+
572+
class BazelModuleLockHandler(BaseBazelModuleHandler):
573+
"""
574+
Handle Bazel MODULE.bazel.lock files and merge their metadata with a
575+
sibling MODULE.bazel manifest during assembly.
576+
"""
577+
578+
datasource_id = "bazel_module_lock"
579+
path_patterns = ("*/MODULE.bazel.lock",)
580+
default_package_type = "bazel"
581+
is_lockfile = True
582+
description = "Bazel MODULE.bazel lockfile"
583+
documentation_url = "https://bazel.build/external/lockfile"
584+
585+
@classmethod
586+
def parse(cls, location, package_only=False):
587+
with open(location, encoding="utf-8", errors="replace") as f:
588+
parsed = json.load(f)
589+
590+
registry_file_hashes = parsed.get("registryFileHashes") or {}
591+
module_extensions = parsed.get("moduleExtensions") or {}
592+
593+
yield models.PackageData(
594+
datasource_id=cls.datasource_id,
595+
type=cls.default_package_type,
596+
extra_data={
597+
"bazel_lockfile_version": parsed.get("lockFileVersion"),
598+
"bazel_registry_file_hashes_count": len(registry_file_hashes),
599+
"bazel_module_extensions": sorted(module_extensions),
600+
"bazel_selected_yanked_versions": parsed.get("selectedYankedVersions")
601+
or {},
602+
},
603+
)

0 commit comments

Comments
 (0)