blob: 54d0cd4c19fb2f4fa31e4a4bb567d301efb8cd9b [file] [log] [blame]
#!/usr/bin/env python3
# Copyright 2019 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Generates ComponentGraphs from PackageManager data.
The ComponentGraphGenerator is responsible for taking raw Package and service
configuration data and converting this into a ComponentGraph. It handles the
core business logic in the application.
"""
from server.graph import ComponentGraph
from server.graph.component_link import ComponentLink
from server.graph.component_node import ComponentNode
from server.util.url import package_resource_url
from server.util.logging import get_logger
def create_inferred_node(pkg_url, fidl_service):
""" Returns an inferred node derived from a missing link target. """
inferred_node = ComponentNode.create_inferred(pkg_url)
inferred_node.append_offer(fidl_service)
return inferred_node
def component_url_strip_arguments(pkg_url):
""" Strips optional arguments provided in package urls defined in service mappings. """
node_id = pkg_url
# This deals with one specific case of a package url using a list.
if isinstance(node_id, list):
node_id = node_id[0]
return node_id
class ComponentGraphGenerator:
"""Responsible for generating the component graph from the provided sources"""
def __init__(self):
""" Sets up the logging system for the generator. """
self.logger = get_logger(__name__)
def generate(self, packages, service_mappings):
""" Generates the nodes and links of the graph by analyzing the packages """
graph = ComponentGraph()
# Pass 1: Add all the components to the graph
for package in packages:
for path, data in package["files"].items():
# TODO(benwright) - Add cm when V2 is supported.
if path.startswith("meta/") and path.endswith(".cmx"):
node = ComponentNode(
package_resource_url(package["url"], path), data, package["type"])
graph.add_node(node)
# Pass 2: Resolve all the fidl service mappings and attach them to their
# nodes.
for fidl_service, pkg_url in service_mappings.items():
node_id = component_url_strip_arguments(pkg_url)
try:
graph[node_id].append_offer(fidl_service)
except KeyError:
self.logger.warning(
"Missing service package: %s adding inferred node", pkg_url)
graph.add_node(create_inferred_node(pkg_url, fidl_service))
# Pass 3: Connect all the links.
graph_nodes = list(graph.nodes.values())
for node in graph_nodes:
for use_route in node.uses:
if use_route in service_mappings:
service_url = component_url_strip_arguments(service_mappings[use_route])
link = ComponentLink(node.id, service_url, "use", use_route)
graph[service_url].consumers += 1
node.component_use_deps.append(service_url)
graph.add_link(link)
else:
self.logger.warning(
"Missing use route from %s to %s; adding inferred node",
node.id, use_route)
inferred_pkg_url = "fuchsia-pkg://inferred#meta/" + use_route + ".cmx"
graph.add_node(
create_inferred_node(inferred_pkg_url, use_route))
service_mappings[use_route] = inferred_pkg_url
link = ComponentLink(
node.id, inferred_pkg_url, "use", use_route)
graph[inferred_pkg_url].consumers += 1
graph.add_link(link)
return graph