Skip to content

Commit

Permalink
Merge branch 'release/1.34' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
czoido committed Mar 10, 2021
2 parents a866f48 + 210df98 commit e126605
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 35 deletions.
42 changes: 36 additions & 6 deletions conan/tools/cmake/cmakedeps.py
Expand Up @@ -5,6 +5,7 @@

from conans.errors import ConanException
from conans.model.build_info import CppInfo, merge_dicts
from conans.util.conan_v2_mode import conan_v2_error
from conans.util.files import save

COMPONENT_SCOPE = "::"
Expand Down Expand Up @@ -560,12 +561,40 @@ def _check_component_in_requirements(require):
for pkg_require in cpp_info.requires:
_check_component_in_requirements(pkg_require)

def _get_name(self, cpp_info, pkg_name):
# FIXME: This is a workaround to be able to use existing recipes that declare
# FIXME: cpp_info.names["cmake_find_package_multi"] = "xxxxx"
name = cpp_info.names.get(self.name)
if name is not None:
return name
find_name = cpp_info.names.get("cmake_find_package_multi")
if find_name is not None:
# Not displaying a warning, too noisy as this is called many times
conan_v2_error("'{}' defines information for 'cmake_find_package_multi', "
"but not 'CMakeDeps'".format(pkg_name))
return find_name
return cpp_info._name

def _get_filename(self, cpp_info, pkg_name):
# FIXME: This is a workaround to be able to use existing recipes that declare
# FIXME: cpp_info.filenames["cmake_find_package_multi"] = "xxxxx"
name = cpp_info.filenames.get(self.name)
if name is not None:
return name
find_name = cpp_info.filenames.get("cmake_find_package_multi")
if find_name is not None:
# Not displaying a warning, too noisy as this is called many times
conan_v2_error("'{}' defines information for 'cmake_find_package_multi', "
"but not 'CMakeDeps'".format(pkg_name))
return find_name
return cpp_info._name

def _get_require_name(self, pkg_name, req):
pkg, cmp = req.split(COMPONENT_SCOPE) if COMPONENT_SCOPE in req else (pkg_name, req)
pkg_cpp_info = self._conanfile.deps_cpp_info[pkg]
pkg_name = pkg_cpp_info.get_name(self.name)
pkg_name = self._get_name(pkg_cpp_info, pkg_name)
if cmp in pkg_cpp_info.components:
cmp_name = pkg_cpp_info.components[cmp].get_name(self.name)
cmp_name = self._get_name(pkg_cpp_info.components[cmp], pkg_name)
else:
cmp_name = pkg_name
return pkg_name, cmp_name
Expand All @@ -575,7 +604,7 @@ def _get_components(self, pkg_name, cpp_info):
sorted_comps = cpp_info._get_sorted_components()

for comp_name, comp in sorted_comps.items():
comp_genname = cpp_info.components[comp_name].get_name(self.name)
comp_genname = self._get_name(cpp_info.components[comp_name], pkg_name)
comp_requires_gennames = []
for require in comp.requires:
comp_requires_gennames.append(self._get_require_name(pkg_name, require))
Expand Down Expand Up @@ -617,8 +646,8 @@ def content(self):

for pkg_name, cpp_info in self._conanfile.deps_cpp_info.dependencies:
self._validate_components(cpp_info)
pkg_filename = cpp_info.get_filename(self.name)
pkg_findname = cpp_info.get_name(self.name)
pkg_filename = self._get_filename(cpp_info, pkg_name)
pkg_findname = self._get_name(cpp_info, pkg_name)
pkg_version = cpp_info.version

