Skip to content

Commit

Permalink
[2/n] [xbuild] Add CLI arguments to support new crossbuilding model (#…
Browse files Browse the repository at this point in the history
…5594)

* implement main cli

* fix tests

* better with no default parameter

* add tests

* fix tests

* fix cli: argument '-p' is ambiguous

* preserve old API

* revert test

* no newline if it fits in one line

* fix test

* pass profile_build from the CLI side to the graph

* removed in develop

* review
  • Loading branch information
jgsogo committed Mar 30, 2020
1 parent 1d4d4f8 commit 65e780d
Show file tree
Hide file tree
Showing 11 changed files with 276 additions and 122 deletions.
176 changes: 114 additions & 62 deletions conans/client/command.py

Large diffs are not rendered by default.

100 changes: 55 additions & 45 deletions conans/client/conan_api.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
import sys
from collections import OrderedDict
from collections import namedtuple

from six import StringIO

Expand Down Expand Up @@ -69,6 +70,12 @@
default_manifest_folder = '.conan_manifests'


class ProfileData(namedtuple("ProfileData", ["profiles", "settings", "options", "env"])):
def __bool__(self):
return bool(self.profiles or self.settings or self.options or self.env)
__nonzero__ = __bool__


def api_method(f):
def wrapper(api, *args, **kwargs):
quiet = kwargs.pop("quiet", False)
Expand Down Expand Up @@ -290,17 +297,15 @@ def inspect(self, path, attributes, remote_name=None):
@api_method
def test(self, path, reference, profile_names=None, settings=None, options=None, env=None,
remote_name=None, update=False, build_modes=None, cwd=None, test_build_folder=None,
lockfile=None):
lockfile=None, profile_build=None):

settings = settings or []
options = options or []
env = env or []
profile_host = ProfileData(profiles=profile_names, settings=settings, options=options, env=env)

remotes = self.app.load_remotes(remote_name=remote_name, update=update)
conanfile_path = _get_conanfile_path(path, cwd, py=True)
cwd = cwd or get_cwd()
lockfile = _make_abs_path(lockfile, cwd) if lockfile else None
graph_info = get_graph_info(profile_names, settings, options, env, cwd, None,
graph_info = get_graph_info(profile_host, profile_build, cwd, None,
self.app.cache, self.app.out, lockfile=lockfile)
ref = ConanFileReference.loads(reference)
recorder = ActionRecorder()
Expand All @@ -316,26 +321,24 @@ def create(self, conanfile_path, name=None, version=None, user=None, channel=Non
keep_source=False, keep_build=False, verify=None,
manifests=None, manifests_interactive=None,
remote_name=None, update=False, cwd=None, test_build_folder=None,
lockfile=None, ignore_dirty=False):
lockfile=None, ignore_dirty=False, profile_build=None):
"""
API method to create a conan package
:param test_folder: default None - looks for default 'test' or 'test_package' folder),
string - test_folder path
False - disabling tests
"""
settings = settings or []
options = options or []
env = env or []

profile_host = ProfileData(profiles=profile_names, settings=settings, options=options, env=env)
try:
cwd = cwd or os.getcwd()
recorder = ActionRecorder()
conanfile_path = _get_conanfile_path(conanfile_path, cwd, py=True)

