103 lines
3.6 KiB
Python
Executable File
103 lines
3.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
"""
|
|
Check that crates under crates/utils don't depend on disallowed workspace crates.
|
|
|
|
Ensures that utility crates remain independent from higher-level crates like store, viewer, and top.
|
|
Dependencies on crates/build and other crates/utils crates are allowed.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import tomli
|
|
|
|
|
|
def main() -> int:
|
|
"""Check utils crate dependencies and return exit code."""
|
|
repo_root = Path(__file__).parent.parent
|
|
utils_dir = repo_root / "crates" / "utils"
|
|
workspace_toml = repo_root / "Cargo.toml"
|
|
|
|
# Parse workspace Cargo.toml to get all workspace crates and their locations
|
|
with open(workspace_toml, "rb") as f:
|
|
workspace_data = tomli.load(f)
|
|
|
|
# Get all workspace crates
|
|
workspace_deps = workspace_data.get("workspace", {}).get("dependencies", {})
|
|
|
|
# Identify disallowed workspace crates (from store, top, viewer)
|
|
# Allowed: crates/utils and crates/build
|
|
disallowed_workspace_crates = set()
|
|
|
|
for crate_name, crate_info in workspace_deps.items():
|
|
if not isinstance(crate_info, dict) or "path" not in crate_info:
|
|
continue
|
|
|
|
crate_path = crate_info["path"]
|
|
# Disallow dependencies on store, top, and viewer crates
|
|
if crate_path.startswith(("crates/store/", "crates/top/", "crates/viewer/")):
|
|
disallowed_workspace_crates.add(crate_name)
|
|
|
|
# Check each Cargo.toml in crates/utils
|
|
errors = []
|
|
for cargo_toml in sorted(utils_dir.glob("*/Cargo.toml")):
|
|
crate_dir = cargo_toml.parent
|
|
crate_name = crate_dir.name
|
|
|
|
with open(cargo_toml, "rb") as f:
|
|
crate_data = tomli.load(f)
|
|
|
|
# Check all dependency sections
|
|
dep_sections = [
|
|
("dependencies", crate_data.get("dependencies", {})),
|
|
("dev-dependencies", crate_data.get("dev-dependencies", {})),
|
|
("build-dependencies", crate_data.get("build-dependencies", {})),
|
|
]
|
|
|
|
# Also check target-specific dependencies
|
|
for target_name, target_data in crate_data.get("target", {}).items():
|
|
if isinstance(target_data, dict):
|
|
dep_sections.append((f"target.{target_name}.dependencies", target_data.get("dependencies", {})))
|
|
dep_sections.append((f"target.{target_name}.dev-dependencies", target_data.get("dev-dependencies", {})))
|
|
dep_sections.append((
|
|
f"target.{target_name}.build-dependencies",
|
|
target_data.get("build-dependencies", {}),
|
|
))
|
|
|
|
for section_name, deps in dep_sections:
|
|
if not isinstance(deps, dict):
|
|
continue
|
|
|
|
for dep_name in deps:
|
|
if dep_name in disallowed_workspace_crates:
|
|
errors.append(
|
|
f"ERROR: {crate_name} ({section_name}) depends on {dep_name}, "
|
|
f"which is a disallowed workspace crate"
|
|
)
|
|
|
|
if errors:
|
|
print("Found disallowed dependencies from crates/utils:\n")
|
|
for error in errors:
|
|
print(error)
|
|
print(
|
|
"\nCrates under crates/utils should only depend on:\n"
|
|
" - Other crates under crates/utils\n"
|
|
" - Crates under crates/build\n"
|
|
" - External crates (from crates.io)\n"
|
|
"\nThey should NOT depend on workspace crates from:\n"
|
|
" - crates/store\n"
|
|
" - crates/top\n"
|
|
" - crates/viewer"
|
|
)
|
|
return 1
|
|
|
|
print("✓ All crates under crates/utils have valid dependencies")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|