public_deps = self.get_public_deps(cpp_info)
Expand All @@ -628,7 +657,8 @@ def content(self):
if name not in deps_names:
deps_names.append(name)
deps_names = ';'.join(deps_names)
pkg_public_deps_filenames = [self._conanfile.deps_cpp_info[it[0]].get_filename(self.name)
pkg_public_deps_filenames = [self._get_filename(self._conanfile.deps_cpp_info[it[0]],
pkg_name)
for it in public_deps]
config_version = self.config_version_template.format(version=pkg_version)
ret[self._config_version_filename(pkg_filename)] = config_version
Expand Down
3 changes: 2 additions & 1 deletion conans/client/migrations_settings.py
Expand Up @@ -2058,5 +2058,6 @@
"""

settings_1_34_0 = settings_1_33_1
settings_1_34_1 = settings_1_34_0

settings_1_35_0 = settings_1_34_0
settings_1_35_0 = settings_1_34_1
53 changes: 31 additions & 22 deletions conans/model/lock_bundle.py
Expand Up @@ -14,11 +14,12 @@ class LockBundle(object):
products. The format is a json with: For every reference, for each "package_id" for that
reference, list the lockfiles that contain such reference:package_id and the node indexes
inside that lockfile
lock_bundle": {
"app1/0.1@#584778f98ba1d0eb7c80a5ae1fe12fe2": {
"package_id": {
"3bcd6800847f779e0883ee91b411aad9ddd8e83c": {
"packages": [
{
"package_id": "3bcd6800847f779e0883ee91b411aad9ddd8e83c",
"lockfiles": {
"app1_windows.lock": [
"1"
Expand All @@ -27,9 +28,7 @@ class LockBundle(object):
"prev": null,
"modified": null
},
"60fbb0a22359b4888f7ecad69bcdfcd6e70e2784": {
}
},
],
"requires": [
"pkgb/0.1@#cd8f22d6f264f65398d8c534046e8e20",
"tool/0.1@#f096d7d54098b7ad7012f9435d9c33f3"
Expand All @@ -38,9 +37,6 @@ class LockBundle(object):
"""

def __init__(self):
""" The structure is
"
"""
self._nodes = {}

@staticmethod
Expand All @@ -64,8 +60,16 @@ def ref_convert(r):
ref_str = node.ref.full_str()
ref_str = ref_convert(ref_str)
ref_node = result._nodes.setdefault(ref_str, {})
pids_node = ref_node.setdefault("package_id", {})
pid_node = pids_node.setdefault(node.package_id, {})
packages_node = ref_node.setdefault("packages", [])
# Find existing package_id in the list of packages
# This is the equivalent of a setdefault over a dict, but on a list
for pkg in packages_node:
if pkg["package_id"] == node.package_id:
pid_node = pkg
break
else:
pid_node = {"package_id": node.package_id}
packages_node.append(pid_node)
ids = pid_node.setdefault("lockfiles", {})
# TODO: Add check that this prev is always the same
pid_node["prev"] = node.prev
Expand Down Expand Up @@ -95,16 +99,21 @@ def build_order(self):
opened = list(self._nodes.keys())
while opened:
current_level = []
closed = []
for o in opened:
node = self._nodes[o]
requires = node.get("requires", [])
if not any(n in opened for n in requires):
current_level.append(o)

current_level.sort()
levels.append(current_level)
if not any(n in opened for n in requires): # Doesn't have an open requires
# iterate all packages to see if some has prev=null
if any(pkg["prev"] is None for pkg in node["packages"]):
current_level.append(o)
closed.append(o)

if current_level:
current_level.sort()
levels.append(current_level)
# now initialize new level
opened = set(opened).difference(current_level)
opened = set(opened).difference(closed)

return levels

Expand All @@ -118,12 +127,12 @@ def update_bundle(bundle_path, revisions_enabled):
bundle.loads(load(bundle_path))
for node in bundle._nodes.values():
# Each node in bundle belongs to a "ref", and contains lockinfo for every package_id
for bundle_package_ids in node["package_id"].values():
for pkg in node["packages"]:
# Each package_id contains information of multiple lockfiles

# First, compute the modified PREV from all lockfiles
prev = modified = prev_lockfile = None
for lockfile, nodes_ids in bundle_package_ids["lockfiles"].items():
for lockfile, nodes_ids in pkg["lockfiles"].items():
graph_lock_conf = GraphLockFile.load(lockfile, revisions_enabled)
graph_lock = graph_lock_conf.graph_lock

Expand All @@ -139,11 +148,11 @@ def update_bundle(bundle_path, revisions_enabled):
msg = "Lock mismatch for {} prev: {}:{} != {}:{}".format(
ref, prev_lockfile, prev, lockfile, lock_prev)
raise ConanException(msg)
bundle_package_ids["prev"] = prev
bundle_package_ids["modified"] = modified
pkg["prev"] = prev
pkg["modified"] = modified

# Then, update all prev of all config lockfiles
for lockfile, nodes_ids in bundle_package_ids["lockfiles"].items():
for lockfile, nodes_ids in pkg["lockfiles"].items():
graph_lock_conf = GraphLockFile.load(lockfile, revisions_enabled)
graph_lock = graph_lock_conf.graph_lock
for node_id in nodes_ids:
Expand Down
44 changes: 38 additions & 6 deletions conans/test/integration/graph_lock/test_lock_bundle.py
Expand Up @@ -58,9 +58,9 @@ def test_basic():
for level in order:
for ref in level:
# Now get the package_id, lockfile
pkg_ids = bundle[ref]["package_id"]
for pkg_id, lockfile_info in pkg_ids.items():
lockfiles = lockfile_info["lockfiles"]
packages = bundle[ref]["packages"]
for pkg in packages:
lockfiles = pkg["lockfiles"]
lockfile = next(iter(sorted(lockfiles)))

client.run("install {ref} --build={ref} --lockfile={lockfile} "
Expand Down Expand Up @@ -166,9 +166,9 @@ def test_build_requires():
for level in order:
for ref in level:
# Now get the package_id, lockfile
pkg_ids = bundle[ref]["package_id"]
for pkg_id, lockfile_info in pkg_ids.items():
lockfiles = lockfile_info["lockfiles"]
packages = bundle[ref]["packages"]
for pkg in packages:
lockfiles = pkg["lockfiles"]
lockfile = next(iter(sorted(lockfiles)))

client.run("install {ref} --build={ref} --lockfile={lockfile} "
Expand Down Expand Up @@ -222,3 +222,35 @@ def test_build_requires():
assert nodes[n].ref.full_str() == "tool/0.1#f096d7d54098b7ad7012f9435d9c33f3"
assert nodes[n].package_id == "cb054d0b3e1ca595dc66bc2339d40f1f8f04ab31"
assert nodes[n].prev == "9e99cfd92d0d7df79d687b01512ce844"


def test_build_requires_error():
# https://github.com/conan-io/conan/issues/8577
client = TestClient()
# TODO: This is hardcoded
client.run("config set general.revisions_enabled=1")
client.save({"tool/conanfile.py": GenConanfile().with_settings("os"),
"pkga/conanfile.py": GenConanfile().with_settings("os"),
"app1/conanfile.py": GenConanfile().with_settings("os").with_requires("pkga/0.1"),
"profile": "[build_requires]\ntool/0.1"})
client.run("create tool tool/0.1@ -s os=Windows")
client.run("create tool tool/0.1@ -s os=Linux")
client.run("export pkga pkga/0.1@")
client.run("export app1 app1/0.1@")

client.run("lock create --ref=app1/0.1 -pr=profile -s os=Windows "
"--lockfile-out=app1_windows.lock --build=missing")
assert "tool/0.1:3475bd55b91ae904ac96fde0f106a136ab951a5e - Cache" in client.out
client.run("lock create --ref=app1/0.1 -pr=profile -s os=Linux "
"--lockfile-out=app1_linux.lock --build=missing")
assert "tool/0.1:cb054d0b3e1ca595dc66bc2339d40f1f8f04ab31 - Cache" in client.out

client.run("lock bundle create app1_windows.lock app1_linux.lock --bundle-out=lock1.bundle")
client.run("lock bundle build-order lock1.bundle --json=bo.json")
order = client.load("bo.json")
print(order)
order = json.loads(order)
assert order == [
["pkga/0.1@#f096d7d54098b7ad7012f9435d9c33f3"],
["app1/0.1@#5af607abc205b47375f485a98abc3b38"]
]
57 changes: 57 additions & 0 deletions conans/test/unittests/tools/cmake/test_cmakedeps.py
@@ -0,0 +1,57 @@
import pytest
from mock import Mock

from conan.tools.cmake import CMakeDeps
from conans import ConanFile, Settings
from conans.client.tools import environment_append
from conans.errors import ConanException
from conans.model.build_info import CppInfo, DepCppInfo
from conans.model.env_info import EnvValues
from conans.util.conan_v2_mode import CONAN_V2_MODE_ENVVAR


def test_cpp_info_name_cmakedeps():
conanfile = ConanFile(Mock(), None)
conanfile.settings = "os", "compiler", "build_type", "arch"
conanfile.initialize(Settings({"os": ["Windows"],
"compiler": ["gcc"],
"build_type": ["Release"],
"arch": ["x86"]}), EnvValues())

cpp_info = CppInfo("mypkg", "dummy_root_folder1")
cpp_info.names["cmake_find_package_multi"] = "MySuperPkg1"
cpp_info.filenames["cmake_find_package_multi"] = "ComplexFileName1"
conanfile.deps_cpp_info.add("mypkg", cpp_info)

cmakedeps = CMakeDeps(conanfile)
files = cmakedeps.content
assert "TARGET MySuperPkg1::MySuperPkg1" in files["ComplexFileName1Config.cmake"]

with pytest.raises(ConanException,
match="'mypkg' defines information for 'cmake_find_package_multi'"):
with environment_append({CONAN_V2_MODE_ENVVAR: "1"}):
_ = cmakedeps.content


def test_cpp_info_name_cmakedeps_components():
conanfile = ConanFile(Mock(), None)
conanfile.settings = "os", "compiler", "build_type", "arch"
conanfile.initialize(Settings({"os": ["Windows"],
"compiler": ["gcc"],
"build_type": ["Release"],
"arch": ["x86"]}), EnvValues())

cpp_info = CppInfo("mypkg", "dummy_root_folder1")
cpp_info.names["cmake_find_package_multi"] = "GlobakPkgName1"
cpp_info.components["mycomp"].names["cmake_find_package_multi"] = "MySuperPkg1"
cpp_info.filenames["cmake_find_package_multi"] = "ComplexFileName1"
conanfile.deps_cpp_info.add("mypkg", DepCppInfo(cpp_info))

cmakedeps = CMakeDeps(conanfile)
files = cmakedeps.content
assert "TARGET GlobakPkgName1::MySuperPkg1" in files["ComplexFileName1Config.cmake"]

with pytest.raises(ConanException,
match="'mypkg' defines information for 'cmake_find_package_multi'"):
with environment_append({CONAN_V2_MODE_ENVVAR: "1"}):
_ = cmakedeps.content

0 comments on commit e126605

Please sign in to comment.