remotes = self.app.load_remotes(remote_name=remote_name, update=update)
lockfile = _make_abs_path(lockfile, cwd) if lockfile else None
graph_info = get_graph_info(profile_names, settings, options, env, cwd, None,
graph_info = get_graph_info(profile_host, profile_build, cwd, None,
self.app.cache, self.app.out, lockfile=lockfile)

# Make sure keep_source is set for keep_build
Expand Down Expand Up @@ -377,12 +380,9 @@ def create(self, conanfile_path, name=None, version=None, user=None, channel=Non
def export_pkg(self, conanfile_path, name, channel, source_folder=None, build_folder=None,
package_folder=None, install_folder=None, profile_names=None, settings=None,
options=None, env=None, force=False, user=None, version=None, cwd=None,
lockfile=None, ignore_dirty=False):

lockfile=None, ignore_dirty=False, profile_build=None):
profile_host = ProfileData(profiles=profile_names, settings=settings, options=options, env=env)
remotes = self.app.load_remotes()
settings = settings or []
options = options or []
env = env or []
cwd = cwd or get_cwd()

try:
Expand Down Expand Up @@ -413,7 +413,7 @@ def export_pkg(self, conanfile_path, name, channel, source_folder=None, build_fo

lockfile = _make_abs_path(lockfile, cwd) if lockfile else None
# Checks that no both settings and info files are specified
graph_info = get_graph_info(profile_names, settings, options, env, cwd, install_folder,
graph_info = get_graph_info(profile_host, profile_build, cwd, install_folder,
self.app.cache, self.app.out, lockfile=lockfile)

new_ref = cmd_export(self.app, conanfile_path, name, version, user, channel, True,
Expand Down Expand Up @@ -459,14 +459,15 @@ def download(self, reference, remote_name=None, packages=None, recipe=False):
@api_method
def workspace_install(self, path, settings=None, options=None, env=None,
remote_name=None, build=None, profile_name=None,
update=False, cwd=None, install_folder=None):
update=False, cwd=None, install_folder=None, profile_build=None):
profile_host = ProfileData(profiles=profile_name, settings=settings, options=options, env=env)
cwd = cwd or get_cwd()
abs_path = os.path.normpath(os.path.join(cwd, path))

remotes = self.app.load_remotes(remote_name=remote_name, update=update)

workspace = Workspace(abs_path, self.app.cache)
graph_info = get_graph_info(profile_name, settings, options, env, cwd, None,
graph_info = get_graph_info(profile_host, profile_build, cwd, None,
self.app.cache, self.app.out)

self.app.out.info("Configuration:")
Expand Down Expand Up @@ -501,8 +502,8 @@ def install_reference(self, reference, settings=None, options=None, env=None,
remote_name=None, verify=None, manifests=None,
manifests_interactive=None, build=None, profile_names=None,
update=False, generators=None, install_folder=None, cwd=None,
lockfile=None):

lockfile=None, profile_build=None):
profile_host = ProfileData(profiles=profile_names, settings=settings, options=options, env=env)
try:
recorder = ActionRecorder()
cwd = cwd or os.getcwd()
Expand All @@ -511,7 +512,7 @@ def install_reference(self, reference, settings=None, options=None, env=None,
manifest_folder, manifest_interactive, manifest_verify = manifests

lockfile = _make_abs_path(lockfile, cwd) if lockfile else None
graph_info = get_graph_info(profile_names, settings, options, env, cwd, None,
graph_info = get_graph_info(profile_host, profile_build, cwd, None,
self.app.cache, self.app.out, lockfile=lockfile)

if not generators: # We don't want the default txt
Expand Down Expand Up @@ -539,16 +540,16 @@ 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=None, profile_build=None):
profile_host = ProfileData(profiles=profile_names, settings=settings, options=options, env=env)
try:
recorder = ActionRecorder()
cwd = cwd or os.getcwd()
manifests = _parse_manifests_arguments(verify, manifests, manifests_interactive, cwd)
manifest_folder, manifest_interactive, manifest_verify = manifests

lockfile = _make_abs_path(lockfile, cwd) if lockfile else None
graph_info = get_graph_info(profile_names, settings, options, env, cwd, None,
graph_info = get_graph_info(profile_host, profile_build, cwd, None,
self.app.cache, self.app.out,
name=name, version=version, user=user, channel=channel,
lockfile=lockfile)
Expand Down Expand Up @@ -605,8 +606,7 @@ def config_install(self, path_or_url, verify_ssl, config_type=None, args=None,
def config_home(self):
return self.cache_folder

def _info_args(self, reference_or_path, install_folder, profile_names, settings, options, env,
lockfile=None):
def _info_args(self, reference_or_path, install_folder, profile_host, profile_build, lockfile=None):
cwd = get_cwd()
if check_valid_ref(reference_or_path):
ref = ConanFileReference.loads(reference_or_path)
Expand All @@ -619,17 +619,17 @@ def _info_args(self, reference_or_path, install_folder, profile_names, settings,
install_folder = None

lockfile = _make_abs_path(lockfile, cwd) if lockfile else None
graph_info = get_graph_info(profile_names, settings, options, env, cwd, install_folder,
graph_info = get_graph_info(profile_host, profile_build, cwd, install_folder,
self.app.cache, self.app.out, lockfile=lockfile)

return ref, graph_info

@api_method
def info_build_order(self, reference, settings=None, options=None, env=None,
profile_names=None, remote_name=None, build_order=None, check_updates=None,
install_folder=None):
reference, graph_info = self._info_args(reference, install_folder, profile_names,
settings, options, env)
install_folder=None, profile_build=None):
profile_host = ProfileData(profiles=profile_names, settings=settings, options=options, env=env)
reference, graph_info = self._info_args(reference, install_folder, profile_host, profile_build)
recorder = ActionRecorder()
remotes = self.app.load_remotes(remote_name=remote_name, check_updates=check_updates)
deps_graph = self.app.graph_manager.load_graph(reference, None, graph_info, ["missing"],
Expand All @@ -639,9 +639,9 @@ def info_build_order(self, reference, settings=None, options=None, env=None,
@api_method
def info_nodes_to_build(self, reference, build_modes, settings=None, options=None, env=None,
profile_names=None, remote_name=None, check_updates=None,
install_folder=None):
reference, graph_info = self._info_args(reference, install_folder, profile_names,
settings, options, env)
install_folder=None, profile_build=None):
profile_host = ProfileData(profiles=profile_names, settings=settings, options=options, env=env)
reference, graph_info = self._info_args(reference, install_folder, profile_host, profile_build)
recorder = ActionRecorder()
remotes = self.app.load_remotes(remote_name=remote_name, check_updates=check_updates)
deps_graph = self.app.graph_manager.load_graph(reference, None, graph_info, build_modes,
Expand All @@ -651,9 +651,10 @@ def info_nodes_to_build(self, reference, build_modes, settings=None, options=Non

@api_method
def info(self, reference_or_path, remote_name=None, settings=None, options=None, env=None,
profile_names=None, update=False, install_folder=None, build=None, lockfile=None):
reference, graph_info = self._info_args(reference_or_path, install_folder, profile_names,
settings, options, env, lockfile=lockfile)
profile_names=None, update=False, install_folder=None, build=None, lockfile=None, profile_build=None):
profile_host = ProfileData(profiles=profile_names, settings=settings, options=options, env=env)
reference, graph_info = self._info_args(reference_or_path, install_folder, profile_host, profile_build,
lockfile=lockfile)
recorder = ActionRecorder()
# FIXME: Using update as check_update?
remotes = self.app.load_remotes(remote_name=remote_name, check_updates=update)
Expand Down Expand Up @@ -1215,7 +1216,7 @@ def build_order(self, lockfile, build=None, cwd=None):
recorder = ActionRecorder()
remotes = self.app.load_remotes()

graph_info = get_graph_info(None, None, None, None,
graph_info = get_graph_info(None, None,
cwd=cwd, install_folder=None,
cache=self.app.cache, output=self.app.out,
lockfile=lockfile)
Expand All @@ -1242,9 +1243,9 @@ def lock_clean_modified(self, lockfile, cwd=None):

@api_method
def create_lock(self, reference, remote_name=None, settings=None, options=None, env=None,
profile_names=None, update=False, lockfile=None, build=None,):
reference, graph_info = self._info_args(reference, None, profile_names,
settings, options, env)
profile_names=None, update=False, lockfile=None, build=None, profile_build=None):
profile_host = ProfileData(profiles=profile_names, settings=settings, options=options, env=env)
reference, graph_info = self._info_args(reference, None, profile_host, profile_build)
recorder = ActionRecorder()
# FIXME: Using update as check_update?
remotes = self.app.load_remotes(remote_name=remote_name, check_updates=update)
Expand All @@ -1260,7 +1261,7 @@ def create_lock(self, reference, remote_name=None, settings=None, options=None,
Conan = ConanAPIV1


def get_graph_info(profile_names, settings, options, env, cwd, install_folder, cache, output,
def get_graph_info(profile_host, profile_build, cwd, install_folder, cache, output,
name=None, version=None, user=None, channel=None, lockfile=None):
if lockfile:
try:
Expand Down Expand Up @@ -1291,7 +1292,7 @@ def get_graph_info(profile_names, settings, options, env, cwd, install_folder, c
graph_info.profile_host = graph_lock_file.profile_host
graph_info.profile_host.process_settings(cache, preprocess=False)

if profile_names or settings or options or env or not graph_info:
if profile_host or profile_build or not graph_info:
if graph_info:
# FIXME: Convert to Exception in Conan 2.0
output.warn("Settings, options, env or profile specified. "
Expand All @@ -1300,10 +1301,19 @@ def get_graph_info(profile_names, settings, options, env, cwd, install_folder, c
"the installed graph-info file."
% install_folder)

profile = profile_from_args(profile_names, settings, options, env, cwd, cache)
profile.process_settings(cache)
phost = profile_from_args(profile_host.profiles, profile_host.settings, profile_host.options,
profile_host.env, cwd, cache)
phost.process_settings(cache)
if profile_build:
# Only work on the profile_build if something is provided
pbuild = profile_from_args(profile_build.profiles, profile_build.settings,
profile_build.options, profile_build.env, cwd, cache)
pbuild.process_settings(cache)
else:
pbuild = None

root_ref = ConanFileReference(name, version, user, channel, validate=False)
graph_info = GraphInfo(profile_host=profile, root_ref=root_ref)
graph_info = GraphInfo(profile_host=phost, profile_build=pbuild, root_ref=root_ref)
# Preprocess settings and convert to real settings
return graph_info

Expand Down
11 changes: 9 additions & 2 deletions conans/client/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,15 @@ def deps_install(app, ref_or_path, install_folder, graph_info, remotes=None, bui
generators = set(generators) if generators else set()
generators.add("txt") # Add txt generator by default

out.info("Configuration:")
out.writeln(graph_info.profile_host.dumps())
if graph_info.profile_build:
out.info("Configuration (profile_host):")
out.writeln(graph_info.profile_host.dumps())
out.info("Configuration (profile_build):")
out.writeln(graph_info.profile_build.dumps())
else:
out.info("Configuration:")
out.writeln(graph_info.profile_host.dumps())

deps_graph = graph_manager.load_graph(ref_or_path, create_reference, graph_info, build_modes,
False, update, remotes, recorder)
root_node = deps_graph.root
Expand Down
3 changes: 2 additions & 1 deletion conans/test/functional/command/info_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ def install_folder_test(self):
client.run("info . --install-folder=MyInstall -s build_type=Release",
assert_error=True) # Re-uses debug from MyInstall folder

self.assertIn("--install-folder cannot be used together with -s, -o, -e or -pr", client.out)
self.assertIn("--install-folder cannot be used together with a"
" host profile (-s, -o, -e or -pr)", client.out)

def graph_test(self):
self.client = TestClient()
Expand Down
6 changes: 4 additions & 2 deletions conans/test/functional/conan_api/two_conan_creates_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,13 @@ def get_conaninfo(info):
return load(os.path.join(folder, "conaninfo.txt"))

settings = ["compiler=Visual Studio", "compiler.version=15", "build_type=Release"]
info = api.create(".", user="conan", channel="stable", settings=settings)
info = api.create(".", name=None, version=None, user="conan", channel="stable",
settings=settings)
self.assertIn("compiler.runtime=MD", get_conaninfo(info))

settings = ["compiler=Visual Studio", "compiler.version=15", "build_type=Debug"]
info = api.create(".", user="conan", channel="stable", settings=settings)
info = api.create(".", name=None, version=None, user="conan", channel="stable",
settings=settings)
self.assertIn("compiler.runtime=MDd", get_conaninfo(info))

def test_api_conanfile_loader_shouldnt_cache(self):
Expand Down
10 changes: 5 additions & 5 deletions conans/test/functional/configuration/profile_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ def setUp(self):
def test_create(self):

# The latest declared profile has priority
self.client.run("create . lib/1.0@user/channel --profile profile1 -p profile2")
self.client.run("create . lib/1.0@user/channel --profile profile1 -pr profile2")
self.assertIn(dedent("""
[env]
ENV1=foo2
Expand All @@ -531,7 +531,7 @@ def test_create(self):
def test_info(self):

# The latest declared profile has priority
self.client.run("create . lib/1.0@user/channel --profile profile1 -p profile2")
self.client.run("create . lib/1.0@user/channel --profile profile1 -pr profile2")

self.client.save({CONANFILE: self.consumer})
self.client.run("info . --profile profile1 --profile profile2")
Expand All @@ -545,7 +545,7 @@ def test_info(self):
def test_install(self):
self.client.run("export . lib/1.0@user/channel")
# Install ref
self.client.run("install lib/1.0@user/channel -p profile1 -p profile2 --build missing")
self.client.run("install lib/1.0@user/channel -pr profile1 -pr profile2 --build missing")
self.assertIn(dedent("""
[env]
ENV1=foo2
Expand All @@ -557,7 +557,7 @@ def test_install(self):

# Install project
self.client.save({CONANFILE: self.consumer})
self.client.run("install . -p profile1 -p profile2 --build")
self.client.run("install . -pr profile1 -pr profile2 --build")
self.assertIn("arch=x86", self.client.out)
self.assertIn(dedent("""
[env]
Expand Down Expand Up @@ -587,7 +587,7 @@ def profile_crazy_inheritance_test(self):
""")

self.client.save({"profile1": profile1, "profile2": profile2})
self.client.run("create . lib/1.0@user/channel --profile profile2 -p profile1")
self.client.run("create . lib/1.0@user/channel --profile profile2 -pr profile1")
self.assertIn(dedent("""
Configuration:
[settings]
Expand Down
Loading

0 comments on commit 65e780d

Please sign in to comment.