Skip to content

Commit

Permalink
Improve module_analyzer (#3079)
Browse files Browse the repository at this point in the history
- Fixed a bug that `direct_deps` wasn't actually returned.
- Added `--exclude-dev-deps` to support calculating without dev
dependencies
- Added `--name-only` flag to only print out module names without
scores.
- Filtered out potential modules parsed that actually don't exist in
BCR. (bazel_dep with override)
  • Loading branch information
meteorcloudy authored Oct 31, 2024
1 parent e1aba23 commit ee96d2f
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 4 deletions.
4 changes: 3 additions & 1 deletion tools/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,16 @@ This script calculates the importance of each module in the BCR based on their P
The graph is constructed based on dependencies of the latest version of each module.

```
usage: module_analyzer.py [-h] [--registry REGISTRY] [--top_n TOP_N]
usage: module_analyzer.py [-h] [--registry REGISTRY] [--top_n TOP_N] [--exclude-dev-deps] [--name-only]
Select module versions matching given patterns.
optional arguments:
-h, --help show this help message and exit
--registry REGISTRY Specify the root path of the registry (default: the current working directory or the workspace root if running with Bazel).
--top_n TOP_N Specify the top N important modules to print out (default: 50).
--exclude-dev-deps Exclude dev dependencies when constructing the dependency graph (default: False).
--name-only Only print the module names without the scores (default: False).
```

You can also run with Bazel, for example:
Expand Down
28 changes: 25 additions & 3 deletions tools/module_analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def get_buildozer_path():
return "buildozer"


def get_direct_dependencies(module_name, version, registry_dir, buildozer):
def get_direct_dependencies(module_name, version, registry_dir, buildozer, exclude_dev_deps):
deps = (
subprocess.check_output(
[buildozer, "print name", f"//modules/{module_name}/{version}/MODULE.bazel:%bazel_dep"],
Expand All @@ -45,6 +45,9 @@ def get_direct_dependencies(module_name, version, registry_dir, buildozer):
.split()
)

if not exclude_dev_deps:
return deps

dev_deps_stat = (
subprocess.check_output(
[buildozer, "print dev_dependency", f"//modules/{module_name}/{version}/MODULE.bazel:%bazel_dep"],
Expand All @@ -60,7 +63,7 @@ def get_direct_dependencies(module_name, version, registry_dir, buildozer):
if dev_deps_stat[i] != "True":
direct_deps.append(dep)

return deps
return direct_deps


def main():
Expand All @@ -77,6 +80,16 @@ def main():
default=50,
help="Specify the top N important modules to print out (default: 50).",
)
parser.add_argument(
"--exclude-dev-deps",
action="store_true",
help="Exclude dev dependencies when constructing the dependency graph (default: False).",
)
parser.add_argument(
"--name-only",
action="store_true",
help="Only print the module names without the scores (default: False).",
)

args = parser.parse_args()

Expand All @@ -91,14 +104,23 @@ def main():
G = nx.DiGraph()
for module in modules:
module_name, version = module.split("@")
for dep in get_direct_dependencies(module_name, version, args.registry, buildozer):
for dep in get_direct_dependencies(module_name, version, args.registry, buildozer, args.exclude_dev_deps):
# It is possible for a MODULE.bazel to contain a bazel_dep with an override that is not in the registry
if not registry.contains(dep):
continue
G.add_edge(module_name, dep)

pagerank = nx.pagerank(G)

sorted_modules = sorted(pagerank.items(), key=lambda x: x[1], reverse=True)

N = min(args.top_n, len(sorted_modules))

if args.name_only:
for module, _ in sorted_modules[:N]:
print(module)
return

print(f"Top {N} Modules by PageRank:")
for module, score in sorted_modules[:N]:
print(f"{module}: {score:.6f}")
Expand Down

0 comments on commit ee96d2f

Please sign in to comment.