Skip to content

Commit

Permalink
--require-override in cli (#9195)
Browse files Browse the repository at this point in the history
  • Loading branch information
memsharded committed Jul 21, 2021
1 parent 84c8010 commit ae7732b
Show file tree
Hide file tree
Showing 9 changed files with 102 additions and 30 deletions.
9 changes: 6 additions & 3 deletions conans/client/cmd/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def _get_test_conanfile_path(tf, conanfile_path):

def create(app, ref, graph_info, remotes, update, build_modes,
manifest_folder, manifest_verify, manifest_interactive, keep_build, test_build_folder,
test_folder, conanfile_path, recorder, is_build_require=False):
test_folder, conanfile_path, recorder, is_build_require=False, require_overrides=None):
assert isinstance(ref, ConanFileReference), "ref needed"
test_conanfile_path = _get_test_conanfile_path(test_folder, conanfile_path)

Expand Down Expand Up @@ -76,7 +76,9 @@ def create(app, ref, graph_info, remotes, update, build_modes,
manifest_interactive=manifest_interactive,
keep_build=keep_build,
test_build_folder=test_build_folder,
recorder=recorder)
recorder=recorder,
require_overrides=require_overrides
)
else:
deps_install(app=app,
ref_or_path=ref,
Expand All @@ -92,4 +94,5 @@ def create(app, ref, graph_info, remotes, update, build_modes,
update=update,
keep_build=keep_build,
recorder=recorder,
is_build_require=is_build_require)
is_build_require=is_build_require,
require_overrides=require_overrides)
5 changes: 3 additions & 2 deletions conans/client/cmd/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
def install_build_and_test(app, conanfile_abs_path, reference, graph_info,
remotes, update, build_modes=None, manifest_folder=None,
manifest_verify=False, manifest_interactive=False, keep_build=False,
test_build_folder=None, recorder=None):
test_build_folder=None, recorder=None, require_overrides=None):
"""
Installs the reference (specified by the parameters or extracted from the test conanfile)
and builds the test_package/conanfile.py running the test() method.
Expand All @@ -36,7 +36,8 @@ def install_build_and_test(app, conanfile_abs_path, reference, graph_info,
manifest_verify=manifest_verify,
manifest_interactive=manifest_interactive,
keep_build=keep_build,
recorder=recorder)
recorder=recorder,
require_overrides=require_overrides)
cmd_build(app, conanfile_abs_path, test_build_folder,
source_folder=base_folder, build_folder=test_build_folder,
package_folder=os.path.join(test_build_folder, "package"),
Expand Down
13 changes: 10 additions & 3 deletions conans/client/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,8 @@ def create(self, *args):
' revision and url even if there are uncommitted changes')
parser.add_argument("--build-require", action='store_true', default=False,
help='The provided reference is a build-require')
parser.add_argument("--require-override", action="append",
help="Define a requirement override")

_add_manifests_arguments(parser)
_add_common_install_arguments(parser, build_help=_help_build_policies.format("package name"))
Expand Down Expand Up @@ -392,7 +394,8 @@ def create(self, *args):
lockfile_out=args.lockfile_out,
ignore_dirty=args.ignore_dirty,
profile_build=profile_build,
is_build_require=args.build_require)
is_build_require=args.build_require,
require_overrides=args.require_override)
except ConanException as exc:
info = exc.info
raise
Expand Down Expand Up @@ -496,6 +499,8 @@ def install(self, *args):
_add_common_install_arguments(parser, build_help=_help_build_policies.format("never"))
parser.add_argument("--lockfile-node-id", action=OnceArgument,
help="NodeID of the referenced package in the lockfile")
parser.add_argument("--require-override", action="append",
help="Define a requirement override")

args = parser.parse_args(*args)
self._check_lockfile_args(args)
Expand Down Expand Up @@ -529,7 +534,8 @@ def install(self, *args):
no_imports=args.no_imports,
install_folder=args.install_folder,
lockfile=args.lockfile,
lockfile_out=args.lockfile_out)
lockfile_out=args.lockfile_out,
require_overrides=args.require_override)
else:
if args.reference:
raise ConanException("A full reference was provided as first argument, second "
Expand All @@ -554,7 +560,8 @@ def install(self, *args):
lockfile=args.lockfile,
lockfile_out=args.lockfile_out,
lockfile_node_id=args.lockfile_node_id,
is_build_require=args.build_require)
is_build_require=args.build_require,
require_overrides=args.require_override)

except ConanException as exc:
info = exc.info
Expand Down
16 changes: 10 additions & 6 deletions conans/client/conan_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ def create(self, conanfile_path, name=None, version=None, user=None, channel=Non
manifests=None, manifests_interactive=None,
remote_name=None, update=False, cwd=None, test_build_folder=None,
lockfile=None, lockfile_out=None, ignore_dirty=False, profile_build=None,
is_build_require=False, conf=None):
is_build_require=False, conf=None, require_overrides=None):
"""
API method to create a conan package
Expand Down Expand Up @@ -388,7 +388,7 @@ def create(self, conanfile_path, name=None, version=None, user=None, channel=Non
create(self.app, ref, graph_info, remotes, update, build_modes,
manifest_folder, manifest_verify, manifest_interactive, keep_build,
test_build_folder, test_folder, conanfile_path, recorder=recorder,
is_build_require=is_build_require)
is_build_require=is_build_require, require_overrides=require_overrides)

