blob: 573784059e180b5a3eb9cb65abee82cdc46d9586 [file]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import json
import subprocess
from dataclasses import asdict, dataclass
from graphlib import TopologicalSorter
from pathlib import Path
PROJECT_DIR = Path(__file__).resolve().parents[3]
@dataclass(frozen=True)
class Package:
name: str
version: str
def plan() -> list[Package]:
metadata = json.loads(
subprocess.check_output(
["cargo", "metadata", "--no-deps", "--format-version", "1"],
cwd=PROJECT_DIR,
text=True,
)
)
# --no-deps returns workspace members; Cargo validates their identities.
local = {
Path(package["manifest_path"]).parent: package
for package in metadata["packages"]
}
packages = {
path: package
for path, package in local.items()
if package["publish"] is None or "crates-io" in package["publish"]
}
graph = {}
for path, package in packages.items():
dependencies = set()
for dependency in package["dependencies"]:
if dependency["kind"] == "dev" or "path" not in dependency:
continue
dependency_path = Path(dependency["path"])
if dependency_path in local:
assert dependency_path in packages, (
f"{package['name']} depends on unpublished workspace package "
f"{local[dependency_path]['name']}"
)
dependencies.add(dependency_path)
graph[path] = dependencies
return [
Package(packages[path]["name"], packages[path]["version"])
for path in TopologicalSorter(graph).static_order()
]
if __name__ == "__main__":
print(json.dumps([asdict(package) for package in plan()], indent=2))