Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

InstallGraph.reduce #15573

Merged
merged 6 commits into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions conan/cli/commands/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ def graph_build_order(conan_api, parser, subparser, *args):
common_graph_args(subparser)
subparser.add_argument("--order", choices=['recipe', 'configuration'], default="recipe",
help='Select how to order the output, "recipe" by default if not set.')
subparser.add_argument("--reduce", action='store_true', default=False,
help='Reduce the build order, output only those to build')
args = parser.parse_args(*args)

# parameter validation
Expand Down Expand Up @@ -100,6 +102,8 @@ def graph_build_order(conan_api, parser, subparser, *args):
out = ConanOutput()
out.title("Computing the build order")
install_graph = InstallGraph(deps_graph, order=args.order)
if args.reduce:
install_graph.reduce()
install_order_serialized = install_graph.install_build_order()

lockfile = conan_api.lockfile.update_lockfile(lockfile, deps_graph, args.lockfile_packages,
Expand Down
26 changes: 25 additions & 1 deletion conans/client/graph/install_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from conan.api.output import ConanOutput
from conans.client.graph.graph import RECIPE_CONSUMER, RECIPE_VIRTUAL, BINARY_SKIP, \
BINARY_MISSING, BINARY_INVALID, Overrides, BINARY_BUILD
BINARY_MISSING, BINARY_INVALID, Overrides, BINARY_BUILD, BINARY_EDITABLE_BUILD
from conans.errors import ConanInvalidConfiguration, ConanException
from conans.model.package_ref import PkgReference
from conans.model.recipe_ref import RecipeReference
Expand Down Expand Up @@ -111,6 +111,13 @@ def __init__(self):
self.packages = {} # {package_id: _InstallPackageReference}
self.depends = [] # Other REFs, defines the graph topology and operation ordering

@property
def need_build(self):
for package in self.packages.values():
if package.binary in (BINARY_BUILD, BINARY_EDITABLE_BUILD):
return True
return False

@property
def node(self):
return self._node
Expand Down Expand Up @@ -212,6 +219,10 @@ def __init__(self):
self.depends = [] # List of full prefs
self.overrides = Overrides()

@property
def need_build(self):
return self.binary in (BINARY_BUILD, BINARY_EDITABLE_BUILD)

@property
def pref(self):
return PkgReference(self.ref, self.package_id, self.prev)
Expand Down Expand Up @@ -363,6 +374,19 @@ def _initialize_deps_graph(self, deps_graph):
else:
existing.add(node)

def reduce(self):
result = {}
for k, node in self._nodes.items():
if node.need_build:
result[k] = node
else: # Eliminate this element from the graph
dependencies = node.depends
# Find all consumers
for n in self._nodes.values():
if k in n.depends:
n.depends = [d for d in n.depends if d != k] + dependencies
self._nodes = result

def install_order(self, flat=False):
# a topological order by levels, returns a list of list, in order of processing
levels = []
Expand Down
29 changes: 29 additions & 0 deletions conans/test/integration/command_v2/test_info_build_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ def test_info_build_order():
]

assert bo_json == result
c.run("graph build-order consumer --build=missing --reduce --format=json")
bo_json = json.loads(c.stdout)
assert bo_json == result


def test_info_build_order_configuration():
Expand Down Expand Up @@ -109,6 +112,9 @@ def test_info_build_order_configuration():
]

assert bo_json == result
c.run("graph build-order consumer --build=missing --order=configuration --reduce --format=json")
bo_json = json.loads(c.stdout)
assert bo_json == result


def test_info_build_order_configuration_text_formatter():
Expand Down Expand Up @@ -526,3 +532,26 @@ def export(self):
c.run("graph build-order --requires=dep/0.1 --format=json", assert_error=True)
assert "ImportError" in c.out
assert "It is possible that this recipe is not Conan 2.0 ready" in c.out


class TestBuildOrderReduce:
def test_reduce(self):
c = TestClient()
c.save({"liba/conanfile.py": GenConanfile("liba", "0.1"),
"libb/conanfile.py": GenConanfile("libb", "0.1").with_requires("liba/0.1"),
"libc/conanfile.py": GenConanfile("libc", "0.1").with_requires("libb/0.1"),
"consumer/conanfile.txt": "[requires]\nlibc/0.1"})
c.run("create liba")
c.run("create libb")
c.run("create libc")
c.run("remove liba:* -c")
c.run("remove libc:* -c")
c.run("graph build-order consumer --build=missing --reduce --format=json")
bo_json = json.loads(c.stdout)
franramirez688 marked this conversation as resolved.
Show resolved Hide resolved
assert len(bo_json) == 2 # 2 levels
level0 = bo_json[0]
assert len(level0) == 1
assert level0[0]["ref"] == "liba/0.1#a658e7beaaae5d6be0b6f67dcc9859e2"
level1 = bo_json[1]
assert len(level1) == 1
assert level1[0]["depends"] == ["liba/0.1#a658e7beaaae5d6be0b6f67dcc9859e2"]