if lockfile_out:
lockfile_out = _make_abs_path(lockfile_out, cwd)
Expand Down Expand Up @@ -537,7 +537,8 @@ def install_reference(self, reference, settings=None, options=None, env=None,
manifests_interactive=None, build=None, profile_names=None,
update=False, generators=None, install_folder=None, cwd=None,
lockfile=None, lockfile_out=None, profile_build=None,
lockfile_node_id=None, is_build_require=False, conf=None):
lockfile_node_id=None, is_build_require=False, conf=None,
require_overrides=None):
profile_host = ProfileData(profiles=profile_names, settings=settings, options=options,
env=env, conf=conf)
recorder = ActionRecorder()
Expand All @@ -562,7 +563,8 @@ def install_reference(self, reference, settings=None, options=None, env=None,
generators=generators, recorder=recorder,
lockfile_node_id=lockfile_node_id,
is_build_require=is_build_require,
add_txt_generator=False)
add_txt_generator=False,
require_overrides=require_overrides)

if lockfile_out:
lockfile_out = _make_abs_path(lockfile_out, cwd)
Expand All @@ -581,7 +583,8 @@ def install(self, path="", name=None, version=None, user=None, channel=None,
remote_name=None, verify=None, manifests=None,
manifests_interactive=None, build=None, profile_names=None,
update=False, generators=None, no_imports=False, install_folder=None, cwd=None,
lockfile=None, lockfile_out=None, profile_build=None, conf=None):
lockfile=None, lockfile_out=None, profile_build=None, conf=None,
require_overrides=None):
profile_host = ProfileData(profiles=profile_names, settings=settings, options=options,
env=env, conf=conf)
recorder = ActionRecorder()
Expand Down Expand Up @@ -613,7 +616,8 @@ def install(self, path="", name=None, version=None, user=None, channel=None,
manifest_interactive=manifest_interactive,
generators=generators,
no_imports=no_imports,
recorder=recorder)
recorder=recorder,
require_overrides=require_overrides)

if lockfile_out:
lockfile_out = _make_abs_path(lockfile_out, cwd)
Expand Down
33 changes: 21 additions & 12 deletions conans/client/graph/graph_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,15 @@ def load_consumer_conanfile(self, conanfile_path, info_folder,

def load_graph(self, reference, create_reference, graph_info, build_mode, check_updates, update,
remotes, recorder, apply_build_requires=True, lockfile_node_id=None,
is_build_require=False):
is_build_require=False, require_overrides=None):
""" main entry point to compute a full dependency graph
"""
profile_host, profile_build = graph_info.profile_host, graph_info.profile_build
graph_lock, root_ref = graph_info.graph_lock, graph_info.root

