Skip to content

Commit

Permalink
extend --build-require to more commands and cases (conan-io#13669)
Browse files Browse the repository at this point in the history
  • Loading branch information
memsharded authored Apr 11, 2023
1 parent 555a54d commit 658916b
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 22 deletions.
17 changes: 10 additions & 7 deletions conan/api/subapi/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

from conan.api.output import ConanOutput
from conan.internal.conan_app import ConanApp
from conans.client.graph.graph import Node, RECIPE_CONSUMER, CONTEXT_HOST, RECIPE_VIRTUAL
from conans.client.graph.graph import Node, RECIPE_CONSUMER, CONTEXT_HOST, RECIPE_VIRTUAL, \
CONTEXT_BUILD
from conans.client.graph.graph_binaries import GraphBinariesAnalyzer
from conans.client.graph.graph_builder import DepsGraphBuilder
from conans.client.graph.profile_node_definer import initialize_conanfile_profile, consumer_definer
Expand Down Expand Up @@ -35,15 +36,16 @@ def _load_root_consumer_conanfile(self, path, profile_host, profile_build,
update=update)
ref = RecipeReference(conanfile.name, conanfile.version,
conanfile.user, conanfile.channel)
initialize_conanfile_profile(conanfile, profile_build, profile_host, CONTEXT_HOST,
context = CONTEXT_BUILD if is_build_require else CONTEXT_HOST
initialize_conanfile_profile(conanfile, profile_build, profile_host, context,
is_build_require, ref)
if ref.name:
profile_host.options.scope(ref)
root_node = Node(ref, conanfile, context=CONTEXT_HOST, recipe=RECIPE_CONSUMER, path=path)
root_node = Node(ref, conanfile, context=context, recipe=RECIPE_CONSUMER, path=path)
root_node.should_build = True # It is a consumer, this is something we are building
else:
conanfile = app.loader.load_conanfile_txt(path)
consumer_definer(conanfile, profile_host)
consumer_definer(conanfile, profile_host, profile_build)
root_node = Node(None, conanfile, context=CONTEXT_HOST, recipe=RECIPE_CONSUMER,
path=path)
return root_node
Expand Down Expand Up @@ -86,12 +88,12 @@ def load_root_test_conanfile(self, path, tested_reference, profile_host, profile
root_node = Node(ref, conanfile, recipe=RECIPE_CONSUMER, context=CONTEXT_HOST, path=path)
return root_node

def _load_root_virtual_conanfile(self, profile_host, requires=None, tool_requires=None):
def _load_root_virtual_conanfile(self, profile_host, profile_build, requires, tool_requires):
if not requires and not tool_requires:
raise ConanException("Provide requires or tool_requires")
app = ConanApp(self.conan_api.cache_folder)
conanfile = app.loader.load_virtual(requires=requires, tool_requires=tool_requires)
consumer_definer(conanfile, profile_host)
consumer_definer(conanfile, profile_host, profile_build)
root_node = Node(ref=None, conanfile=conanfile, context=CONTEXT_HOST, recipe=RECIPE_VIRTUAL)
return root_node

Expand All @@ -117,7 +119,8 @@ def load_graph_requires(self, requires, tool_requires, profile_host, profile_bui

self._scope_options(profile_host, requires=requires, tool_requires=tool_requires)
root_node = self._load_root_virtual_conanfile(requires=requires, tool_requires=tool_requires,
profile_host=profile_host)
profile_host=profile_host,
profile_build=profile_build)

# check_updates = args.check_updates if "check_updates" in args else False
deps_graph = self.load_graph(root_node, profile_host=profile_host,
Expand Down
5 changes: 4 additions & 1 deletion conan/cli/commands/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ def graph_info(conan_api, parser, subparser, *args):
help='Print information only for packages that match the patterns')
subparser.add_argument("--deploy", action="append",
help='Deploy using the provided deployer to the output folder')
subparser.add_argument("--build-require", action='store_true', default=False,
help='Whether the provided reference is a build-require')
args = parser.parse_args(*args)

# parameter validation
Expand All @@ -141,7 +143,8 @@ def graph_info(conan_api, parser, subparser, *args):
args.user, args.channel,
profile_host, profile_build, lockfile,
remotes, args.update,
check_updates=args.check_updates)
check_updates=args.check_updates,
is_build_require=args.build_require)
else:
deps_graph = conan_api.graph.load_graph_requires(args.requires, args.tool_requires,
profile_host, profile_build, lockfile,
Expand Down
5 changes: 4 additions & 1 deletion conan/cli/commands/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ def install(conan_api, parser, *args):
help='The root output folder for generated and build files')
parser.add_argument("--deploy", action="append",
help='Deploy using the provided deployer to the output folder')
parser.add_argument("--build-require", action='store_true', default=False,
help='Whether the provided reference is a build-require')
args = parser.parse_args(*args)

validate_common_graph_args(args)
Expand Down Expand Up @@ -64,7 +66,8 @@ def install(conan_api, parser, *args):
deps_graph = conan_api.graph.load_graph_consumer(path, args.name, args.version,
args.user, args.channel,
profile_host, profile_build, lockfile,
remotes, args.update)
remotes, args.update,
is_build_require=args.build_require)
else:
deps_graph = conan_api.graph.load_graph_requires(args.requires, args.tool_requires,
profile_host, profile_build, lockfile,
Expand Down
5 changes: 4 additions & 1 deletion conan/cli/commands/lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ def lock_create(conan_api, parser, subparser, *args):
Create a lockfile from a conanfile or a reference.
"""
common_graph_args(subparser)
subparser.add_argument("--build-require", action='store_true', default=False,
help='Whether the provided reference is a build-require')
args = parser.parse_args(*args)

# parameter validation
Expand All @@ -39,7 +41,8 @@ def lock_create(conan_api, parser, subparser, *args):
graph = conan_api.graph.load_graph_consumer(path, args.name, args.version,
args.user, args.channel,
profile_host, profile_build, lockfile,
remotes, args.build, args.update)
remotes, args.build, args.update,
is_build_require=args.build_require)
else:
graph = conan_api.graph.load_graph_requires(args.requires, args.tool_requires,
profile_host, profile_build, lockfile,
Expand Down
4 changes: 0 additions & 4 deletions conans/client/graph/graph_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,6 @@ def load_graph(self, root_node, profile_host, profile_build, graph_lock=None):
# print("Loading graph")
dep_graph = DepsGraph()

# TODO: Why assign here the settings_build and settings_target?
root_node.conanfile.settings_build = profile_build.processed_settings.copy()
root_node.conanfile.settings_target = None

self._prepare_node(root_node, profile_host, profile_build, Options())
self._initialize_requires(root_node, dep_graph, graph_lock)
dep_graph.add_node(root_node)
Expand Down
21 changes: 13 additions & 8 deletions conans/client/graph/profile_node_definer.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from conans.client.graph.graph import CONTEXT_HOST, CONTEXT_BUILD
from conans.client.graph.graph import CONTEXT_BUILD
from conans.errors import ConanException
from conans.model.recipe_ref import ref_matches

Expand Down Expand Up @@ -28,12 +28,8 @@ def initialize_conanfile_profile(conanfile, profile_build, profile_host, base_co
conanfile.settings_build = profile_build.processed_settings.copy()
# profile target
conanfile.settings_target = None
if base_context == CONTEXT_HOST:
if is_build_require:
conanfile.settings_target = profile_host.processed_settings.copy()
else:
if not is_build_require:
conanfile.settings_target = profile_build.processed_settings.copy()
if is_build_require or base_context == CONTEXT_BUILD:
conanfile.settings_target = profile_host.processed_settings.copy()


def _initialize_conanfile(conanfile, profile, ref):
Expand Down Expand Up @@ -65,7 +61,7 @@ def _initialize_conanfile(conanfile, profile, ref):
conanfile.conf = profile.conf.get_conanfile_conf(ref, conanfile._conan_is_consumer) # Maybe this can be done lazy too


def consumer_definer(conanfile, profile_host):
def consumer_definer(conanfile, profile_host, profile_build):
""" conanfile.txt does not declare settings, but it assumes it uses all the profile settings
These settings are very necessary for helpers like generators to produce the right output
"""
Expand All @@ -76,7 +72,16 @@ def consumer_definer(conanfile, profile_host):
if ref_matches(ref=None, pattern=pattern, is_consumer=True):
tmp_settings.update_values(settings)

tmp_settings_build = profile_build.processed_settings.copy()
package_settings_values_build = profile_build.package_settings_values

for pattern, settings in package_settings_values_build.items():
if ref_matches(ref=None, pattern=pattern, is_consumer=True):
tmp_settings_build.update_values(settings)

conanfile.settings = tmp_settings
conanfile.settings_build = tmp_settings_build
conanfile.settings_target = None
conanfile.settings._frozen = True
conanfile._conan_buildenv = profile_host.buildenv
conanfile._conan_runenv = profile_host.runenv
Expand Down
65 changes: 65 additions & 0 deletions conans/test/integration/lockfile/test_lock_build_requires.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
import textwrap

from conans.test.assets.genconanfile import GenConanfile
from conans.test.utils.tools import TestClient
Expand Down Expand Up @@ -52,3 +53,67 @@ def test_lock_buildrequires_create_transitive():
lock = json.loads(c.load("conan.lock"))
assert "tool/0.1#e4f0da4d9097c4da0725ea25b8bf83c8" in lock["build_requires"][0]
assert "dep/0.1#f8c2264d0b32a4c33f251fe2944bb642" in lock["build_requires"][1]


def test_lock_create_build_require_transitive():
""" cross compiling from Windows to Linux
"""
c = TestClient()
dep = textwrap.dedent("""
from conan import ConanFile
class Dep(ConanFile):
name = "dep"
settings = "os"
def package_id(self):
self.output.info(f"MYOS:{self.info.settings.os}!!")
self.output.info(f"TARGET:{self.settings_target.os}!!")
""")
tool = textwrap.dedent("""
from conan import ConanFile
class Tool(ConanFile):
name = "tool"
version = "0.1"
requires = "dep/[*]"
settings = "os"
def generate(self):
self.output.info(f"MYOS-GEN:{self.info.settings.os}!!")
self.output.info(f"TARGET-GEN:{self.settings_target.os}!!")
def package_id(self):
self.output.info(f"MYOS:{self.info.settings.os}!!")
self.output.info(f"TARGET:{self.settings_target.os}!!")
""")
c.save({"dep/conanfile.py": dep,
"tool/conanfile.py": tool})
c.run("create dep --build-require --version=0.1 -s:b os=Windows -s:h os=Linux")
assert "dep/0.1: MYOS:Windows!!" in c.out
assert "dep/0.1: TARGET:Linux!!" in c.out

# The lockfile should contain dep in build-requires
c.run("lock create tool --build-require -s:b os=Windows -s:h os=Linux")
assert "dep/0.1: MYOS:Windows!!" in c.out
assert "dep/0.1: TARGET:Linux!!" in c.out
lock = json.loads(c.load("tool/conan.lock"))
assert "dep/0.1" in lock["build_requires"][0]

# Now try to apply it in graph info, even if a new 0.2 verion si there
c.run("create dep --build-require --version=0.2 -s:b os=Windows -s:h os=Linux")
assert "dep/0.2: MYOS:Windows!!" in c.out
assert "dep/0.2: TARGET:Linux!!" in c.out

c.run("graph info tool --build-require -s:b os=Windows -s:h os=Linux")
c.assert_listed_require({"dep/0.1": "Cache"}, build=True)
assert "dep/0.1: MYOS:Windows!!" in c.out
assert "dep/0.1: TARGET:Linux!!" in c.out
assert "conanfile.py (tool/0.1): MYOS:Windows!!" in c.out
assert "conanfile.py (tool/0.1): TARGET:Linux!!" in c.out
assert "context: build" in c.out
assert "context: host" not in c.out

c.run("install tool --build-require -s:b os=Windows -s:h os=Linux")
c.assert_listed_require({"dep/0.1": "Cache"}, build=True)
assert "dep/0.1: MYOS:Windows!!" in c.out
assert "dep/0.1: TARGET:Linux!!" in c.out
assert "conanfile.py (tool/0.1): MYOS:Windows!!" in c.out
assert "conanfile.py (tool/0.1): TARGET:Linux!!" in c.out
assert "conanfile.py (tool/0.1): MYOS-GEN:Windows!!" in c.out
assert "conanfile.py (tool/0.1): TARGET-GEN:Linux!!" in c.out

0 comments on commit 658916b

Please sign in to comment.