From e327c67a09a2eb274799910004426369b6889340 Mon Sep 17 00:00:00 2001 From: memsharded Date: Wed, 2 Oct 2024 20:47:42 +0200 Subject: [PATCH] poc for package manifests and SBOM --- conans/client/graph/graph.py | 17 ++++++++ conans/model/conan_file.py | 4 ++ .../graph/test_subgraph_reports.py | 41 +++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 test/integration/graph/test_subgraph_reports.py diff --git a/conans/client/graph/graph.py b/conans/client/graph/graph.py index d79cf16ba1f..00d8f4512a1 100644 --- a/conans/client/graph/graph.py +++ b/conans/client/graph/graph.py @@ -69,6 +69,23 @@ def __init__(self, ref, conanfile, context, recipe=None, path=None, test=False): self.is_conf = False self.replaced_requires = {} # To track the replaced requires for self.dependencies[old-ref] + def subgraph(self): + nodes = [self] + opened = [self] + while opened: + new_opened = [] + for o in opened: + for n in o.neighbors(): + if n not in nodes: + nodes.append(n) + if n not in opened: + new_opened.append(n) + opened = new_opened + + graph = DepsGraph() + graph.nodes = nodes + return graph + def __lt__(self, other): """ @type other: Node diff --git a/conans/model/conan_file.py b/conans/model/conan_file.py index 50cecb9b01e..6d2a23bf05a 100644 --- a/conans/model/conan_file.py +++ b/conans/model/conan_file.py @@ -186,6 +186,10 @@ def output(self): def context(self): return self._conan_node.context + @property + def subgraph(self): + return self._conan_node.subgraph() + @property def dependencies(self): # Caching it, this object is requested many times diff --git a/test/integration/graph/test_subgraph_reports.py b/test/integration/graph/test_subgraph_reports.py new file mode 100644 index 00000000000..940ed55ec24 --- /dev/null +++ b/test/integration/graph/test_subgraph_reports.py @@ -0,0 +1,41 @@ +import json +import os +import textwrap + +from conan.test.assets.genconanfile import GenConanfile +from conan.test.utils.tools import TestClient +from conans.util.files import load + + +def test_subgraph_reports(): + c = TestClient() + subgraph_hook = textwrap.dedent("""\ + import os, json + from conan.tools.files import save + from conans.model.graph_lock import Lockfile + + def post_package(conanfile): + subgraph = conanfile.subgraph + + save(conanfile, os.path.join(conanfile.package_folder, "conangraph.json"), + json.dumps(subgraph.serialize(), indent=2)) + save(conanfile, os.path.join(conanfile.package_folder, "conan.lock"), + Lockfile(subgraph).dumps()) + """) + + c.save_home({"extensions/hooks/subgraph_hook/hook_subgraph.py": subgraph_hook}) + c.save({"dep/conanfile.py": GenConanfile("dep", "0.1"), + "pkg/conanfile.py": GenConanfile("pkg", "0.1").with_requirement("dep/0.1"), + "app/conanfile.py": GenConanfile("app", "0.1").with_requirement("pkg/0.1")}) + c.run("export dep") + c.run("export pkg") + c.run("create app --build=missing --format=json") + + graph = json.loads(c.stdout) + folder = graph["graph"]["nodes"]["2"]["package_folder"] + graph = load(os.path.join(folder, "conangraph.json")) + print(graph) + lock = load(os.path.join(folder, "conan.lock")) + print(lock) + + # Save it in metadata files? => extensible for future manifests