mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-12-22 13:45:20 +00:00
84 lines
2.9 KiB
Python
84 lines
2.9 KiB
Python
|
#!/bin/env python3
|
||
|
#
|
||
|
# Copyright © 2024 Institute of Software, CAS. All rights reserved.
|
||
|
#
|
||
|
# SPDX-License-Identifier: Apache-2.0
|
||
|
#
|
||
|
|
||
|
import subprocess
|
||
|
import json
|
||
|
from argparse import ArgumentParser
|
||
|
from collections import defaultdict
|
||
|
|
||
|
def get_cargo_metadata():
|
||
|
result = subprocess.run(
|
||
|
['cargo', 'metadata', '--format-version=1'],
|
||
|
capture_output=True,
|
||
|
text=True
|
||
|
)
|
||
|
if result.returncode != 0:
|
||
|
exit(1)
|
||
|
|
||
|
metadata = json.loads(result.stdout)
|
||
|
return metadata
|
||
|
|
||
|
def find_dependents_of_package(metadata, package_source):
|
||
|
"""Find dependencies based on the provided source identifier and return related package info."""
|
||
|
packages = defaultdict(list)
|
||
|
direct_dependents = defaultdict(list)
|
||
|
|
||
|
# Identify packages from the given package source and record version
|
||
|
for pkg in metadata['packages']:
|
||
|
repository = pkg['repository'] or ''
|
||
|
if package_source in repository:
|
||
|
packages[pkg['name']].append(pkg['version'])
|
||
|
|
||
|
# Find packages that immediately depend on the identified source packages
|
||
|
for node in metadata['resolve']['nodes']:
|
||
|
current_pkg = next(pkg for pkg in metadata['packages'] if pkg['id'] == node['id'])
|
||
|
current_pkg_name = current_pkg['name']
|
||
|
current_pkg_version = current_pkg['version']
|
||
|
|
||
|
for dep_id in node['dependencies']:
|
||
|
dep_pkg = next(pkg for pkg in metadata['packages'] if pkg['id'] == dep_id)
|
||
|
dep_name = dep_pkg['name']
|
||
|
dep_version = dep_pkg['version']
|
||
|
|
||
|
if dep_name in packages:
|
||
|
direct_dependents[(dep_name, dep_version)].append((current_pkg_name, current_pkg_version))
|
||
|
|
||
|
return packages, direct_dependents
|
||
|
|
||
|
def check_for_version_conflicts(packages, direct_dependents):
|
||
|
"""Check if there are multiple versions of dependencies, and return True if conflicts are found."""
|
||
|
has_conflicts = False
|
||
|
|
||
|
for pkg_name, versions in packages.items():
|
||
|
if len(set(versions)) > 1:
|
||
|
has_conflicts = True
|
||
|
print(f"Error: Multiple versions detected for {pkg_name}: {set(versions)}")
|
||
|
for version in set(versions):
|
||
|
print(f" Version {version} used by:")
|
||
|
for dependent, dep_version in direct_dependents[(pkg_name, version)]:
|
||
|
print(f" - {dependent} v{dep_version}")
|
||
|
|
||
|
return has_conflicts
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
parser = ArgumentParser(description='Cargo dependency conflict checker.')
|
||
|
parser.add_argument('package_source', type=str, help='A keyword used to match the repository URL field')
|
||
|
args = parser.parse_args()
|
||
|
|
||
|
metadata = get_cargo_metadata()
|
||
|
if metadata is None:
|
||
|
print("Error: Metadata is empty")
|
||
|
exit(1)
|
||
|
|
||
|
packages, direct_dependents = find_dependents_of_package(metadata, args.package_source)
|
||
|
|
||
|
has_conflicts = check_for_version_conflicts(packages, direct_dependents)
|
||
|
|
||
|
if has_conflicts:
|
||
|
exit(1)
|
||
|
|