root_node = self._load_root_node(reference, create_reference, profile_host, graph_lock,
root_ref, lockfile_node_id, is_build_require)
root_ref, lockfile_node_id, is_build_require,
require_overrides)
deps_graph = self._resolve_graph(root_node, profile_host, profile_build, graph_lock,
build_mode, check_updates, update, remotes, recorder,
apply_build_requires=apply_build_requires)
Expand All @@ -134,7 +135,7 @@ def load_graph(self, reference, create_reference, graph_info, build_mode, check_
return deps_graph

def _load_root_node(self, reference, create_reference, profile_host, graph_lock, root_ref,
lockfile_node_id, is_build_require):
lockfile_node_id, is_build_require, require_overrides):
""" creates the first, root node of the graph, loading or creating a conanfile
and initializing it (settings, options) as necessary. Also locking with lockfile
information
Expand All @@ -149,17 +150,20 @@ def _load_root_node(self, reference, create_reference, profile_host, graph_lock,
# create (without test_package), install|info|graph|export-pkg <ref>
if isinstance(reference, ConanFileReference):
return self._load_root_direct_reference(reference, graph_lock, profile_host,
lockfile_node_id, is_build_require)
lockfile_node_id, is_build_require,
require_overrides)

path = reference # The reference must be pointing to a user space conanfile
if create_reference: # Test_package -> tested reference
return self._load_root_test_package(path, create_reference, graph_lock, profile_host)
return self._load_root_test_package(path, create_reference, graph_lock, profile_host,
require_overrides)

# It is a path to conanfile.py or conanfile.txt
root_node = self._load_root_consumer(path, graph_lock, profile_host, root_ref)
root_node = self._load_root_consumer(path, graph_lock, profile_host, root_ref,
require_overrides)
return root_node

def _load_root_consumer(self, path, graph_lock, profile, ref):
def _load_root_consumer(self, path, graph_lock, profile, ref, require_overrides):
""" load a CONSUMER node from a user space conanfile.py or conanfile.txt
install|info|create|graph <path>
:path full path to a conanfile
Expand Down Expand Up @@ -188,7 +192,8 @@ def _load_root_consumer(self, path, graph_lock, profile, ref):
version=ref.version,
user=ref.user,
channel=ref.channel,
lock_python_requires=lock_python_requires)
lock_python_requires=lock_python_requires,
require_overrides=require_overrides)

ref = ConanFileReference(conanfile.name, conanfile.version,
ref.user, ref.channel, validate=False)
Expand All @@ -205,7 +210,7 @@ def _load_root_consumer(self, path, graph_lock, profile, ref):
return root_node

def _load_root_direct_reference(self, reference, graph_lock, profile, lockfile_node_id,
is_build_require):
is_build_require, require_overrides):
""" When a full reference is provided:
install|info|graph <ref> or export-pkg .
:return a VIRTUAL root_node with a conanfile that requires the reference
Expand All @@ -215,14 +220,16 @@ def _load_root_direct_reference(self, reference, graph_lock, profile, lockfile_n
"reference without revision")

conanfile = self._loader.load_virtual([reference], profile,
is_build_require=is_build_require)
is_build_require=is_build_require,
require_overrides=require_overrides)
root_node = Node(ref=None, conanfile=conanfile, context=CONTEXT_HOST, recipe=RECIPE_VIRTUAL)
# Build_requires cannot be found as early as this, because there is no require yet
if graph_lock and not is_build_require: # Find the Node ID in the lock of current root
graph_lock.find_require_and_lock(reference, conanfile, lockfile_node_id)
return root_node

def _load_root_test_package(self, path, create_reference, graph_lock, profile):
def _load_root_test_package(self, path, create_reference, graph_lock, profile,
require_overrides):
""" when a test_package/conanfile.py is provided, together with the reference that is
being created and need to be tested
:return a CONSUMER root_node with a conanfile.py with an injected requires to the
Expand All @@ -231,7 +238,9 @@ def _load_root_test_package(self, path, create_reference, graph_lock, profile):
test = str(create_reference)
# do not try apply lock_python_requires for test_package/conanfile.py consumer
conanfile = self._loader.load_consumer(path, profile, user=create_reference.user,
channel=create_reference.channel)
channel=create_reference.channel,
require_overrides=require_overrides
)
conanfile.display_name = "%s (test package)" % str(test)
conanfile.output.scope = conanfile.display_name

Expand Down
14 changes: 12 additions & 2 deletions conans/client/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ def _initialize_conanfile(conanfile, profile):
conanfile.conf = profile.conf.get_conanfile_conf(ref_str)

def load_consumer(self, conanfile_path, profile_host, name=None, version=None, user=None,
channel=None, lock_python_requires=None):
channel=None, lock_python_requires=None, require_overrides=None):
""" loads a conanfile.py in user space. Might have name/version or not
"""
conanfile = self.load_named(conanfile_path, name, version, user, channel,
Expand All @@ -226,6 +226,11 @@ def load_consumer(self, conanfile_path, profile_host, name=None, version=None, u
name=conanfile.name)
profile_host.user_options.clear_unscoped_options()

if require_overrides is not None:
for req_override in require_overrides:
req_override = ConanFileReference.loads(req_override)
conanfile.requires.override(req_override)

return conanfile
except ConanInvalidConfiguration:
raise
Expand Down Expand Up @@ -309,7 +314,7 @@ def _parse_conan_txt(self, contents, path, display_name, profile):
return conanfile

def load_virtual(self, references, profile_host, scope_options=True,
build_requires_options=None, is_build_require=False):
build_requires_options=None, is_build_require=False, require_overrides=None):
# If user don't specify namespace in options, assume that it is
# for the reference (keep compatibility)
conanfile = ConanFile(self._output, self._runner, display_name="virtual")
Expand All @@ -324,6 +329,11 @@ def load_virtual(self, references, profile_host, scope_options=True,
for reference in references:
conanfile.requires.add_ref(reference)

if require_overrides is not None:
for req_override in require_overrides:
req_override = ConanFileReference.loads(req_override)
conanfile.requires.override(req_override)

# Allows options without package namespace in conan install commands:
# conan install zlib/1.2.8@lasote/stable -o shared=True
if scope_options:
Expand Down
5 changes: 3 additions & 2 deletions conans/client/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def deps_install(app, ref_or_path, install_folder, base_folder, graph_info, remo
build_modes=None, update=False, manifest_folder=None, manifest_verify=False,
manifest_interactive=False, generators=None, no_imports=False,
create_reference=None, keep_build=False, recorder=None, lockfile_node_id=None,
is_build_require=False, add_txt_generator=True):
is_build_require=False, add_txt_generator=True, require_overrides=None):

""" Fetch and build all dependencies for the given reference
@param app: The ConanApp instance with all collaborators
Expand Down Expand Up @@ -57,7 +57,8 @@ def deps_install(app, ref_or_path, install_folder, base_folder, graph_info, remo
deps_graph = graph_manager.load_graph(ref_or_path, create_reference, graph_info, build_modes,
False, update, remotes, recorder,
lockfile_node_id=lockfile_node_id,
is_build_require=is_build_require)
is_build_require=is_build_require,
require_overrides=require_overrides)
graph_lock = graph_info.graph_lock # After the graph is loaded it is defined
root_node = deps_graph.root
conanfile = root_node.conanfile
Expand Down

0 comments on commit ae7732b

Please sign in to comment.