From 760cfa80e3fc32dc7800f3afc855302d97f3e6fa Mon Sep 17 00:00:00 2001 From: memsharded Date: Fri, 11 Jan 2019 02:00:15 +0100 Subject: [PATCH 01/41] rebasing ws --- conans/client/conan_api.py | 9 +++-- conans/client/graph/graph_binaries.py | 15 ++++---- conans/client/graph/graph_builder.py | 36 +++++++------------ conans/client/graph/graph_manager.py | 20 +++++------ conans/client/graph/printer.py | 4 +-- conans/client/graph/proxy.py | 9 ++++- conans/client/manager.py | 2 +- .../package_editable_layout.py | 5 ++- conans/paths/simple_paths.py | 7 +++- .../unittests/model/transitive_reqs_test.py | 8 ++--- .../unittests/model/version_ranges_test.py | 2 +- 11 files changed, 56 insertions(+), 61 deletions(-) diff --git a/conans/client/conan_api.py b/conans/client/conan_api.py index 86f4d1f549f..70740a37fa5 100644 --- a/conans/client/conan_api.py +++ b/conans/client/conan_api.py @@ -49,7 +49,7 @@ from conans.model.ref import ConanFileReference, PackageReference, check_valid_ref from conans.model.version import Version from conans.model.workspace import Workspace -from conans.paths import BUILD_INFO, CONANINFO, get_conan_user_home, CONAN_PACKAGE_LAYOUT_FILE +from conans.paths import BUILD_INFO, CONANINFO, get_conan_user_home from conans.tools import set_global_instances from conans.unicode import get_cwd from conans.util.env_reader import get_env @@ -584,7 +584,7 @@ def info_build_order(self, reference, settings=None, options=None, env=None, recorder = ActionRecorder() deps_graph, _ = self._graph_manager.load_graph(reference, None, graph_info, ["missing"], check_updates, False, remote_name, - recorder, workspace=None) + recorder) return deps_graph.build_order(build_order) @api_method @@ -596,8 +596,7 @@ def info_nodes_to_build(self, reference, build_modes, settings=None, options=Non recorder = ActionRecorder() deps_graph, conanfile = self._graph_manager.load_graph(reference, None, graph_info, build_modes, check_updates, - False, remote_name, recorder, - workspace=None) + False, remote_name, recorder) nodes_to_build = deps_graph.nodes_to_build() return nodes_to_build, conanfile @@ -609,7 +608,7 @@ def info(self, reference, remote_name=None, settings=None, options=None, env=Non recorder = ActionRecorder() deps_graph, conanfile = self._graph_manager.load_graph(reference, None, graph_info, build, update, False, remote_name, - recorder, workspace=None) + recorder) return deps_graph, conanfile @api_method diff --git a/conans/client/graph/graph_binaries.py b/conans/client/graph/graph_binaries.py index 933d757fe1f..95d75fae9d3 100644 --- a/conans/client/graph/graph_binaries.py +++ b/conans/client/graph/graph_binaries.py @@ -3,8 +3,7 @@ from conans.client.graph.graph import (BINARY_BUILD, BINARY_CACHE, BINARY_DOWNLOAD, BINARY_MISSING, BINARY_SKIP, BINARY_UPDATE, BINARY_WORKSPACE, RECIPE_EDITABLE, BINARY_EDITABLE, - RECIPE_CONSUMER, RECIPE_VIRTUAL) -from conans.client.output import ScopedOutput + RECIPE_CONSUMER, RECIPE_VIRTUAL, RECIPE_WORKSPACE) from conans.errors import NoRemoteAvailable, NotFoundException from conans.model.info import ConanInfo from conans.model.manifest import FileTreeManifest @@ -14,12 +13,11 @@ class GraphBinariesAnalyzer(object): - def __init__(self, client_cache, output, remote_manager, workspace): + def __init__(self, client_cache, output, remote_manager): self._client_cache = client_cache self._out = output self._remote_manager = remote_manager self._registry = client_cache.registry - self._workspace = workspace def _get_package_info(self, package_ref, remote): try: @@ -81,6 +79,10 @@ def _evaluate_node(self, node, build_mode, update, evaluated_references, remote_ node.binary = BINARY_EDITABLE return + if node.recipe == RECIPE_WORKSPACE: + node.binary = BINARY_WORKSPACE + return + if build_mode.forced(conanfile, conan_ref): output.warn('Forced build from source') node.binary = BINARY_BUILD @@ -90,11 +92,6 @@ def _evaluate_node(self, node, build_mode, update, evaluated_references, remote_ short_paths=conanfile.short_paths) # Check if dirty, to remove it - local_project = self._workspace[conan_ref] if self._workspace else None - if local_project: - node.binary = BINARY_WORKSPACE - return - with self._client_cache.package_lock(package_ref): if is_dirty(package_folder): output.warn("Package is corrupted, removing folder: %s" % package_folder) diff --git a/conans/client/graph/graph_builder.py b/conans/client/graph/graph_builder.py index ae4129b071e..4086dd299bc 100644 --- a/conans/client/graph/graph_builder.py +++ b/conans/client/graph/graph_builder.py @@ -1,12 +1,11 @@ import time -from conans.client.graph.graph import DepsGraph, Node, RECIPE_WORKSPACE +from conans.client.graph.graph import DepsGraph, Node from conans.errors import (ConanException, ConanExceptionInUserConanfileMethod, conanfile_exception_formatter) from conans.model.conan_file import get_env_context_manager from conans.model.ref import ConanFileReference from conans.model.requires import Requirements -from conans.model.workspace import WORKSPACE_FILE from conans.util.log import logger REFERENCE_CONFLICT, REVISION_CONFLICT = 1, 2 @@ -15,12 +14,11 @@ class DepsGraphBuilder(object): """ Responsible for computing the dependencies graph DepsGraph """ - def __init__(self, proxy, output, loader, resolver, workspace, recorder): + def __init__(self, proxy, output, loader, resolver, recorder): self._proxy = proxy self._output = output self._loader = loader self._resolver = resolver - self._workspace = workspace self._recorder = recorder def load_graph(self, root_node, check_updates, update, remote_name, processed_profile): @@ -227,30 +225,20 @@ def _create_new_node(self, current_node, dep_graph, requirement, public_deps, na check_updates, update, remote_name, processed_profile, alias_ref=None): """ creates and adds a new node to the dependency graph """ - workspace_package = self._workspace[requirement.conan_reference] if self._workspace else None - - if workspace_package: - conanfile_path = workspace_package.conanfile_path - recipe_status = RECIPE_WORKSPACE - remote = WORKSPACE_FILE - new_ref = requirement.conan_reference - else: - try: - result = self._proxy.get_recipe(requirement.conan_reference, - check_updates, update, remote_name, self._recorder) - except ConanException as e: - if current_node.conan_ref: - self._output.error("Failed requirement '%s' from '%s'" - % (requirement.conan_reference, - current_node.conanfile.display_name)) - raise e - conanfile_path, recipe_status, remote, new_ref = result + try: + result = self._proxy.get_recipe(requirement.conan_reference, + check_updates, update, remote_name, self._recorder) + except ConanException as e: + if current_node.conan_ref: + self._output.error("Failed requirement '%s' from '%s'" + % (requirement.conan_reference, + current_node.conanfile.display_name)) + raise e + conanfile_path, recipe_status, remote, new_ref = result dep_conanfile = self._loader.load_conanfile(conanfile_path, processed_profile, ref=requirement.conan_reference) - if workspace_package: - workspace_package.conanfile = dep_conanfile if getattr(dep_conanfile, "alias", None): alias_reference = alias_ref or new_ref.copy_clear_rev() requirement.conan_reference = ConanFileReference.loads(dep_conanfile.alias) diff --git a/conans/client/graph/graph_manager.py b/conans/client/graph/graph_manager.py index 673ad337f9e..1b89c1ad184 100644 --- a/conans/client/graph/graph_manager.py +++ b/conans/client/graph/graph_manager.py @@ -90,7 +90,7 @@ def load_simple_graph(self, reference, profile, recorder): # export-pkg command, not hitting the server # # https://github.com/conan-io/conan/issues/3432 builder = DepsGraphBuilder(self._proxy, self._output, self._loader, self._resolver, - workspace=None, recorder=recorder) + recorder=recorder) processed_profile = ProcessedProfile(profile, create_reference=None) conanfile = self._loader.load_virtual([reference], processed_profile) root_node = Node(None, conanfile, recipe=RECIPE_VIRTUAL) @@ -99,7 +99,7 @@ def load_simple_graph(self, reference, profile, recorder): return graph def load_graph(self, reference, create_reference, graph_info, build_mode, check_updates, update, - remote_name, recorder, workspace): + remote_name, recorder): def _inject_require(conanfile, reference): """ test_package functionality requires injecting the tested package as requirement @@ -140,7 +140,7 @@ def _inject_require(conanfile, reference): deps_graph = self._load_graph(root_node, check_updates, update, build_mode=build_mode, remote_name=remote_name, profile_build_requires=profile.build_requires, - recorder=recorder, workspace=workspace, + recorder=recorder, processed_profile=processed_profile) # THIS IS NECESSARY to store dependencies options in profile, for consumer @@ -168,7 +168,7 @@ def _get_recipe_build_requires(conanfile): return conanfile.build_requires def _recurse_build_requires(self, graph, check_updates, update, build_mode, remote_name, - profile_build_requires, recorder, workspace, processed_profile): + profile_build_requires, recorder, processed_profile): for node in list(graph.nodes): # Virtual conanfiles doesn't have output, but conanfile.py and conanfile.txt do # FIXME: To be improved and build a explicit model for this @@ -202,7 +202,7 @@ def _recurse_build_requires(self, graph, check_updates, update, build_mode, remo build_requires_package_graph = self._load_graph(virtual_node, check_updates, update, build_mode, remote_name, profile_build_requires, - recorder, workspace, + recorder, processed_profile) graph.add_graph(node, build_requires_package_graph, build_require=True) @@ -217,23 +217,23 @@ def _recurse_build_requires(self, graph, check_updates, update, build_mode, remo build_requires_profile_graph = self._load_graph(virtual_node, check_updates, update, build_mode, remote_name, new_profile_build_requires, - recorder, workspace, + recorder, processed_profile) graph.add_graph(node, build_requires_profile_graph, build_require=True) def _load_graph(self, root_node, check_updates, update, build_mode, remote_name, - profile_build_requires, recorder, workspace, processed_profile): + profile_build_requires, recorder, processed_profile): builder = DepsGraphBuilder(self._proxy, self._output, self._loader, self._resolver, - workspace, recorder) + recorder) graph = builder.load_graph(root_node, check_updates, update, remote_name, processed_profile) if build_mode is None: return graph binaries_analyzer = GraphBinariesAnalyzer(self._client_cache, self._output, - self._remote_manager, workspace) + self._remote_manager) binaries_analyzer.evaluate_graph(graph, build_mode, update, remote_name) self._recurse_build_requires(graph, check_updates, update, build_mode, remote_name, - profile_build_requires, recorder, workspace, processed_profile) + profile_build_requires, recorder, processed_profile) return graph diff --git a/conans/client/graph/printer.py b/conans/client/graph/printer.py index 832cee21f4e..4626b5d697f 100644 --- a/conans/client/graph/printer.py +++ b/conans/client/graph/printer.py @@ -1,7 +1,7 @@ from collections import OrderedDict from conans.client.graph.graph import BINARY_SKIP, RECIPE_CONSUMER,\ - RECIPE_VIRTUAL + RECIPE_VIRTUAL, RECIPE_WORKSPACE from conans.client.output import Color from conans.model.ref import PackageReference from conans.model.workspace import WORKSPACE_FILE @@ -34,7 +34,7 @@ def print_graph(deps_graph, out): def _recipes(nodes): for package_id, list_nodes in nodes.items(): node = list_nodes[0] # For printing recipes, we can use the first one - if node.remote == WORKSPACE_FILE: + if node.recipe == RECIPE_WORKSPACE: from_text = "from '%s'" % WORKSPACE_FILE else: from_text = "from local cache" if not node.remote else "from '%s'" % node.remote.name diff --git a/conans/client/graph/proxy.py b/conans/client/graph/proxy.py index 7277a231a07..c1725971084 100644 --- a/conans/client/graph/proxy.py +++ b/conans/client/graph/proxy.py @@ -4,7 +4,7 @@ from conans.client.graph.graph import (RECIPE_DOWNLOADED, RECIPE_INCACHE, RECIPE_NEWER, RECIPE_NOT_IN_REMOTE, RECIPE_NO_REMOTE, RECIPE_UPDATEABLE, - RECIPE_UPDATED, RECIPE_EDITABLE) + RECIPE_UPDATED, RECIPE_EDITABLE, RECIPE_WORKSPACE) from conans.client.output import ScopedOutput from conans.client.recorder.action_recorder import INSTALL_ERROR_MISSING, INSTALL_ERROR_NETWORK from conans.client.remover import DiskRemover @@ -30,6 +30,13 @@ def get_recipe(self, conan_reference, check_updates, update, remote_name, record # TODO: recorder.recipe_fetched_as_editable(reference) return conanfile_path, status, None, conan_reference + if conan_reference in self._client_cache._workspace_refs: + conanfile_path = self._client_cache.conanfile(conan_reference) + status = RECIPE_WORKSPACE + # TODO: log_recipe_got_from_editable(reference) + # TODO: recorder.recipe_fetched_as_editable(reference) + return conanfile_path, status, None, conan_reference + with self._client_cache.conanfile_write_lock(conan_reference): result = self._get_recipe(conan_reference, check_updates, update, remote_name, recorder) conanfile_path, status, remote, reference = result diff --git a/conans/client/manager.py b/conans/client/manager.py index ac614826ae2..108efab85ad 100644 --- a/conans/client/manager.py +++ b/conans/client/manager.py @@ -73,7 +73,7 @@ def install(self, reference, install_folder, graph_info, remote_name=None, build self._user_io.out.writeln(graph_info.profile.dumps()) result = self._graph_manager.load_graph(reference, create_reference, graph_info, build_modes, False, update, remote_name, - self._recorder, None) + self._recorder) deps_graph, conanfile = result if conanfile.display_name == "virtual": diff --git a/conans/paths/package_layouts/package_editable_layout.py b/conans/paths/package_layouts/package_editable_layout.py index 15933f0a93c..21a738c597a 100644 --- a/conans/paths/package_layouts/package_editable_layout.py +++ b/conans/paths/package_layouts/package_editable_layout.py @@ -5,15 +5,14 @@ from conans.model.ref import ConanFileReference from conans.model.ref import PackageReference from conans.paths import CONANFILE, CONAN_PACKAGE_LAYOUT_FILE -from conans.util.files import load class PackageEditableLayout(object): - def __init__(self, linked_package_file, conan_ref): + def __init__(self, base_folder, conan_ref): assert isinstance(conan_ref, ConanFileReference) self._conan_ref = conan_ref - self._base_folder = os.path.normpath(load(linked_package_file)) + self._base_folder = base_folder def conan(self): """ Returns the base folder for this package reference """ diff --git a/conans/paths/simple_paths.py b/conans/paths/simple_paths.py index 225f496ba1b..c8903a73268 100644 --- a/conans/paths/simple_paths.py +++ b/conans/paths/simple_paths.py @@ -5,6 +5,7 @@ from conans.paths import LINKED_PACKAGE_SENTINEL, is_case_insensitive_os from conans.paths.package_layouts.package_cache_layout import PackageCacheLayout from conans.paths.package_layouts.package_editable_layout import PackageEditableLayout +from conans.util.files import load if is_case_insensitive_os(): def check_ref_case(conan_reference, store_folder): @@ -35,6 +36,7 @@ class SimplePaths(object): """ def __init__(self, store_folder): self._store_folder = store_folder + self._workspace_refs = {} @property def store(self): @@ -53,7 +55,10 @@ def package_layout(self, conan_reference, short_paths=False): "It is a {}".format(type(conan_reference)) linked_package_file = self._build_path_to_linked_folder_sentinel(conan_reference) if os.path.exists(linked_package_file): - return PackageEditableLayout(linked_package_file=linked_package_file, + return PackageEditableLayout(base_folder=load(linked_package_file), + conan_ref=conan_reference) + elif conan_reference in self._workspace_refs: + return PackageEditableLayout(base_folder=self._workspace_refs[conan_reference], conan_ref=conan_reference) else: check_ref_case(conan_reference, self.store) diff --git a/conans/test/unittests/model/transitive_reqs_test.py b/conans/test/unittests/model/transitive_reqs_test.py index 1990afb9cc9..c70220ea567 100644 --- a/conans/test/unittests/model/transitive_reqs_test.py +++ b/conans/test/unittests/model/transitive_reqs_test.py @@ -112,7 +112,7 @@ def setUp(self): self.loader = ConanFileLoader(None, self.output, ConanPythonRequire(None, None)) self.retriever = Retriever(self.loader) self.builder = DepsGraphBuilder(self.retriever, self.output, self.loader, - MockRequireResolver(), None, None) + MockRequireResolver(), None) def root(self, content): self.loader.cached_conanfiles = {} @@ -1504,7 +1504,7 @@ def setUp(self): self.loader = ConanFileLoader(None, self.output, ConanPythonRequire(None, None)) self.retriever = Retriever(self.loader) self.builder = DepsGraphBuilder(self.retriever, self.output, self.loader, - MockRequireResolver(), None, None) + MockRequireResolver(), None) liba_ref = ConanFileReference.loads("LibA/0.1@user/testing") libb_ref = ConanFileReference.loads("LibB/0.1@user/testing") libc_ref = ConanFileReference.loads("LibC/0.1@user/testing") @@ -1632,7 +1632,7 @@ def root(self, content, options="", settings=""): profile.options = OptionsValues.loads(options) loader = ConanFileLoader(None, self.output, ConanPythonRequire(None, None)) retriever = Retriever(loader) - builder = DepsGraphBuilder(retriever, self.output, loader, MockRequireResolver(), None, None) + builder = DepsGraphBuilder(retriever, self.output, loader, MockRequireResolver(), None) processed_profile = test_processed_profile(profile=profile) root_conan = retriever.root(content, processed_profile) deps_graph = builder.load_graph(root_conan, False, False, None, processed_profile) @@ -1919,7 +1919,7 @@ class ChatConan(ConanFile): "myoption_chat=on") loader = ConanFileLoader(None, output, ConanPythonRequire(None, None)) retriever = Retriever(loader) - builder = DepsGraphBuilder(retriever, output, loader, MockRequireResolver(), None, None) + builder = DepsGraphBuilder(retriever, output, loader, MockRequireResolver(), None) retriever.conan(say_ref, say_content) retriever.conan(hello_ref, hello_content) diff --git a/conans/test/unittests/model/version_ranges_test.py b/conans/test/unittests/model/version_ranges_test.py index 661f0ec6526..41e8a833d64 100644 --- a/conans/test/unittests/model/version_ranges_test.py +++ b/conans/test/unittests/model/version_ranges_test.py @@ -168,7 +168,7 @@ def setUp(self): paths = SimplePaths(self.retriever.folder) self.resolver = RangeResolver(paths, self.remote_search) self.builder = DepsGraphBuilder(self.retriever, self.output, self.loader, self.resolver, - None, None) + None) for v in ["0.1", "0.2", "0.3", "1.1", "1.1.2", "1.2.1", "2.1", "2.2.1"]: say_content = """ From bc60a752f994a6de87e0c0f7f3690a5d2ece21b9 Mon Sep 17 00:00:00 2001 From: memsharded Date: Fri, 11 Jan 2019 10:51:51 +0100 Subject: [PATCH 02/41] all tests passing but WS ones --- conans/client/graph/graph.py | 2 -- conans/client/graph/graph_binaries.py | 8 ++------ conans/client/graph/graph_manager.py | 7 ++----- conans/client/graph/printer.py | 9 ++++----- conans/client/graph/proxy.py | 9 +-------- .../test/functional/editable/consume_header_only_test.py | 2 +- .../editable/consume_settings_and_options_test.py | 2 +- conans/test/functional/editable/graph_related_test.py | 4 ++-- 8 files changed, 13 insertions(+), 30 deletions(-) diff --git a/conans/client/graph/graph.py b/conans/client/graph/graph.py index cc168b89096..918f4b384ab 100644 --- a/conans/client/graph/graph.py +++ b/conans/client/graph/graph.py @@ -11,7 +11,6 @@ RECIPE_NOT_IN_REMOTE = "Not in remote" RECIPE_UPDATEABLE = "Update available" # The update of the recipe is available (only in conan info) RECIPE_NO_REMOTE = "No remote" -RECIPE_WORKSPACE = "Workspace" RECIPE_EDITABLE = "Editable" RECIPE_CONSUMER = "Consumer" # A conanfile from the user RECIPE_VIRTUAL = "Virtual" # A virtual conanfile (dynamic in memory conanfile) @@ -22,7 +21,6 @@ BINARY_BUILD = "Build" BINARY_MISSING = "Missing" BINARY_SKIP = "Skip" -BINARY_WORKSPACE = "Workspace" BINARY_EDITABLE = "Editable" diff --git a/conans/client/graph/graph_binaries.py b/conans/client/graph/graph_binaries.py index 95d75fae9d3..cf16f3bcd92 100644 --- a/conans/client/graph/graph_binaries.py +++ b/conans/client/graph/graph_binaries.py @@ -1,9 +1,9 @@ import os from conans.client.graph.graph import (BINARY_BUILD, BINARY_CACHE, BINARY_DOWNLOAD, BINARY_MISSING, - BINARY_SKIP, BINARY_UPDATE, BINARY_WORKSPACE, + BINARY_SKIP, BINARY_UPDATE, RECIPE_EDITABLE, BINARY_EDITABLE, - RECIPE_CONSUMER, RECIPE_VIRTUAL, RECIPE_WORKSPACE) + RECIPE_CONSUMER, RECIPE_VIRTUAL) from conans.errors import NoRemoteAvailable, NotFoundException from conans.model.info import ConanInfo from conans.model.manifest import FileTreeManifest @@ -79,10 +79,6 @@ def _evaluate_node(self, node, build_mode, update, evaluated_references, remote_ node.binary = BINARY_EDITABLE return - if node.recipe == RECIPE_WORKSPACE: - node.binary = BINARY_WORKSPACE - return - if build_mode.forced(conanfile, conan_ref): output.warn('Forced build from source') node.binary = BINARY_BUILD diff --git a/conans/client/graph/graph_manager.py b/conans/client/graph/graph_manager.py index 1b89c1ad184..f32c9362f52 100644 --- a/conans/client/graph/graph_manager.py +++ b/conans/client/graph/graph_manager.py @@ -4,7 +4,7 @@ from conans.client.generators.text import TXTGenerator from conans.client.graph.build_mode import BuildMode -from conans.client.graph.graph import BINARY_BUILD, BINARY_WORKSPACE, Node,\ +from conans.client.graph.graph import BINARY_BUILD, Node,\ RECIPE_CONSUMER, RECIPE_VIRTUAL from conans.client.graph.graph_binaries import GraphBinariesAnalyzer from conans.client.graph.graph_builder import DepsGraphBuilder @@ -170,12 +170,9 @@ def _get_recipe_build_requires(conanfile): def _recurse_build_requires(self, graph, check_updates, update, build_mode, remote_name, profile_build_requires, recorder, processed_profile): for node in list(graph.nodes): - # Virtual conanfiles doesn't have output, but conanfile.py and conanfile.txt do - # FIXME: To be improved and build a explicit model for this if node.recipe == RECIPE_VIRTUAL: continue - if (node.binary not in (BINARY_BUILD, BINARY_WORKSPACE) and - node.recipe != RECIPE_CONSUMER): + if (node.binary != BINARY_BUILD and node.recipe != RECIPE_CONSUMER): continue package_build_requires = self._get_recipe_build_requires(node.conanfile) str_ref = str(node.conan_ref) diff --git a/conans/client/graph/printer.py b/conans/client/graph/printer.py index 4626b5d697f..c486c4cb811 100644 --- a/conans/client/graph/printer.py +++ b/conans/client/graph/printer.py @@ -1,10 +1,9 @@ from collections import OrderedDict -from conans.client.graph.graph import BINARY_SKIP, RECIPE_CONSUMER,\ - RECIPE_VIRTUAL, RECIPE_WORKSPACE +from conans.client.graph.graph import BINARY_SKIP, RECIPE_CONSUMER, RECIPE_VIRTUAL,\ + RECIPE_EDITABLE from conans.client.output import Color from conans.model.ref import PackageReference -from conans.model.workspace import WORKSPACE_FILE def _get_python_requires(conanfile): @@ -34,8 +33,8 @@ def print_graph(deps_graph, out): def _recipes(nodes): for package_id, list_nodes in nodes.items(): node = list_nodes[0] # For printing recipes, we can use the first one - if node.recipe == RECIPE_WORKSPACE: - from_text = "from '%s'" % WORKSPACE_FILE + if node.recipe == RECIPE_EDITABLE: + from_text = "from user" else: from_text = "from local cache" if not node.remote else "from '%s'" % node.remote.name out.writeln(" %s %s - %s" % (repr(node.conan_ref), from_text, node.recipe), diff --git a/conans/client/graph/proxy.py b/conans/client/graph/proxy.py index c1725971084..7277a231a07 100644 --- a/conans/client/graph/proxy.py +++ b/conans/client/graph/proxy.py @@ -4,7 +4,7 @@ from conans.client.graph.graph import (RECIPE_DOWNLOADED, RECIPE_INCACHE, RECIPE_NEWER, RECIPE_NOT_IN_REMOTE, RECIPE_NO_REMOTE, RECIPE_UPDATEABLE, - RECIPE_UPDATED, RECIPE_EDITABLE, RECIPE_WORKSPACE) + RECIPE_UPDATED, RECIPE_EDITABLE) from conans.client.output import ScopedOutput from conans.client.recorder.action_recorder import INSTALL_ERROR_MISSING, INSTALL_ERROR_NETWORK from conans.client.remover import DiskRemover @@ -30,13 +30,6 @@ def get_recipe(self, conan_reference, check_updates, update, remote_name, record # TODO: recorder.recipe_fetched_as_editable(reference) return conanfile_path, status, None, conan_reference - if conan_reference in self._client_cache._workspace_refs: - conanfile_path = self._client_cache.conanfile(conan_reference) - status = RECIPE_WORKSPACE - # TODO: log_recipe_got_from_editable(reference) - # TODO: recorder.recipe_fetched_as_editable(reference) - return conanfile_path, status, None, conan_reference - with self._client_cache.conanfile_write_lock(conan_reference): result = self._get_recipe(conan_reference, check_updates, update, remote_name, recorder) conanfile_path, status, remote, reference = result diff --git a/conans/test/functional/editable/consume_header_only_test.py b/conans/test/functional/editable/consume_header_only_test.py index 632c1a8b7c1..7ac773f77bd 100644 --- a/conans/test/functional/editable/consume_header_only_test.py +++ b/conans/test/functional/editable/consume_header_only_test.py @@ -147,7 +147,7 @@ def build(self): # Build consumer project client.run("create . pkg/0.0@user/testing") - self.assertIn(" MyLib/0.1@user/editable from local cache - Editable", client.out) + self.assertIn(" MyLib/0.1@user/editable from user - Editable", client.out) self.assertIn(" MyLib/0.1@user/editable:" "5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9 - Editable", client.out) self.assertIn("Hello EDITABLE!", client.out) diff --git a/conans/test/functional/editable/consume_settings_and_options_test.py b/conans/test/functional/editable/consume_settings_and_options_test.py index 0c55bba86bb..7eaff4ffaf5 100644 --- a/conans/test/functional/editable/consume_settings_and_options_test.py +++ b/conans/test/functional/editable/consume_settings_and_options_test.py @@ -142,6 +142,6 @@ def build(self): # Build consumer project client.run("create . pkg/0.0@user/testing -s build_type={} -o MyLib:shared={}".format(build_type, str(shared))) - self.assertIn(" MyLib/0.1@user/editable from local cache - Editable", client.out) + self.assertIn(" MyLib/0.1@user/editable from user - Editable", client.out) self.assertIn("Hello {}!".format(build_type), client.out) self.assertIn(" - options.shared: {}".format(shared), client.out) diff --git a/conans/test/functional/editable/graph_related_test.py b/conans/test/functional/editable/graph_related_test.py index 33c0c714a2a..ad511eb12d7 100644 --- a/conans/test/functional/editable/graph_related_test.py +++ b/conans/test/functional/editable/graph_related_test.py @@ -88,7 +88,7 @@ def test_install_requirements(self, update): # Install our project and check that everything is in place update = ' --update' if update else '' self.t.run('install {}{}'.format(self.reference, update)) - self.assertIn(" lib/version@user/channel from local cache - Editable", self.t.out) + self.assertIn(" lib/version@user/channel from user - Editable", self.t.out) self.assertIn(" parent/version@lasote/channel from 'default' - Downloaded", self.t.out) self.assertTrue(os.path.exists(self.t.client_cache.conan(ref_parent))) @@ -123,7 +123,7 @@ def test_middle_graph(self, update): child_remote = 'No remote' if update else 'Cache' self.assertIn(" child/version@lasote/channel from local cache - {}".format(child_remote), self.t.out) - self.assertIn(" lib/version@user/channel from local cache - Editable", self.t.out) + self.assertIn(" lib/version@user/channel from user - Editable", self.t.out) self.assertIn(" parent/version@lasote/channel from 'default' - Downloaded", self.t.out) self.assertTrue(os.path.exists(self.t.client_cache.conan(ref_parent))) From 9b9cc2dd5ac9e0d29e5dd6a1986a9a5d71abdc50 Mon Sep 17 00:00:00 2001 From: memsharded Date: Fri, 11 Jan 2019 13:52:30 +0100 Subject: [PATCH 03/41] working, new command workspace install --- conans/client/command.py | 20 +++++++ conans/client/conan_api.py | 35 +++++++----- conans/client/installer.py | 68 +++++++---------------- conans/client/manager.py | 5 +- conans/model/workspace.py | 50 ++++++----------- conans/test/integration/workspace_test.py | 58 +++++++++++++++++++ 6 files changed, 136 insertions(+), 100 deletions(-) diff --git a/conans/client/command.py b/conans/client/command.py index 67c6548510a..9ca4ad9980a 100644 --- a/conans/client/command.py +++ b/conans/client/command.py @@ -1333,6 +1333,26 @@ def alias(self, *args): self._conan.export_alias(args.reference, args.target) + def workspace(self, *args): + """ handle worksapces + + """ + parser = argparse.ArgumentParser(description=self.workspace.__doc__, + prog="conan workspace") + subparsers = parser.add_subparsers(dest='subcommand', help='sub-command help') + + # create the parser for the "a" command + install_parser = subparsers.add_parser('install', help='install this workspace') + install_parser.add_argument('path', help='path to workspace file or folder') + _add_common_install_arguments(install_parser, build_help=_help_build_policies) + + args = parser.parse_args(*args) + + if args.subcommand == "install": + self._conan.install_workspace(args.path, args.settings, args.options, args.env, + args.remote, args.build, + args.profile, args.update) + def link(self, *args): """ Links a conan reference (e.g lib/1.0@conan/stable) with a local folder path. diff --git a/conans/client/conan_api.py b/conans/client/conan_api.py index 70740a37fa5..ef5ebde7ded 100644 --- a/conans/client/conan_api.py +++ b/conans/client/conan_api.py @@ -446,6 +446,26 @@ def download(self, reference, remote_name=None, package=None, recipe=False): else: raise ConanException("Provide a valid full reference without wildcards.") + @api_method + def install_workspace(self, path, settings=None, options=None, env=None, + remote_name=None, build=None, profile_name=None, + update=False, cwd=None): + cwd = cwd or get_cwd() + if os.path.isabs(path): + abs_path = path + else: + abs_path = os.path.normpath(os.path.join(cwd, path)) + + workspace = Workspace(abs_path, None) + graph_info = get_graph_info(profile_name, settings, options, env, cwd, None, + self._client_cache, self._user_io.out) + self._user_io.out.success("Using workspace file from %s" % workspace._base_folder) + + self._client_cache._workspace_refs.update(workspace.get_editable_dict()) + recorder = ActionRecorder() + manager = self._init_manager(recorder) + manager.install_workspace(graph_info, workspace, remote_name, build, update) + @api_method def install_reference(self, reference, settings=None, options=None, env=None, remote_name=None, verify=None, manifests=None, @@ -495,21 +515,6 @@ def install(self, path="", settings=None, options=None, env=None, graph_info = get_graph_info(profile_name, settings, options, env, cwd, None, self._client_cache, self._user_io.out) - wspath = _make_abs_path(path, cwd) - if install_folder: - if os.path.isabs(install_folder): - wsinstall_folder = install_folder - else: - wsinstall_folder = os.path.join(cwd, install_folder) - else: - wsinstall_folder = None - workspace = Workspace.get_workspace(wspath, wsinstall_folder) - if workspace: - self._user_io.out.success("Using conanws.yml file from %s" % workspace._base_folder) - manager = self._init_manager(recorder) - manager.install_workspace(graph_info, workspace, remote_name, build, update) - return - install_folder = _make_abs_path(install_folder, cwd) conanfile_path = _get_conanfile_path(path, cwd, py=None) manager = self._init_manager(recorder) diff --git a/conans/client/installer.py b/conans/client/installer.py index a1a79555a36..8cfa3c3c34c 100644 --- a/conans/client/installer.py +++ b/conans/client/installer.py @@ -9,7 +9,6 @@ from conans.client.graph.graph import BINARY_BUILD, BINARY_CACHE, BINARY_DOWNLOAD, BINARY_MISSING, \ BINARY_SKIP, BINARY_UPDATE, BINARY_EDITABLE from conans.client.importer import remove_imports -from conans.client.output import ScopedOutput from conans.client.packager import create_package from conans.client.recorder.action_recorder import INSTALL_ERROR_BUILDING, INSTALL_ERROR_MISSING, \ INSTALL_ERROR_MISSING_BUILD_FOLDER @@ -28,8 +27,7 @@ from conans.util.env_reader import get_env from conans.util.files import (clean_dirty, is_dirty, make_read_only, mkdir, rmdir, save, set_dirty) from conans.util.log import logger -from conans.util.tracer import log_package_built, \ - log_package_got_from_local_cache +from conans.util.tracer import log_package_built, log_package_got_from_local_cache def build_id(conan_file): @@ -290,16 +288,10 @@ def _build(self, nodes_by_level, deps_graph, keep_build, root_node, graph_info): raise_package_not_found_error(conan_file, conan_ref, package_id, dependencies, out=output, recorder=self._recorder) + self._propagate_info(node, inverse_levels, deps_graph) if node.binary == BINARY_EDITABLE: - self._handle_node_editable(node) - continue - - workspace_package = self._workspace[node.conan_ref] if self._workspace else None - if workspace_package: - self._handle_node_workspace(node, workspace_package, inverse_levels, deps_graph, - graph_info) + self._handle_node_editable(node, graph_info) else: - self._propagate_info(node, inverse_levels, deps_graph) if node.binary == BINARY_SKIP: # Privates not necessary continue package_ref = PackageReference(conan_ref, package_id) @@ -323,7 +315,7 @@ def _load_editables_cpp_info(self): return EditableCppInfo.load(editables_path, require_namespace=True) return None - def _handle_node_editable(self, node): + def _handle_node_editable(self, node, graph_info): # Get source of information package_layout = self._client_cache.package_layout(node.conan_ref) base_path = package_layout.conan() @@ -348,9 +340,22 @@ def _handle_node_editable(self, node): settings=node.conanfile.settings, options=node.conanfile.options) - # Use `package_info()` data - else: - pass # It will use `package_info()` data relative to path used as 'package_folder' + workspace_package = self._workspace[node.conan_ref] if self._workspace else None + if workspace_package: + output = node.conanfile.output + build_folder = workspace_package.build_folder(node.conanfile) + write_generators(node.conanfile, build_folder, output) + save(os.path.join(build_folder, CONANINFO), node.conanfile.info.dumps()) + output.info("Generated %s" % CONANINFO) + graph_info.save(build_folder) + output.info("Generated graphinfo") + save(os.path.join(build_folder, BUILD_INFO), TXTGenerator(node.conanfile).content) + output.info("Generated %s" % BUILD_INFO) + # Build step might need DLLs, binaries as protoc to generate source files + # So execute imports() before build, storing the list of copied_files + from conans.client.importer import run_imports + copied_files = run_imports(node.conanfile, build_folder) + report_copied_files(copied_files, output) def _handle_node_cache(self, node, package_ref, keep_build, processed_package_references): conan_file = node.conanfile @@ -382,39 +387,6 @@ def _handle_node_cache(self, node, package_ref, keep_build, processed_package_re self._call_package_info(conan_file, package_folder) self._recorder.package_cpp_info(package_ref, conan_file.cpp_info) - def _handle_node_workspace(self, node, workspace_package, inverse_levels, deps_graph, - graph_info): - conan_file = node.conanfile - output = ScopedOutput("Workspace %s" % conan_file.display_name, self._out) - include_dirs = workspace_package.includedirs - lib_dirs = workspace_package.libdirs - self._call_package_info(conan_file, workspace_package.package_folder) - if include_dirs: - conan_file.cpp_info.includedirs = include_dirs - if lib_dirs: - conan_file.cpp_info.libdirs = lib_dirs - # Make sure the folders exists, otherwise they will be filtered out - lib_paths = [os.path.join(conan_file.cpp_info.rootpath, p) - if not os.path.isabs(p) else p for p in lib_dirs] - for p in lib_paths: - mkdir(p) - - self._propagate_info(node, inverse_levels, deps_graph) - - build_folder = workspace_package.build_folder - write_generators(conan_file, build_folder, output) - save(os.path.join(build_folder, CONANINFO), conan_file.info.dumps()) - output.info("Generated %s" % CONANINFO) - graph_info.save(build_folder) - output.info("Generated graphinfo") - save(os.path.join(build_folder, BUILD_INFO), TXTGenerator(conan_file).content) - output.info("Generated %s" % BUILD_INFO) - # Build step might need DLLs, binaries as protoc to generate source files - # So execute imports() before build, storing the list of copied_files - from conans.client.importer import run_imports - copied_files = run_imports(conan_file, build_folder) - report_copied_files(copied_files, output) - def _build_package(self, node, package_ref, output, keep_build): conan_ref, conan_file = node.conan_ref, node.conanfile diff --git a/conans/client/manager.py b/conans/client/manager.py index 108efab85ad..973de2788c6 100644 --- a/conans/client/manager.py +++ b/conans/client/manager.py @@ -30,10 +30,9 @@ def __init__(self, client_cache, user_io, remote_manager, self._hook_manager = hook_manager def install_workspace(self, graph_info, workspace, remote_name, build_modes, update): - references = [ConanFileReference(v, "root", "project", "develop") for v in workspace.root] + references = workspace.root deps_graph, _ = self._graph_manager.load_graph(references, None, graph_info, build_modes, - False, update, remote_name, self._recorder, - workspace) + False, update, remote_name, self._recorder) output = ScopedOutput(str("Workspace"), self._user_io.out) output.highlight("Installing...") diff --git a/conans/model/workspace.py b/conans/model/workspace.py index 26f373d357a..9ff0f6da501 100644 --- a/conans/model/workspace.py +++ b/conans/model/workspace.py @@ -14,7 +14,6 @@ def __init__(self, base_folder, install_folder, data): self._base_folder = base_folder self._install_folder = install_folder self._conanfile_folder = data.get("folder") # The folder with the conanfile - self._source_folder = data.get("source") # By default the conanfile_folder self._build_folder = data.get("build", "") # package_folder can be None, then it will directly use build_folder self._package_folder = data.get("package", "") @@ -23,7 +22,6 @@ def __init__(self, base_folder, install_folder, data): self._includedirs = [includedirs] if not isinstance(includedirs, list) else includedirs libdirs = data.get("libdirs", []) # To override libdirs... self._libdirs = [libdirs] if not isinstance(libdirs, list) else libdirs - self.conanfile = None @property def root_folder(self): @@ -33,9 +31,8 @@ def root_folder(self): def conanfile_path(self): return os.path.join(self.root_folder, "conanfile.py") - @property - def build_folder(self): - folder = self._evaluate(self._build_folder) + def build_folder(self, conanfile): + folder = self._evaluate(self._build_folder, conanfile) if self._install_folder: pkg_folder = os.path.join(self._install_folder, self._conanfile_folder, folder) else: @@ -57,17 +54,8 @@ def package_folder(self): def install_folder(self): return self._evaluate(self._install_folder) - @property - def includedirs(self): - return [os.path.join(self._base_folder, self._conanfile_folder, v) - for v in self._includedirs] - - @property - def libdirs(self): - return [self._evaluate(v) for v in self._libdirs] - - def _evaluate(self, value): - settings = self.conanfile.settings + def _evaluate(self, value, conanfile): + settings = conanfile.settings v = value.format(build_type=settings.get_safe("build_type"), arch=settings.get_safe("arch"), os=platform.system()) @@ -88,19 +76,6 @@ def local_cmakedir(self): class Workspace(object): - @staticmethod - def get_workspace(folder, install_folder): - if isinstance(folder, ConanFileReference): - return None - if not os.path.exists(folder): - return None - path = os.path.join(folder, WORKSPACE_FILE) - if os.path.exists(path): - return Workspace(path, install_folder) - parent = os.path.dirname(folder) - if parent and parent != folder: - return Workspace.get_workspace(parent, install_folder) - return None def generate(self): if self._generator == "cmake": @@ -124,14 +99,19 @@ def __init__(self, path, install_folder): self._generator = None self._name = "ConanWorkspace" self._workspace_packages = OrderedDict() # {reference: LocalPackage} - if not path: - return self._base_folder = os.path.dirname(path) - content = load(path) + try: + content = load(path) + except IOError: + raise ConanException("Couldn't load workwspace file in %s" % path) self._loads(content) + def get_editable_dict(self): + return {ref: local_package.root_folder + for ref, local_package in self._workspace_packages.items()} + def __getitem__(self, reference): - return self._workspace_packages.get(reference.name) + return self._workspace_packages.get(reference) @property def root(self): @@ -142,11 +122,13 @@ def _loads(self, text): yml = yaml.load(text) self._generator = yml.pop("generator", None) self._name = yml.pop("name", None) - self._root = [s.strip() for s in yml.pop("root", "").split(",") if s.strip()] + self._root = [ConanFileReference.loads(s.strip()) + for s in yml.pop("root", "").split(",") if s.strip()] if not self._root: raise ConanException("Conan workspace needs at least 1 root conanfile") for package_name, data in yml.items(): workspace_package = LocalPackage(self._base_folder, self._install_folder, data) + package_name = ConanFileReference.loads(package_name) self._workspace_packages[package_name] = workspace_package for package_name in self._root: if package_name not in self._workspace_packages: diff --git a/conans/test/integration/workspace_test.py b/conans/test/integration/workspace_test.py index e5c1ea3cc3f..63afdec8885 100644 --- a/conans/test/integration/workspace_test.py +++ b/conans/test/integration/workspace_test.py @@ -11,6 +11,7 @@ from conans.model.workspace import WORKSPACE_FILE from conans.test.utils.tools import TestClient from conans.util.files import load +import textwrap conanfile = """from conans import ConanFile import os @@ -95,6 +96,63 @@ def package_info(self): class WorkspaceTest(unittest.TestCase): + def simple_test(self): + client = TestClient() + + def files(name, depend=None): + deps = ('"Hello%s/0.1@lasote/stable"' % depend) if depend else "None" + return {"conanfile.py": conanfile_build.format(deps=deps, name=name)} + + client.save(files("C"), path=os.path.join(client.current_folder, "C")) + client.save(files("B", "C"), path=os.path.join(client.current_folder, "B")) + client.save(files("A", "B"), path=os.path.join(client.current_folder, "A")) + + project = textwrap.dedent(""" + HelloB/0.1@lasote/stable: + folder: B + HelloC/0.1@lasote/stable: + folder: C + HelloA/0.1@lasote/stable: + folder: A + root: HelloA/0.1@lasote/stable + """) + client.save({WORKSPACE_FILE: project}) + client.run("workspace install conanws.yml") + self.assertIn("HelloA/0.1@lasote/stable from user - Editable", client.out) + self.assertIn("HelloB/0.1@lasote/stable from user - Editable", client.out) + self.assertIn("HelloC/0.1@lasote/stable from user - Editable", client.out) + for sub in ("A", "B", "C"): + for f in ("conanbuildinfo.cmake", "conaninfo.txt", "conanbuildinfo.txt"): + self.assertTrue(os.path.exists(os.path.join(client.current_folder, sub, f))) + + def simple_build_test(self): + client = TestClient() + + def files(name, depend=None): + deps = ('"Hello%s/0.1@lasote/stable"' % depend) if depend else "None" + return {"conanfile.py": conanfile_build.format(deps=deps, name=name)} + + client.save(files("C"), path=os.path.join(client.current_folder, "C")) + client.save(files("B", "C"), path=os.path.join(client.current_folder, "B")) + client.save(files("A", "B"), path=os.path.join(client.current_folder, "A")) + + project = textwrap.dedent(""" + HelloB/0.1@lasote/stable: + folder: B + HelloC/0.1@lasote/stable: + folder: C + HelloA/0.1@lasote/stable: + folder: A + root: HelloA/0.1@lasote/stable + """) + client.save({WORKSPACE_FILE: project}) + client.run("workspace install conanws.yml") + self.assertIn("HelloA/0.1@lasote/stable from user - Editable", client.out) + self.assertIn("HelloB/0.1@lasote/stable from user - Editable", client.out) + self.assertIn("HelloC/0.1@lasote/stable from user - Editable", client.out) + for sub in ("A", "B", "C"): + for f in ("conanbuildinfo.cmake", "conaninfo.txt", "conanbuildinfo.txt"): + self.assertTrue(os.path.exists(os.path.join(client.current_folder, sub, f))) def build_requires_test(self): # https://github.com/conan-io/conan/issues/3075 From ff88550b7407bae9baeabedf55c4beaf38e06158 Mon Sep 17 00:00:00 2001 From: memsharded Date: Fri, 11 Jan 2019 16:26:43 +0100 Subject: [PATCH 04/41] working --- conans/client/command.py | 3 ++- conans/client/conan_api.py | 4 ++-- conans/client/installer.py | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/conans/client/command.py b/conans/client/command.py index cd030118ceb..f4ab3faaf39 100644 --- a/conans/client/command.py +++ b/conans/client/command.py @@ -1390,7 +1390,8 @@ def _show_help(self): """ grps = [("Consumer commands", ("install", "config", "get", "info", "search")), ("Creator commands", ("new", "create", "upload", "export", "export-pkg", "test")), - ("Package development commands", ("source", "build", "package", "link")), + ("Package development commands", ("source", "build", "package", "link", + "workspace")), ("Misc commands", ("profile", "remote", "user", "imports", "copy", "remove", "alias", "download", "inspect", "help"))] diff --git a/conans/client/conan_api.py b/conans/client/conan_api.py index bdc2202d2d5..17c3e7b9105 100644 --- a/conans/client/conan_api.py +++ b/conans/client/conan_api.py @@ -455,10 +455,10 @@ def install_workspace(self, path, settings=None, options=None, env=None, workspace = Workspace(abs_path, None) graph_info = get_graph_info(profile_name, settings, options, env, cwd, None, - self._client_cache, self._user_io.out) + self._cache, self._user_io.out) self._user_io.out.success("Using workspace file from %s" % workspace._base_folder) - self._client_cache._workspace_refs.update(workspace.get_editable_dict()) + self._cache._workspace_refs.update(workspace.get_editable_dict()) recorder = ActionRecorder() manager = self._init_manager(recorder) manager.install_workspace(graph_info, workspace, remote_name, build, update) diff --git a/conans/client/installer.py b/conans/client/installer.py index 9df0529cbfb..73ef620f080 100644 --- a/conans/client/installer.py +++ b/conans/client/installer.py @@ -336,7 +336,7 @@ def _handle_node_editable(self, node, graph_info): settings=node.conanfile.settings, options=node.conanfile.options) - workspace_package = self._workspace[node.conan_ref] if self._workspace else None + workspace_package = self._workspace[node.ref] if self._workspace else None if workspace_package: output = node.conanfile.output build_folder = workspace_package.build_folder(node.conanfile) From f09cfdd7b0a5d3df863b2abc7f92e20dac2287ca Mon Sep 17 00:00:00 2001 From: memsharded Date: Mon, 4 Feb 2019 22:41:44 +0100 Subject: [PATCH 05/41] working --- conans/model/editable_cpp_info.py | 5 +- conans/model/workspace.py | 20 ++++-- conans/test/integration/workspace_test.py | 64 +++++++++++++------ .../model/editable_cpp_info/apply_test.py | 4 ++ 4 files changed, 67 insertions(+), 26 deletions(-) diff --git a/conans/model/editable_cpp_info.py b/conans/model/editable_cpp_info.py index 948ef621082..89d7bdf48b6 100644 --- a/conans/model/editable_cpp_info.py +++ b/conans/model/editable_cpp_info.py @@ -37,13 +37,16 @@ def __init__(self, data): @staticmethod def load(filepath): - parser = configparser.ConfigParser(allow_no_value=True) + parser = configparser.ConfigParser(allow_no_value=True,) parser.optionxform = str try: parser.read(filepath) except configparser.Error as e: raise ConanException("Error parsing layout file: %s\n%s" % (filepath, str(e))) data = OrderedDict() + if parser.has_section("folders"): + build_folder = parser.get("folders", "build") + parser.remove_section("folders") for section in parser.sections(): ref, cpp_info_dir = section.rsplit(":", 1) if ':' in section else (None, section) if cpp_info_dir not in EditableCppInfo.cpp_info_dirs: diff --git a/conans/model/workspace.py b/conans/model/workspace.py index b5499135f7f..bfbc99d8d3d 100644 --- a/conans/model/workspace.py +++ b/conans/model/workspace.py @@ -11,13 +11,18 @@ class LocalPackage(object): - def __init__(self, base_folder, install_folder, data, cache): + def __init__(self, base_folder, install_folder, data, cache, ws_layout): self._base_folder = base_folder self._install_folder = install_folder self._conanfile_folder = data.get("folder") # The folder with the conanfile self._build_folder = data.get("build", "") - self.layout = get_editable_abs_path(data.get("layout"), self._base_folder, - cache.conan_folder) + layout = data.get("layout") + if layout: + self.layout = get_editable_abs_path(data.get("layout"), self._base_folder, + cache.conan_folder) + else: + self.layout = ws_layout + # package_folder can be None, then it will directly use build_folder self._package_folder = data.get("package", "") self._cmakedir = data.get("cmakedir") @@ -64,7 +69,7 @@ def _evaluate(self, value, conanfile): os=platform.system()) try: result = eval('%s' % v) - except: + except Exception: result = v return result @@ -126,12 +131,17 @@ def _loads(self, text): yml = yaml.safe_load(text) self._generator = yml.pop("generator", None) self._name = yml.pop("name", None) + self._layout = yml.pop("layout", None) + if self._layout: + self._layout = get_editable_abs_path(self._layout, self._base_folder, + self._cache.conan_folder) self._root = [ConanFileReference.loads(s.strip()) for s in yml.pop("root", "").split(",") if s.strip()] if not self._root: raise ConanException("Conan workspace needs at least 1 root conanfile") for package_name, data in yml.items(): - workspace_package = LocalPackage(self._base_folder, self._install_folder, data, self._cache) + workspace_package = LocalPackage(self._base_folder, self._install_folder, data, + self._cache, self._layout) package_name = ConanFileReference.loads(package_name) self._workspace_packages[package_name] = workspace_package for package_name in self._root: diff --git a/conans/test/integration/workspace_test.py b/conans/test/integration/workspace_test.py index cb83566de80..337b2a7276a 100644 --- a/conans/test/integration/workspace_test.py +++ b/conans/test/integration/workspace_test.py @@ -2,9 +2,9 @@ import platform import re import shutil -import textwrap import time import unittest +from textwrap import dedent from parameterized.parameterized import parameterized @@ -107,15 +107,15 @@ def files(name, depend=None): client.save(files("B", "C"), path=os.path.join(client.current_folder, "B")) client.save(files("A", "B"), path=os.path.join(client.current_folder, "A")) - project = textwrap.dedent(""" - HelloB/0.1@lasote/stable: - folder: B - HelloC/0.1@lasote/stable: - folder: C - HelloA/0.1@lasote/stable: - folder: A - root: HelloA/0.1@lasote/stable - """) + project = dedent(""" + HelloB/0.1@lasote/stable: + folder: B + HelloC/0.1@lasote/stable: + folder: C + HelloA/0.1@lasote/stable: + folder: A + root: HelloA/0.1@lasote/stable + """) client.save({"conanws.yml": project}) client.run("workspace install conanws.yml") self.assertIn("HelloA/0.1@lasote/stable from user folder - Editable", client.out) @@ -146,21 +146,45 @@ def files(name, depend=None): a["src/main.cpp"] = main_cpp client.save(a, path=A) - project = textwrap.dedent(""" - HelloB/0.1@lasote/stable: - folder: B - HelloC/0.1@lasote/stable: - folder: C - HelloA/0.1@lasote/stable: - folder: A - root: HelloA/0.1@lasote/stable - """) - client.save({"conanws.yml": project}) + project = dedent(""" + HelloB/0.1@lasote/stable: + folder: B + HelloC/0.1@lasote/stable: + folder: C + HelloA/0.1@lasote/stable: + folder: A + layout: layout + root: HelloA/0.1@lasote/stable + """) + layout = dedent(""" + [includedirs] + src + + [libdirs] + build/{settings.build_type} + """) + client.save({"conanws.yml": project, + "layout": layout}) client.run("workspace install conanws.yml") self.assertIn("HelloA/0.1@lasote/stable from user folder - Editable", client.out) self.assertIn("HelloB/0.1@lasote/stable from user folder - Editable", client.out) self.assertIn("HelloC/0.1@lasote/stable from user folder - Editable", client.out) + release = "build/Release" + client.run("build C -bf=C/%s" % release) + client.run("build B -bf=B/%s" % release) + client.run("build A -bf=A/%s" % release) + if platform.system() == "Windows": + cmd_release = r".\A\build\Release\app" + cmd_debug = r".\A\build\Debug\app" + else: + cmd_release = "./A/build_release/app" + cmd_debug = "./A/build_debug/app" + client.runner(cmd_release, cwd=client.current_folder) + self.assertIn("Hello World C Release!", client.out) + self.assertIn("Hello World B Release!", client.out) + self.assertIn("Hello World A Release!", client.out) + def build_requires_test(self): # https://github.com/conan-io/conan/issues/3075 diff --git a/conans/test/unittests/model/editable_cpp_info/apply_test.py b/conans/test/unittests/model/editable_cpp_info/apply_test.py index 387fdc39d44..d0a5f1986c5 100644 --- a/conans/test/unittests/model/editable_cpp_info/apply_test.py +++ b/conans/test/unittests/model/editable_cpp_info/apply_test.py @@ -14,6 +14,10 @@ base_content = textwrap.dedent("""\ + [folders] + build: build_folder + src: source_folder + [{namespace}includedirs] {path_prefix}dirs/includedirs From 52c8b438fc1f94c367c6dba9297e7ee5c5515149 Mon Sep 17 00:00:00 2001 From: memsharded Date: Thu, 7 Feb 2019 00:44:21 +0100 Subject: [PATCH 06/41] ws tests --- conans/client/command.py | 2 +- conans/client/conan_api.py | 19 +- conans/client/graph/graph_manager.py | 5 +- conans/client/installer.py | 37 +- conans/client/manager.py | 18 +- conans/model/editable_cpp_info.py | 21 +- conans/model/workspace.py | 105 ++--- conans/test/integration/workspace_test.py | 444 ++++++++++++---------- 8 files changed, 328 insertions(+), 323 deletions(-) diff --git a/conans/client/command.py b/conans/client/command.py index 350745dd7ef..92d4fcf4eee 100644 --- a/conans/client/command.py +++ b/conans/client/command.py @@ -1408,7 +1408,7 @@ def workspace(self, *args): args = parser.parse_args(*args) if args.subcommand == "install": - self._conan.install_workspace(args.path, args.settings, args.options, args.env, + self._conan.workspace_install(args.path, args.settings, args.options, args.env, args.remote, args.build, args.profile, args.update) diff --git a/conans/client/conan_api.py b/conans/client/conan_api.py index 1034aa0d836..254133c9fff 100644 --- a/conans/client/conan_api.py +++ b/conans/client/conan_api.py @@ -57,6 +57,8 @@ from conans.util.log import configure_logger from conans.util.tracer import log_command, log_exception from conans.model.editable_cpp_info import get_editable_abs_path +from conans.client.graph.printer import print_graph +from conans.client.installer import BinaryInstaller default_manifest_folder = '.conan_manifests' @@ -450,7 +452,7 @@ def download(self, reference, remote_name=None, package=None, recipe=False): raise ConanException("Provide a valid full reference without wildcards.") @api_method - def install_workspace(self, path, settings=None, options=None, env=None, + def workspace_install(self, path, settings=None, options=None, env=None, remote_name=None, build=None, profile_name=None, update=False, cwd=None): cwd = cwd or get_cwd() @@ -459,15 +461,24 @@ def install_workspace(self, path, settings=None, options=None, env=None, else: abs_path = os.path.normpath(os.path.join(cwd, path)) - workspace = Workspace(abs_path, None, self._cache) + workspace = Workspace(abs_path, self._cache) graph_info = get_graph_info(profile_name, settings, options, env, cwd, None, self._cache, self._user_io.out) self._user_io.out.success("Using workspace file from %s" % workspace._base_folder) self._cache.editable_packages.update(workspace.get_editable_dict()) + recorder = ActionRecorder() - manager = self._init_manager(recorder) - manager.install_workspace(graph_info, workspace, remote_name, build, update) + references = workspace.root + deps_graph, _ = self._graph_manager.load_graph(references, None, graph_info, build, + False, update, remote_name, recorder) + + print_graph(deps_graph, self._user_io.out) + + installer = BinaryInstaller(self._cache, self._user_io.out, self._remote_manager, + recorder=recorder, hook_manager=self._hook_manager) + installer.install(deps_graph, keep_build=False, graph_info=graph_info) + workspace.generate(cwd) @api_method def install_reference(self, reference, settings=None, options=None, env=None, diff --git a/conans/client/graph/graph_manager.py b/conans/client/graph/graph_manager.py index 92b618fcda3..0a4b479e0af 100644 --- a/conans/client/graph/graph_manager.py +++ b/conans/client/graph/graph_manager.py @@ -5,7 +5,7 @@ from conans.client.generators.text import TXTGenerator from conans.client.graph.build_mode import BuildMode from conans.client.graph.graph import BINARY_BUILD, Node,\ - RECIPE_CONSUMER, RECIPE_VIRTUAL + RECIPE_CONSUMER, RECIPE_VIRTUAL, BINARY_EDITABLE from conans.client.graph.graph_binaries import GraphBinariesAnalyzer from conans.client.graph.graph_builder import DepsGraphBuilder from conans.client.loader import ProcessedProfile @@ -185,7 +185,8 @@ def _recurse_build_requires(self, graph, check_updates, update, build_mode, remo for node in list(graph.nodes): if node.recipe == RECIPE_VIRTUAL: continue - if (node.binary != BINARY_BUILD and node.recipe != RECIPE_CONSUMER): + if (node.binary not in (BINARY_BUILD, BINARY_EDITABLE) + and node.recipe != RECIPE_CONSUMER): continue package_build_requires = self._get_recipe_build_requires(node.conanfile) str_ref = str(node.ref) diff --git a/conans/client/installer.py b/conans/client/installer.py index 39825100c50..d160a229927 100644 --- a/conans/client/installer.py +++ b/conans/client/installer.py @@ -254,13 +254,12 @@ class BinaryInstaller(object): """ main responsible of retrieving binary packages or building them from source locally in case they are not found in remotes """ - def __init__(self, cache, output, remote_manager, recorder, workspace, hook_manager): + def __init__(self, cache, output, remote_manager, recorder, hook_manager): self._cache = cache self._out = output self._remote_manager = remote_manager self._registry = cache.registry self._recorder = recorder - self._workspace = workspace self._hook_manager = hook_manager def install(self, deps_graph, keep_build=False, graph_info=None): @@ -321,22 +320,24 @@ def _handle_node_editable(self, node, graph_info): settings=node.conanfile.settings, options=node.conanfile.options) - workspace_package = self._workspace[node.ref] if self._workspace else None - if workspace_package: - output = node.conanfile.output - build_folder = workspace_package.build_folder(node.conanfile) - write_generators(node.conanfile, build_folder, output) - save(os.path.join(build_folder, CONANINFO), node.conanfile.info.dumps()) - output.info("Generated %s" % CONANINFO) - graph_info.save(build_folder) - output.info("Generated graphinfo") - save(os.path.join(build_folder, BUILD_INFO), TXTGenerator(node.conanfile).content) - output.info("Generated %s" % BUILD_INFO) - # Build step might need DLLs, binaries as protoc to generate source files - # So execute imports() before build, storing the list of copied_files - from conans.client.importer import run_imports - copied_files = run_imports(node.conanfile, build_folder) - report_copied_files(copied_files, output) + build_folder = editable_cpp_info.folder("build", + settings=node.conanfile.settings, + options=node.conanfile.options) + if build_folder is not None: + build_folder = os.path.join(package_layout.conan(), build_folder) + output = node.conanfile.output + write_generators(node.conanfile, build_folder, output) + save(os.path.join(build_folder, CONANINFO), node.conanfile.info.dumps()) + output.info("Generated %s" % CONANINFO) + graph_info.save(build_folder) + output.info("Generated graphinfo") + save(os.path.join(build_folder, BUILD_INFO), TXTGenerator(node.conanfile).content) + output.info("Generated %s" % BUILD_INFO) + # Build step might need DLLs, binaries as protoc to generate source files + # So execute imports() before build, storing the list of copied_files + from conans.client.importer import run_imports + copied_files = run_imports(node.conanfile, build_folder) + report_copied_files(copied_files, output) def _handle_node_cache(self, node, pref, keep_build, processed_package_references): conan_file = node.conanfile diff --git a/conans/client/manager.py b/conans/client/manager.py index 8203131162e..c3719ec9a03 100644 --- a/conans/client/manager.py +++ b/conans/client/manager.py @@ -7,7 +7,6 @@ from conans.client.importer import run_deploy, run_imports from conans.client.installer import BinaryInstaller, call_system_requirements from conans.client.manifest_manager import ManifestManager -from conans.client.output import Color, ScopedOutput from conans.client.source import complete_recipe_sources from conans.client.tools import cross_building, get_cross_building_settings from conans.client.userio import UserIO @@ -29,21 +28,6 @@ def __init__(self, cache, user_io, remote_manager, self._graph_manager = graph_manager self._hook_manager = hook_manager - def install_workspace(self, graph_info, workspace, remote_name, build_modes, update): - references = workspace.root - deps_graph, _ = self._graph_manager.load_graph(references, None, graph_info, build_modes, - False, update, remote_name, self._recorder) - - output = ScopedOutput(str("Workspace"), self._user_io.out) - output.highlight("Installing...") - print_graph(deps_graph, self._user_io.out) - - installer = BinaryInstaller(self._cache, output, self._remote_manager, - recorder=self._recorder, workspace=workspace, - hook_manager=self._hook_manager) - installer.install(deps_graph, keep_build=False, graph_info=graph_info) - workspace.generate() - def install(self, ref_or_path, install_folder, graph_info, remote_name=None, build_modes=None, update=False, manifest_folder=None, manifest_verify=False, manifest_interactive=False, generators=None, no_imports=False, create_reference=None, @@ -90,7 +74,7 @@ def install(self, ref_or_path, install_folder, graph_info, remote_name=None, bui pass installer = BinaryInstaller(self._cache, self._user_io.out, self._remote_manager, - recorder=self._recorder, workspace=None, + recorder=self._recorder, hook_manager=self._hook_manager) installer.install(deps_graph, keep_build) diff --git a/conans/model/editable_cpp_info.py b/conans/model/editable_cpp_info.py index 89d7bdf48b6..a8be1e77aa5 100644 --- a/conans/model/editable_cpp_info.py +++ b/conans/model/editable_cpp_info.py @@ -32,8 +32,19 @@ def get_editable_abs_path(path, cwd, cache_folder): class EditableCppInfo(object): cpp_info_dirs = ['includedirs', 'libdirs', 'resdirs', 'bindirs', 'builddirs', 'srcdirs'] - def __init__(self, data): + def __init__(self, data, folders): self._data = data + self._folders = folders + + def folder(self, name, settings, options): + try: + path = self._folders[name] + except KeyError: + return None + try: + return self._work_on_item(path, settings, options) + except Exception as e: + raise ConanException("Error getting folder '%s' from layout: %s" % (str(name), str(e))) @staticmethod def load(filepath): @@ -44,8 +55,12 @@ def load(filepath): except configparser.Error as e: raise ConanException("Error parsing layout file: %s\n%s" % (filepath, str(e))) data = OrderedDict() + folders = {} if parser.has_section("folders"): - build_folder = parser.get("folders", "build") + folders_config = parser.options("folders") + if folders_config: + for f in folders_config: + folders[f] = parser.get("folders", f) parser.remove_section("folders") for section in parser.sections(): ref, cpp_info_dir = section.rsplit(":", 1) if ':' in section else (None, section) @@ -62,7 +77,7 @@ def load(filepath): % (ref, filepath)) data.setdefault(ref, {})[cpp_info_dir] = [k for k, _ in parser.items(section)] - return EditableCppInfo(data) + return EditableCppInfo(data, folders) @staticmethod def _work_on_item(value, settings, options): diff --git a/conans/model/workspace.py b/conans/model/workspace.py index bfbc99d8d3d..29ee1527eee 100644 --- a/conans/model/workspace.py +++ b/conans/model/workspace.py @@ -1,21 +1,19 @@ import os -import platform + from collections import OrderedDict import yaml from conans.errors import ConanException from conans.model.ref import ConanFileReference -from conans.util.files import load, mkdir, save +from conans.util.files import load, save from conans.model.editable_cpp_info import get_editable_abs_path class LocalPackage(object): - def __init__(self, base_folder, install_folder, data, cache, ws_layout): + def __init__(self, base_folder, data, cache, ws_layout): self._base_folder = base_folder - self._install_folder = install_folder self._conanfile_folder = data.get("folder") # The folder with the conanfile - self._build_folder = data.get("build", "") layout = data.get("layout") if layout: self.layout = get_editable_abs_path(data.get("layout"), self._base_folder, @@ -23,88 +21,41 @@ def __init__(self, base_folder, install_folder, data, cache, ws_layout): else: self.layout = ws_layout - # package_folder can be None, then it will directly use build_folder - self._package_folder = data.get("package", "") - self._cmakedir = data.get("cmakedir") - includedirs = data.get("includedirs", []) # To override includedirs, mainly for build_folder - self._includedirs = [includedirs] if not isinstance(includedirs, list) else includedirs - libdirs = data.get("libdirs", []) # To override libdirs... - self._libdirs = [libdirs] if not isinstance(libdirs, list) else libdirs - @property def root_folder(self): return os.path.abspath(os.path.join(self._base_folder, self._conanfile_folder)) - @property - def conanfile_path(self): - return os.path.join(self.root_folder, "conanfile.py") - - def build_folder(self, conanfile): - folder = self._evaluate(self._build_folder, conanfile) - if self._install_folder: - pkg_folder = os.path.join(self._install_folder, self._conanfile_folder, folder) - else: - pkg_folder = os.path.join(self.root_folder, folder) - mkdir(pkg_folder) - return pkg_folder - - @property - def package_folder(self): - folder = self._evaluate(self._package_folder) - if self._install_folder: - pkg_folder = os.path.join(self._install_folder, self._conanfile_folder, folder) - else: - pkg_folder = os.path.join(self.root_folder, folder) - mkdir(pkg_folder) - return pkg_folder - - @property - def install_folder(self): - return self._evaluate(self._install_folder) - - def _evaluate(self, value, conanfile): - settings = conanfile.settings - v = value.format(build_type=settings.get_safe("build_type"), - arch=settings.get_safe("arch"), - os=platform.system()) - try: - result = eval('%s' % v) - except Exception: - result = v - return result - - @property - def local_cmakedir(self): - if not self._cmakedir: - return self._conanfile_folder - return os.path.join(self._conanfile_folder, self._cmakedir).replace("\\", "/") - class Workspace(object): - def generate(self): + def generate(self, cwd): if self._generator == "cmake": - template = """# conanws -cmake_minimum_required(VERSION 3.3) -project({name} CXX) - -""" - cmake = template.format(name=self._name) - for _, workspace_package in self._workspace_packages.items(): - build_folder = workspace_package.build_folder - build_folder = build_folder.replace("\\", "/") - cmake += 'add_subdirectory(%s "%s")\n' % (workspace_package.local_cmakedir, - build_folder) - cmake_path = os.path.join(self._base_folder, "CMakeLists.txt") - if os.path.exists(cmake_path) and not load(cmake_path).startswith("# conanws"): - raise ConanException("Can't generate CMakeLists.txt, will overwrite existing one") + cmake = "" + for ref, ws_pkg in self._workspace_packages.items(): + base_folder = ws_pkg.root_folder + src, build = None, None + for root, _, files in os.walk(base_folder): + if not src and "CMakeLists.txt" in files: + src = root.replace("\\", "/") + if not build: + if "conanbuildinfo.cmake" in files or "conanbuildinfo_multi.cmake" in files: + build = root.replace("\\", "/") + if src and build: + break + if src: + cmake += 'set(PACKAGE_%s_SRC "%s")\n' % (ref.name, src) + if build: + cmake += 'set(PACKAGE_%s_BUILD "%s")\n' % (ref.name, build) + + if src and build: + cmake += ('add_subdirectory(${PACKAGE_%s_SRC} ${PACKAGE_%s_BUILD})\n' + % (ref.name, ref.name)) + cmake_path = os.path.join(cwd, "conanworkspace.cmake") save(cmake_path, cmake) - def __init__(self, path, install_folder, cache): + def __init__(self, path, cache): self._cache = cache - self._install_folder = install_folder self._generator = None - self._name = "ConanWorkspace" self._workspace_packages = OrderedDict() # {reference: LocalPackage} self._base_folder = os.path.dirname(path) try: @@ -130,7 +81,7 @@ def root(self): def _loads(self, text): yml = yaml.safe_load(text) self._generator = yml.pop("generator", None) - self._name = yml.pop("name", None) + yml.pop("name", None) self._layout = yml.pop("layout", None) if self._layout: self._layout = get_editable_abs_path(self._layout, self._base_folder, @@ -140,7 +91,7 @@ def _loads(self, text): if not self._root: raise ConanException("Conan workspace needs at least 1 root conanfile") for package_name, data in yml.items(): - workspace_package = LocalPackage(self._base_folder, self._install_folder, data, + workspace_package = LocalPackage(self._base_folder, data, self._cache, self._layout) package_name = ConanFileReference.loads(package_name) self._workspace_packages[package_name] = workspace_package diff --git a/conans/test/integration/workspace_test.py b/conans/test/integration/workspace_test.py index 337b2a7276a..f07e6cc88ca 100644 --- a/conans/test/integration/workspace_test.py +++ b/conans/test/integration/workspace_test.py @@ -1,37 +1,18 @@ import os import platform -import re -import shutil -import time import unittest from textwrap import dedent -from parameterized.parameterized import parameterized - from conans.client import tools from conans.test.utils.tools import TestClient from conans.util.files import load -conanfile = """from conans import ConanFile -import os -class Pkg(ConanFile): - requires = {deps} - generators = "cmake" - exports_sources = "*.h" - def build(self): - assert os.path.exists("conanbuildinfo.cmake") - def package(self): - self.copy("*.h", dst="include") - def package_id(self): - self.info.header_only() -""" - conanfile_build = """from conans import ConanFile, CMake class Pkg(ConanFile): settings = "os", "compiler", "arch", "build_type" requires = {deps} - generators = "cmake" + generators = "cmake", "cmake_multi" exports_sources = "src/*" def build(self): @@ -80,16 +61,25 @@ def package_info(self): project(Hello CXX) cmake_minimum_required(VERSION 2.8.12) include(${{CMAKE_CURRENT_BINARY_DIR}}/conanbuildinfo.cmake) -conan_basic_setup(NO_OUTPUT_DIRS) +conan_basic_setup() add_library(hello{name} hello.cpp) target_link_libraries(hello{name} ${{CONAN_LIBS}}) """ +cmake_multi = """set(CMAKE_CXX_COMPILER_WORKS 1) +project(Hello CXX) +cmake_minimum_required(VERSION 2.8.12) +include(${{CMAKE_CURRENT_BINARY_DIR}}/conanbuildinfo_multi.cmake) +conan_basic_setup() +add_library(hello{name} hello.cpp) +conan_target_link_libraries(hello{name}) +""" + cmake_targets = """set(CMAKE_CXX_COMPILER_WORKS 1) project(Hello CXX) cmake_minimum_required(VERSION 2.8.12) include(${{CMAKE_CURRENT_BINARY_DIR}}/conanbuildinfo.cmake) -conan_basic_setup(NO_OUTPUT_DIRS TARGETS) +conan_basic_setup(TARGETS) add_library(hello{name} hello.cpp) target_link_libraries(hello{name} {dep}) """ @@ -114,9 +104,15 @@ def files(name, depend=None): folder: C HelloA/0.1@lasote/stable: folder: A + layout: layout root: HelloA/0.1@lasote/stable """) - client.save({"conanws.yml": project}) + layout = dedent(""" + [folders] + build: + """) + client.save({"conanws.yml": project, + "layout": layout}) client.run("workspace install conanws.yml") self.assertIn("HelloA/0.1@lasote/stable from user folder - Editable", client.out) self.assertIn("HelloB/0.1@lasote/stable from user folder - Editable", client.out) @@ -157,176 +153,152 @@ def files(name, depend=None): root: HelloA/0.1@lasote/stable """) layout = dedent(""" + [folders] + build: build/{settings.build_type} + [includedirs] src [libdirs] - build/{settings.build_type} + build/{settings.build_type}/lib """) client.save({"conanws.yml": project, "layout": layout}) client.run("workspace install conanws.yml") + client.run("workspace install conanws.yml -s build_type=Debug") self.assertIn("HelloA/0.1@lasote/stable from user folder - Editable", client.out) self.assertIn("HelloB/0.1@lasote/stable from user folder - Editable", client.out) self.assertIn("HelloC/0.1@lasote/stable from user folder - Editable", client.out) - release = "build/Release" - client.run("build C -bf=C/%s" % release) - client.run("build B -bf=B/%s" % release) - client.run("build A -bf=A/%s" % release) - if platform.system() == "Windows": - cmd_release = r".\A\build\Release\app" - cmd_debug = r".\A\build\Debug\app" - else: - cmd_release = "./A/build_release/app" - cmd_debug = "./A/build_debug/app" + build_type = "Release" + client.run("build C -bf=C/build/%s" % build_type) + client.run("build B -bf=B/build/%s" % build_type) + client.run("build A -bf=A/build/%s" % build_type) + + cmd_release = os.path.normpath("./A/build/Release/bin/app") + cmd_debug = os.path.normpath("./A/build/Debug/bin/app") + client.runner(cmd_release, cwd=client.current_folder) self.assertIn("Hello World C Release!", client.out) self.assertIn("Hello World B Release!", client.out) self.assertIn("Hello World A Release!", client.out) + build_type = "Debug" + client.run("build C -bf=C/build/%s" % build_type) + client.run("build B -bf=B/build/%s" % build_type) + client.run("build A -bf=A/build/%s" % build_type) - def build_requires_test(self): - # https://github.com/conan-io/conan/issues/3075 - client = TestClient() - tool = """from conans import ConanFile -class Tool(ConanFile): - def package_info(self): - self.cpp_info.libs = ["MyToolLib"] -""" - client.save({"conanfile.py": tool}) - client.run("create . Tool/0.1@user/testing") - - conanfile = """from conans import ConanFile -import os -class Pkg(ConanFile): - requires = {deps} - build_requires = "Tool/0.1@user/testing" - generators = "cmake" -""" - - def files(name, depend=None): - deps = ('"Hello%s/0.1@lasote/stable"' % depend) if depend else "None" - return {"conanfile.py": conanfile.format(deps=deps, name=name)} - - client.save(files("C"), path=os.path.join(client.current_folder, "C")) - client.save(files("B", "C"), path=os.path.join(client.current_folder, "B")) - client.save(files("A", "B"), path=os.path.join(client.current_folder, "A")) - - project = """HelloB: - folder: B -HelloC: - folder: C -HelloA: - folder: A - -root: HelloA -""" - client.save({"conanws.yml": project}) - client.run("install . -if=build") - self.assertIn("HelloC/0.1@lasote/stable: Applying build-requirement: Tool/0.1@user/testing", - client.out) - self.assertIn("HelloB/0.1@lasote/stable: Applying build-requirement: Tool/0.1@user/testing", - client.out) - self.assertIn("HelloA/root@project/develop: Applying build-requirement: Tool/0.1@user/testing", - client.out) - for sub in ("A", "B", "C"): - conanbuildinfo = load(os.path.join(client.current_folder, "build", sub, "conanbuildinfo.cmake")) - self.assertIn("set(CONAN_LIBS_TOOL MyToolLib)", conanbuildinfo) + client.runner(cmd_debug, cwd=client.current_folder) + self.assertIn("Hello World C Debug!", client.out) + self.assertIn("Hello World B Debug!", client.out) + self.assertIn("Hello World A Debug!", client.out) - @parameterized.expand([(True, ), (False, )]) - # @unittest.skipUnless(platform.system() in ("Windows", "Linux"), "Test doesn't work on OSX") - def cmake_outsource_build_test(self, targets): + def complete_single_conf_build_test(self): client = TestClient() def files(name, depend=None): includes = ('#include "hello%s.h"' % depend) if depend else "" calls = ('hello%s();' % depend) if depend else "" deps = ('"Hello%s/0.1@lasote/stable"' % depend) if depend else "None" - dep = "CONAN_PKG::Hello%s" % depend if depend else "" - used_cmake = cmake_targets.format(dep=dep, name=name) if targets else cmake.format(name=name) return {"conanfile.py": conanfile_build.format(deps=deps, name=name), "src/hello%s.h" % name: hello_h.format(name=name), "src/hello.cpp": hello_cpp.format(name=name, includes=includes, calls=calls), - "src/CMakeLists.txt": used_cmake} + "src/CMakeLists.txt": cmake.format(name=name)} client.save(files("C"), path=os.path.join(client.current_folder, "C")) client.save(files("B", "C"), path=os.path.join(client.current_folder, "B")) + A = os.path.join(client.current_folder, "A") a = files("A", "B") - a["src/CMakeLists.txt"] += "add_executable(app main.cpp)\ntarget_link_libraries(app helloA)\n" + a["src/CMakeLists.txt"] += ("add_executable(app main.cpp)\n" + "target_link_libraries(app helloA)\n") a["src/main.cpp"] = main_cpp - client.save(a, path=os.path.join(client.current_folder, "A")) - - project = """HelloB: - folder: B - includedirs: src - cmakedir: src -HelloC: - folder: C - includedirs: src - cmakedir: src -HelloA: - folder: A - cmakedir: src - -root: HelloA -generator: cmake -name: MyProject -""" - client.save({"conanws.yml": project}) - client.run("install . -if=build") + client.save(a, path=A) + + project = dedent(""" + HelloB/0.1@lasote/stable: + folder: B + HelloC/0.1@lasote/stable: + folder: C + HelloA/0.1@lasote/stable: + folder: A + layout: layout + generator: cmake + root: HelloA/0.1@lasote/stable + """) + layout = dedent(""" + [folders] + build: build/{settings.build_type} + + [includedirs] + src + + [libdirs] + build/{settings.build_type}/lib + """) + metacmake = dedent(""" + cmake_minimum_required(VERSION 3.3) + project(MyProject CXX) + include(${CMAKE_BINARY_DIR}/conanworkspace.cmake) + """) + client.save({"conanws.yml": project, + "layout": layout, + "CMakeLists.txt": metacmake}) + + base_release = os.path.join(client.current_folder, "build_release") + base_debug = os.path.join(client.current_folder, "build_debug") + + with client.chdir("build_release"): + client.run("workspace install ../conanws.yml") + with client.chdir("build_debug"): + client.run("workspace install ../conanws.yml -s build_type=Debug") + generator = "Visual Studio 15 Win64" if platform.system() == "Windows" else "Unix Makefiles" - base_folder = os.path.join(client.current_folder, "build") - client.runner('cmake .. -G "%s" -DCMAKE_BUILD_TYPE=Release' % generator, cwd=base_folder) - client.runner('cmake --build . --config Release', cwd=base_folder) - if platform.system() == "Windows": - cmd_release = r".\build\A\Release\app" - cmd_debug = r".\build\A\Debug\app" - else: - cmd_release = "./build/A/app" - cmd_debug = "./build/A/app" + client.runner('cmake .. -G "%s" -DCMAKE_BUILD_TYPE=Release' % generator, cwd=base_release) + client.runner('cmake --build . --config Release', cwd=base_release) + + cmd_release = os.path.normpath("./A/build/Release/bin/app") + cmd_debug = os.path.normpath("./A/build/Debug/bin/app") client.runner(cmd_release, cwd=client.current_folder) self.assertIn("Hello World C Release!", client.out) self.assertIn("Hello World B Release!", client.out) self.assertIn("Hello World A Release!", client.out) - TIME_DELAY = 1 - time.sleep(TIME_DELAY) + tools.replace_in_file(os.path.join(client.current_folder, "C/src/hello.cpp"), "Hello World", "Bye Moon", output=client.out) + + client.runner('cmake --build . --config Release', cwd=base_release) + client.runner(cmd_release, cwd=client.current_folder) + self.assertIn("Bye Moon C Release!", client.out) + self.assertIn("Hello World B Release!", client.out) + self.assertIn("Hello World A Release!", client.out) + tools.replace_in_file(os.path.join(client.current_folder, "B/src/hello.cpp"), "Hello World", "Bye Moon", output=client.out) - time.sleep(TIME_DELAY) - client.runner('cmake --build . --config Release', cwd=base_folder) - time.sleep(TIME_DELAY) + + client.runner('cmake --build . --config Release', cwd=base_release) client.runner(cmd_release, cwd=client.current_folder) self.assertIn("Bye Moon C Release!", client.out) self.assertIn("Bye Moon B Release!", client.out) self.assertIn("Hello World A Release!", client.out) - time.sleep(TIME_DELAY) # Try to avoid windows errors in CI (The directory is not empty) - shutil.rmtree(os.path.join(client.current_folder, "build")) - client.run("install . -if=build -s build_type=Debug") - client.runner('cmake .. -G "%s" -DCMAKE_BUILD_TYPE=Debug' % generator, cwd=base_folder) - time.sleep(TIME_DELAY) - client.runner('cmake --build . --config Debug', cwd=base_folder) - time.sleep(TIME_DELAY) + client.runner('cmake .. -G "%s" -DCMAKE_BUILD_TYPE=Debug' % generator, cwd=base_debug) + client.runner('cmake --build . --config Debug', cwd=base_debug) client.runner(cmd_debug, cwd=client.current_folder) self.assertIn("Bye Moon C Debug!", client.out) self.assertIn("Bye Moon B Debug!", client.out) self.assertIn("Hello World A Debug!", client.out) - tools.replace_in_file(os.path.join(client.current_folder, "B/src/hello.cpp"), - "Bye Moon", "Bye! Mars", output=client.out) - time.sleep(TIME_DELAY) - client.runner('cmake --build . --config Debug', cwd=base_folder) - time.sleep(TIME_DELAY) + tools.replace_in_file(os.path.join(client.current_folder, "C/src/hello.cpp"), + "Bye Moon", "Hello World", output=client.out) + + client.runner('cmake --build . --config Debug', cwd=base_debug) client.runner(cmd_debug, cwd=client.current_folder) - self.assertIn("Bye Moon C Debug!", client.out) - self.assertIn("Bye! Mars B Debug!", client.out) + self.assertIn("Hello World C Debug!", client.out) + self.assertIn("Bye Moon B Debug!", client.out) self.assertIn("Hello World A Debug!", client.out) - def insource_build_test(self): + def complete_multi_conf_build_test(self): client = TestClient() def files(name, depend=None): @@ -336,81 +308,151 @@ def files(name, depend=None): return {"conanfile.py": conanfile_build.format(deps=deps, name=name), "src/hello%s.h" % name: hello_h.format(name=name), "src/hello.cpp": hello_cpp.format(name=name, includes=includes, calls=calls), - "src/CMakeLists.txt": cmake.format(name=name)} + "src/CMakeLists.txt": cmake_multi.format(name=name)} - C = os.path.join(client.current_folder, "C") - B = os.path.join(client.current_folder, "B") + client.save(files("C"), path=os.path.join(client.current_folder, "C")) + client.save(files("B", "C"), path=os.path.join(client.current_folder, "B")) A = os.path.join(client.current_folder, "A") - client.save(files("C"), path=C) - client.save(files("B", "C"), path=B) a = files("A", "B") - a["src/CMakeLists.txt"] += "add_executable(app main.cpp)\ntarget_link_libraries(app helloA)\n" + a["src/CMakeLists.txt"] += ("add_executable(app main.cpp)\n" + "target_link_libraries(app helloA)\n") a["src/main.cpp"] = main_cpp client.save(a, path=A) - project = """HelloB: - folder: B - includedirs: src - cmakedir: src - build: "'build' if '{os}'=='Windows' else 'build_{build_type}'.lower()" - libdirs: "'build/{build_type}' if '{os}'=='Windows' else 'build_{build_type}'.lower()" -HelloC: - folder: C - includedirs: src - cmakedir: src - build: "'build' if '{os}'=='Windows' else 'build_{build_type}'.lower()" - libdirs: "'build/{build_type}' if '{os}'=='Windows' else 'build_{build_type}'.lower()" -HelloA: - folder: A - cmakedir: src - build: "'build' if '{os}'=='Windows' else 'build_{build_type}'.lower()" - -root: HelloA -""" - client.save({"conanws.yml": project}) - - release = "build" if platform.system() == "Windows" else "build_release" - debug = "build" if platform.system() == "Windows" else "build_debug" - - base_folder = client.current_folder - client.run("install .") - - # Make sure nothing in local cache - client.run("search") - self.assertIn("There are no packages", client.out) - - # Check A - content = load(os.path.join(client.current_folder, "A/%s/conanbuildinfo.cmake" % release)) - include_dirs_hellob = re.search('set\(CONAN_INCLUDE_DIRS_HELLOB "(.*)"\)', content).group(1) - self.assertIn("void helloB();", load(os.path.join(include_dirs_hellob, "helloB.h"))) - include_dirs_helloc = re.search('set\(CONAN_INCLUDE_DIRS_HELLOC "(.*)"\)', content).group(1) - self.assertIn("void helloC();", load(os.path.join(include_dirs_helloc, "helloC.h"))) - - # Check B - content = load(os.path.join(base_folder, "B/%s/conanbuildinfo.cmake" % release)) - include_dirs_helloc2 = re.search('set\(CONAN_INCLUDE_DIRS_HELLOC "(.*)"\)', content).group(1) - self.assertEqual(include_dirs_helloc2, include_dirs_helloc) - - client.run("build C -bf=C/%s" % release) - client.run("build B -bf=B/%s" % release) - client.run("build A -bf=A/%s" % release) - if platform.system() == "Windows": - cmd_release = r".\A\build\Release\app" - cmd_debug = r".\A\build\Debug\app" - else: - cmd_release = "./A/build_release/app" - cmd_debug = "./A/build_debug/app" + project = dedent(""" + HelloB/0.1@lasote/stable: + folder: B + HelloC/0.1@lasote/stable: + folder: C + HelloA/0.1@lasote/stable: + folder: A + layout: layout + generator: cmake + root: HelloA/0.1@lasote/stable + """) + layout = dedent(""" + [folders] + build: build + + [includedirs] + src + + [libdirs] + build/{settings.build_type} + """) + metacmake = dedent(""" + cmake_minimum_required(VERSION 3.3) + project(MyProject CXX) + include(${CMAKE_BINARY_DIR}/conanworkspace.cmake) + """) + client.save({"conanws.yml": project, + "layout": layout, + "CMakeLists.txt": metacmake}) + + build = os.path.join(client.current_folder, "build") + + with client.chdir("build"): + client.run("workspace install ../conanws.yml") + client.run("workspace install ../conanws.yml -s build_type=Debug") + + generator = "Visual Studio 15 Win64" if platform.system() == "Windows" else "Unix Makefiles" + client.runner('cmake .. -G "%s" -DCMAKE_BUILD_TYPE=Release' % generator, cwd=build) + client.runner('cmake --build . --config Release', cwd=build) + + cmd_release = os.path.normpath("./A/build/Release/app") + cmd_debug = os.path.normpath("./A/build/Debug/app") + client.runner(cmd_release, cwd=client.current_folder) self.assertIn("Hello World C Release!", client.out) self.assertIn("Hello World B Release!", client.out) self.assertIn("Hello World A Release!", client.out) - # Now do the same for debug - client.run("install . -s build_type=Debug") - client.run("build C -bf=C/%s" % debug) - client.run("build B -bf=B/%s" % debug) - client.run("build A -bf=A/%s" % debug) + tools.replace_in_file(os.path.join(client.current_folder, "C/src/hello.cpp"), + "Hello World", "Bye Moon", output=client.out) + + client.runner('cmake --build . --config Release', cwd=build) + client.runner(cmd_release, cwd=client.current_folder) + self.assertIn("Bye Moon C Release!", client.out) + self.assertIn("Hello World B Release!", client.out) + self.assertIn("Hello World A Release!", client.out) + + tools.replace_in_file(os.path.join(client.current_folder, "B/src/hello.cpp"), + "Hello World", "Bye Moon", output=client.out) + + client.runner('cmake --build . --config Release', cwd=build) + client.runner(cmd_release, cwd=client.current_folder) + self.assertIn("Bye Moon C Release!", client.out) + self.assertIn("Bye Moon B Release!", client.out) + self.assertIn("Hello World A Release!", client.out) + + client.runner('cmake .. -G "%s" -DCMAKE_BUILD_TYPE=Debug' % generator, cwd=build) + client.runner('cmake --build . --config Debug', cwd=build) + client.runner(cmd_debug, cwd=client.current_folder) + self.assertIn("Bye Moon C Debug!", client.out) + self.assertIn("Bye Moon B Debug!", client.out) + self.assertIn("Hello World A Debug!", client.out) + + tools.replace_in_file(os.path.join(client.current_folder, "C/src/hello.cpp"), + "Bye Moon", "Hello World", output=client.out) + + client.runner('cmake --build . --config Debug', cwd=build) client.runner(cmd_debug, cwd=client.current_folder) self.assertIn("Hello World C Debug!", client.out) - self.assertIn("Hello World B Debug!", client.out) + self.assertIn("Bye Moon B Debug!", client.out) self.assertIn("Hello World A Debug!", client.out) + + def build_requires_test(self): + # https://github.com/conan-io/conan/issues/3075 + client = TestClient() + tool = """from conans import ConanFile +class Tool(ConanFile): + def package_info(self): + self.cpp_info.libs = ["MyToolLib"] +""" + client.save({"conanfile.py": tool}) + client.run("create . Tool/0.1@user/testing") + + conanfile = """from conans import ConanFile +import os +class Pkg(ConanFile): + requires = {deps} + build_requires = "Tool/0.1@user/testing" + generators = "cmake" +""" + + def files(name, depend=None): + deps = ('"Hello%s/0.1@lasote/stable"' % depend) if depend else "None" + return {"conanfile.py": conanfile.format(deps=deps, name=name)} + + client.save(files("C"), path=os.path.join(client.current_folder, "C")) + client.save(files("B", "C"), path=os.path.join(client.current_folder, "B")) + client.save(files("A", "B"), path=os.path.join(client.current_folder, "A")) + + project = dedent(""" + HelloB/0.1@lasote/stable: + folder: B + HelloC/0.1@lasote/stable: + folder: C + HelloA/0.1@lasote/stable: + folder: A + layout: layout + root: HelloA/0.1@lasote/stable + """) + layout = dedent(""" + [folders] + build: build + """) + client.save({"conanws.yml": project, + "layout": layout}) + + client.run("workspace install conanws.yml") + self.assertIn("HelloC/0.1@lasote/stable: Applying build-requirement: Tool/0.1@user/testing", + client.out) + self.assertIn("HelloB/0.1@lasote/stable: Applying build-requirement: Tool/0.1@user/testing", + client.out) + self.assertIn("HelloA/0.1@lasote/stable: Applying build-requirement: Tool/0.1@user/testing", + client.out) + for sub in ("A", "B", "C"): + conanbuildinfo = load(os.path.join(client.current_folder, sub, "build", + "conanbuildinfo.cmake")) + self.assertIn("set(CONAN_LIBS_TOOL MyToolLib)", conanbuildinfo) From e0da0c432d87159827b998b606b6866cfcf61f74 Mon Sep 17 00:00:00 2001 From: memsharded Date: Thu, 7 Feb 2019 00:48:23 +0100 Subject: [PATCH 07/41] missing import --- conans/client/manager.py | 1 + 1 file changed, 1 insertion(+) diff --git a/conans/client/manager.py b/conans/client/manager.py index c3719ec9a03..b704d9ec243 100644 --- a/conans/client/manager.py +++ b/conans/client/manager.py @@ -7,6 +7,7 @@ from conans.client.importer import run_deploy, run_imports from conans.client.installer import BinaryInstaller, call_system_requirements from conans.client.manifest_manager import ManifestManager +from conans.client.output import Color from conans.client.source import complete_recipe_sources from conans.client.tools import cross_building, get_cross_building_settings from conans.client.userio import UserIO From e02045ea08b5f4760e05476217589704754ae11d Mon Sep 17 00:00:00 2001 From: memsharded Date: Thu, 7 Feb 2019 01:20:06 +0100 Subject: [PATCH 08/41] fixing tests --- conans/client/installer.py | 2 +- conans/model/editable_cpp_info.py | 16 +++++++--------- .../functional/editable/graph_related_test.py | 1 - conans/test/integration/workspace_test.py | 3 ++- .../model/editable_cpp_info/apply_test.py | 4 ---- 5 files changed, 10 insertions(+), 16 deletions(-) diff --git a/conans/client/installer.py b/conans/client/installer.py index d160a229927..a3c0531a1b6 100644 --- a/conans/client/installer.py +++ b/conans/client/installer.py @@ -320,7 +320,7 @@ def _handle_node_editable(self, node, graph_info): settings=node.conanfile.settings, options=node.conanfile.options) - build_folder = editable_cpp_info.folder("build", + build_folder = editable_cpp_info.folder(node.ref, "build", settings=node.conanfile.settings, options=node.conanfile.options) if build_folder is not None: diff --git a/conans/model/editable_cpp_info.py b/conans/model/editable_cpp_info.py index a8be1e77aa5..5bd33353394 100644 --- a/conans/model/editable_cpp_info.py +++ b/conans/model/editable_cpp_info.py @@ -36,9 +36,10 @@ def __init__(self, data, folders): self._data = data self._folders = folders - def folder(self, name, settings, options): + def folder(self, ref, name, settings, options): try: - path = self._folders[name] + path = self._folders.get(str(ref)) or self._folders.get(None) or {} + path = path[name] except KeyError: return None try: @@ -56,14 +57,11 @@ def load(filepath): raise ConanException("Error parsing layout file: %s\n%s" % (filepath, str(e))) data = OrderedDict() folders = {} - if parser.has_section("folders"): - folders_config = parser.options("folders") - if folders_config: - for f in folders_config: - folders[f] = parser.get("folders", f) - parser.remove_section("folders") for section in parser.sections(): ref, cpp_info_dir = section.rsplit(":", 1) if ':' in section else (None, section) + if cpp_info_dir == "folders": + folders[ref] = {k: v for k, v in parser.items(section)} + continue if cpp_info_dir not in EditableCppInfo.cpp_info_dirs: raise ConanException("Wrong cpp_info field '%s' in layout file: %s" % (cpp_info_dir, filepath)) @@ -71,7 +69,7 @@ def load(filepath): try: r = ConanFileReference.loads(ref) if r.revision: - raise ConanException + raise ConanException("Don't provide revision in Editable layouts") except ConanException: raise ConanException("Wrong package reference '%s' in layout file: %s" % (ref, filepath)) diff --git a/conans/test/functional/editable/graph_related_test.py b/conans/test/functional/editable/graph_related_test.py index 0a7c84ff1b8..8f7d07f030a 100644 --- a/conans/test/functional/editable/graph_related_test.py +++ b/conans/test/functional/editable/graph_related_test.py @@ -121,7 +121,6 @@ def test_middle_graph(self, update): child_remote = 'No remote' if update else 'Cache' self.assertIn(" child/version@lasote/channel from local cache - {}".format(child_remote), self.t.out) - self.assertIn(" lib/version@user/channel from user folder - Editable", self.t.out) self.assertIn(" parent/version@lasote/channel from 'default' - Downloaded", self.t.out) self.assertTrue(os.path.exists(self.t.cache.conan(ref_parent))) diff --git a/conans/test/integration/workspace_test.py b/conans/test/integration/workspace_test.py index f07e6cc88ca..e31702b200e 100644 --- a/conans/test/integration/workspace_test.py +++ b/conans/test/integration/workspace_test.py @@ -298,6 +298,7 @@ def files(name, depend=None): self.assertIn("Bye Moon B Debug!", client.out) self.assertIn("Hello World A Debug!", client.out) + @unittest.skipUnless(platform.system() == "Windows", "only windows") def complete_multi_conf_build_test(self): client = TestClient() @@ -355,7 +356,7 @@ def files(name, depend=None): client.run("workspace install ../conanws.yml") client.run("workspace install ../conanws.yml -s build_type=Debug") - generator = "Visual Studio 15 Win64" if platform.system() == "Windows" else "Unix Makefiles" + generator = "Visual Studio 15 Win64" client.runner('cmake .. -G "%s" -DCMAKE_BUILD_TYPE=Release' % generator, cwd=build) client.runner('cmake --build . --config Release', cwd=build) diff --git a/conans/test/unittests/model/editable_cpp_info/apply_test.py b/conans/test/unittests/model/editable_cpp_info/apply_test.py index d0a5f1986c5..387fdc39d44 100644 --- a/conans/test/unittests/model/editable_cpp_info/apply_test.py +++ b/conans/test/unittests/model/editable_cpp_info/apply_test.py @@ -14,10 +14,6 @@ base_content = textwrap.dedent("""\ - [folders] - build: build_folder - src: source_folder - [{namespace}includedirs] {path_prefix}dirs/includedirs From 369641be3a851754fd19115603d6017e5089b6f1 Mon Sep 17 00:00:00 2001 From: memsharded Date: Thu, 7 Feb 2019 10:09:06 +0100 Subject: [PATCH 09/41] add some sleeps to test --- conans/test/integration/workspace_test.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/conans/test/integration/workspace_test.py b/conans/test/integration/workspace_test.py index e31702b200e..e155cc96e04 100644 --- a/conans/test/integration/workspace_test.py +++ b/conans/test/integration/workspace_test.py @@ -6,6 +6,7 @@ from conans.client import tools from conans.test.utils.tools import TestClient from conans.util.files import load +import time conanfile_build = """from conans import ConanFile, CMake @@ -284,15 +285,18 @@ def files(name, depend=None): client.runner('cmake .. -G "%s" -DCMAKE_BUILD_TYPE=Debug' % generator, cwd=base_debug) client.runner('cmake --build . --config Debug', cwd=base_debug) + time.sleep(1) client.runner(cmd_debug, cwd=client.current_folder) self.assertIn("Bye Moon C Debug!", client.out) self.assertIn("Bye Moon B Debug!", client.out) self.assertIn("Hello World A Debug!", client.out) + time.sleep(1) tools.replace_in_file(os.path.join(client.current_folder, "C/src/hello.cpp"), "Bye Moon", "Hello World", output=client.out) client.runner('cmake --build . --config Debug', cwd=base_debug) + time.sleep(1) client.runner(cmd_debug, cwd=client.current_folder) self.assertIn("Hello World C Debug!", client.out) self.assertIn("Bye Moon B Debug!", client.out) From 4103b06d3f97a3f3a42205685e95f35e07054c8f Mon Sep 17 00:00:00 2001 From: memsharded Date: Thu, 7 Feb 2019 11:48:44 +0100 Subject: [PATCH 10/41] more sleeps --- conans/test/integration/workspace_test.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/conans/test/integration/workspace_test.py b/conans/test/integration/workspace_test.py index e155cc96e04..ccb3822af41 100644 --- a/conans/test/integration/workspace_test.py +++ b/conans/test/integration/workspace_test.py @@ -265,38 +265,47 @@ def files(name, depend=None): self.assertIn("Hello World B Release!", client.out) self.assertIn("Hello World A Release!", client.out) + time.sleep(2) tools.replace_in_file(os.path.join(client.current_folder, "C/src/hello.cpp"), "Hello World", "Bye Moon", output=client.out) + time.sleep(2) client.runner('cmake --build . --config Release', cwd=base_release) + time.sleep(2) client.runner(cmd_release, cwd=client.current_folder) self.assertIn("Bye Moon C Release!", client.out) self.assertIn("Hello World B Release!", client.out) self.assertIn("Hello World A Release!", client.out) + time.sleep(2) tools.replace_in_file(os.path.join(client.current_folder, "B/src/hello.cpp"), "Hello World", "Bye Moon", output=client.out) + time.sleep(2) client.runner('cmake --build . --config Release', cwd=base_release) + time.sleep(2) client.runner(cmd_release, cwd=client.current_folder) self.assertIn("Bye Moon C Release!", client.out) self.assertIn("Bye Moon B Release!", client.out) self.assertIn("Hello World A Release!", client.out) + time.sleep(2) client.runner('cmake .. -G "%s" -DCMAKE_BUILD_TYPE=Debug' % generator, cwd=base_debug) + time.sleep(2) client.runner('cmake --build . --config Debug', cwd=base_debug) - time.sleep(1) + time.sleep(2) client.runner(cmd_debug, cwd=client.current_folder) self.assertIn("Bye Moon C Debug!", client.out) self.assertIn("Bye Moon B Debug!", client.out) self.assertIn("Hello World A Debug!", client.out) - time.sleep(1) + time.sleep(2) tools.replace_in_file(os.path.join(client.current_folder, "C/src/hello.cpp"), "Bye Moon", "Hello World", output=client.out) + time.sleep(2) client.runner('cmake --build . --config Debug', cwd=base_debug) - time.sleep(1) + time.sleep(2) client.runner(cmd_debug, cwd=client.current_folder) self.assertIn("Hello World C Debug!", client.out) self.assertIn("Bye Moon B Debug!", client.out) From 57b134e129b481144fe065a8c9d29d74f4dec1a7 Mon Sep 17 00:00:00 2001 From: memsharded Date: Fri, 8 Feb 2019 00:18:51 +0100 Subject: [PATCH 11/41] trying new approach for src, build folder in meta-generator --- conans/client/conan_api.py | 2 +- conans/model/workspace.py | 22 +++++++------- .../package_layouts/package_cache_layout.py | 30 +++++++++---------- .../package_editable_layout.py | 2 +- conans/test/integration/workspace_test.py | 15 ++-------- 5 files changed, 30 insertions(+), 41 deletions(-) diff --git a/conans/client/conan_api.py b/conans/client/conan_api.py index 254133c9fff..501000d3c1b 100644 --- a/conans/client/conan_api.py +++ b/conans/client/conan_api.py @@ -478,7 +478,7 @@ def workspace_install(self, path, settings=None, options=None, env=None, installer = BinaryInstaller(self._cache, self._user_io.out, self._remote_manager, recorder=recorder, hook_manager=self._hook_manager) installer.install(deps_graph, keep_build=False, graph_info=graph_info) - workspace.generate(cwd) + workspace.generate(cwd, deps_graph) @api_method def install_reference(self, reference, settings=None, options=None, env=None, diff --git a/conans/model/workspace.py b/conans/model/workspace.py index 29ee1527eee..64e7b9038ce 100644 --- a/conans/model/workspace.py +++ b/conans/model/workspace.py @@ -8,6 +8,7 @@ from conans.model.ref import ConanFileReference from conans.util.files import load, save from conans.model.editable_cpp_info import get_editable_abs_path +from conans.client.graph.graph import RECIPE_EDITABLE class LocalPackage(object): @@ -28,23 +29,22 @@ def root_folder(self): class Workspace(object): - def generate(self, cwd): + def generate(self, cwd, graph): + editables = {node.ref: node.conanfile for node in graph.nodes + if node.recipe == RECIPE_EDITABLE} if self._generator == "cmake": cmake = "" for ref, ws_pkg in self._workspace_packages.items(): - base_folder = ws_pkg.root_folder - src, build = None, None - for root, _, files in os.walk(base_folder): - if not src and "CMakeLists.txt" in files: - src = root.replace("\\", "/") - if not build: - if "conanbuildinfo.cmake" in files or "conanbuildinfo_multi.cmake" in files: - build = root.replace("\\", "/") - if src and build: - break + layout = self._cache.package_layout(ref) + editable = layout.editable_cpp_info() + conanfile = editables[ref] + build = editable.folder(ref, "build", conanfile.settings, conanfile.options) + src = editable.folder(ref, "src", conanfile.settings, conanfile.options) if src: + src = os.path.join(ws_pkg.root_folder, src).replace("\\", "/") cmake += 'set(PACKAGE_%s_SRC "%s")\n' % (ref.name, src) if build: + build = os.path.join(ws_pkg.root_folder, build).replace("\\", "/") cmake += 'set(PACKAGE_%s_BUILD "%s")\n' % (ref.name, build) if src and build: diff --git a/conans/paths/package_layouts/package_cache_layout.py b/conans/paths/package_layouts/package_cache_layout.py index 3ba1a36be9b..8fdd63fc1de 100644 --- a/conans/paths/package_layouts/package_cache_layout.py +++ b/conans/paths/package_layouts/package_cache_layout.py @@ -39,51 +39,51 @@ def conan(self): return self._base_folder def export(self): - return os.path.join(self.conan(), EXPORT_FOLDER) + return os.path.join(self._base_folder, EXPORT_FOLDER) + + def conanfile(self): + export = self.export() + return os.path.join(export, CONANFILE) @short_path def export_sources(self): - return os.path.join(self.conan(), EXPORT_SRC_FOLDER) + return os.path.join(self._base_folder, EXPORT_SRC_FOLDER) @short_path def source(self): - return os.path.join(self.conan(), SRC_FOLDER) - - def conanfile(self): - export = self.export() - return os.path.join(export, CONANFILE) + return os.path.join(self._base_folder, SRC_FOLDER) def builds(self): - return os.path.join(self.conan(), BUILD_FOLDER) + return os.path.join(self._base_folder, BUILD_FOLDER) @short_path def build(self, pref): assert isinstance(pref, PackageReference) assert pref.ref == self._ref - return os.path.join(self.conan(), BUILD_FOLDER, pref.id) + return os.path.join(self._base_folder, BUILD_FOLDER, pref.id) def system_reqs(self): - return os.path.join(self.conan(), SYSTEM_REQS_FOLDER, SYSTEM_REQS) + return os.path.join(self._base_folder, SYSTEM_REQS_FOLDER, SYSTEM_REQS) def system_reqs_package(self, pref): assert isinstance(pref, PackageReference) assert pref.ref == self._ref - return os.path.join(self.conan(), SYSTEM_REQS_FOLDER, pref.id, SYSTEM_REQS) + return os.path.join(self._base_folder, SYSTEM_REQS_FOLDER, pref.id, SYSTEM_REQS) def packages(self): - return os.path.join(self.conan(), PACKAGES_FOLDER) + return os.path.join(self._base_folder, PACKAGES_FOLDER) @short_path def package(self, pref): assert isinstance(pref, PackageReference) assert pref.ref == self._ref - return os.path.join(self.conan(), PACKAGES_FOLDER, pref.id) + return os.path.join(self._base_folder, PACKAGES_FOLDER, pref.id) def scm_folder(self): - return os.path.join(self.conan(), SCM_FOLDER) + return os.path.join(self._base_folder, SCM_FOLDER) def package_metadata(self): - return os.path.join(self.conan(), PACKAGE_METADATA) + return os.path.join(self._base_folder, PACKAGE_METADATA) def load_manifest(self): return FileTreeManifest.load(self.export()) diff --git a/conans/paths/package_layouts/package_editable_layout.py b/conans/paths/package_layouts/package_editable_layout.py index 066043e6c3c..a81a063082f 100644 --- a/conans/paths/package_layouts/package_editable_layout.py +++ b/conans/paths/package_layouts/package_editable_layout.py @@ -25,7 +25,7 @@ def conanfile(self): """ Path to the conanfile. We can agree that an editable package needs to be a Conan package """ - return os.path.join(self.conan(), CONANFILE) + return os.path.join(self._base_folder, CONANFILE) def editable_cpp_info(self): if self._layout_file: diff --git a/conans/test/integration/workspace_test.py b/conans/test/integration/workspace_test.py index ccb3822af41..8df63c411c4 100644 --- a/conans/test/integration/workspace_test.py +++ b/conans/test/integration/workspace_test.py @@ -6,7 +6,6 @@ from conans.client import tools from conans.test.utils.tools import TestClient from conans.util.files import load -import time conanfile_build = """from conans import ConanFile, CMake @@ -229,6 +228,7 @@ def files(name, depend=None): layout = dedent(""" [folders] build: build/{settings.build_type} + src: src [includedirs] src @@ -265,47 +265,35 @@ def files(name, depend=None): self.assertIn("Hello World B Release!", client.out) self.assertIn("Hello World A Release!", client.out) - time.sleep(2) tools.replace_in_file(os.path.join(client.current_folder, "C/src/hello.cpp"), "Hello World", "Bye Moon", output=client.out) - time.sleep(2) client.runner('cmake --build . --config Release', cwd=base_release) - time.sleep(2) client.runner(cmd_release, cwd=client.current_folder) self.assertIn("Bye Moon C Release!", client.out) self.assertIn("Hello World B Release!", client.out) self.assertIn("Hello World A Release!", client.out) - time.sleep(2) tools.replace_in_file(os.path.join(client.current_folder, "B/src/hello.cpp"), "Hello World", "Bye Moon", output=client.out) - time.sleep(2) client.runner('cmake --build . --config Release', cwd=base_release) - time.sleep(2) client.runner(cmd_release, cwd=client.current_folder) self.assertIn("Bye Moon C Release!", client.out) self.assertIn("Bye Moon B Release!", client.out) self.assertIn("Hello World A Release!", client.out) - time.sleep(2) client.runner('cmake .. -G "%s" -DCMAKE_BUILD_TYPE=Debug' % generator, cwd=base_debug) - time.sleep(2) client.runner('cmake --build . --config Debug', cwd=base_debug) - time.sleep(2) client.runner(cmd_debug, cwd=client.current_folder) self.assertIn("Bye Moon C Debug!", client.out) self.assertIn("Bye Moon B Debug!", client.out) self.assertIn("Hello World A Debug!", client.out) - time.sleep(2) tools.replace_in_file(os.path.join(client.current_folder, "C/src/hello.cpp"), "Bye Moon", "Hello World", output=client.out) - time.sleep(2) client.runner('cmake --build . --config Debug', cwd=base_debug) - time.sleep(2) client.runner(cmd_debug, cwd=client.current_folder) self.assertIn("Hello World C Debug!", client.out) self.assertIn("Bye Moon B Debug!", client.out) @@ -347,6 +335,7 @@ def files(name, depend=None): layout = dedent(""" [folders] build: build + src: src [includedirs] src From 51753a6961e839da1e1350d4355dbc5810cc1953 Mon Sep 17 00:00:00 2001 From: memsharded Date: Fri, 8 Feb 2019 00:48:46 +0100 Subject: [PATCH 12/41] time.sleep again --- conans/test/integration/workspace_test.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/conans/test/integration/workspace_test.py b/conans/test/integration/workspace_test.py index 8df63c411c4..7feaa1642ec 100644 --- a/conans/test/integration/workspace_test.py +++ b/conans/test/integration/workspace_test.py @@ -6,6 +6,7 @@ from conans.client import tools from conans.test.utils.tools import TestClient from conans.util.files import load +import time conanfile_build = """from conans import ConanFile, CMake @@ -290,9 +291,11 @@ def files(name, depend=None): self.assertIn("Bye Moon B Debug!", client.out) self.assertIn("Hello World A Debug!", client.out) + time.sleep(1) tools.replace_in_file(os.path.join(client.current_folder, "C/src/hello.cpp"), "Bye Moon", "Hello World", output=client.out) + time.sleep(1) client.runner('cmake --build . --config Debug', cwd=base_debug) client.runner(cmd_debug, cwd=client.current_folder) self.assertIn("Hello World C Debug!", client.out) From 65dc944a70d78f3c3697ff69e2adcfbb248215e6 Mon Sep 17 00:00:00 2001 From: memsharded Date: Fri, 8 Feb 2019 01:12:58 +0100 Subject: [PATCH 13/41] another sleep --- conans/test/integration/workspace_test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/conans/test/integration/workspace_test.py b/conans/test/integration/workspace_test.py index 7feaa1642ec..d8846749f38 100644 --- a/conans/test/integration/workspace_test.py +++ b/conans/test/integration/workspace_test.py @@ -275,9 +275,10 @@ def files(name, depend=None): self.assertIn("Hello World B Release!", client.out) self.assertIn("Hello World A Release!", client.out) + time.sleep(1) tools.replace_in_file(os.path.join(client.current_folder, "B/src/hello.cpp"), "Hello World", "Bye Moon", output=client.out) - + time.sleep(1) client.runner('cmake --build . --config Release', cwd=base_release) client.runner(cmd_release, cwd=client.current_folder) self.assertIn("Bye Moon C Release!", client.out) From 8657130f42b804bc4df52f3f3eda36049c3b4acd Mon Sep 17 00:00:00 2001 From: memsharded Date: Fri, 8 Feb 2019 09:40:51 +0100 Subject: [PATCH 14/41] working --- conans/test/integration/workspace_test.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/conans/test/integration/workspace_test.py b/conans/test/integration/workspace_test.py index d8846749f38..f91c466364e 100644 --- a/conans/test/integration/workspace_test.py +++ b/conans/test/integration/workspace_test.py @@ -256,7 +256,9 @@ def files(name, depend=None): generator = "Visual Studio 15 Win64" if platform.system() == "Windows" else "Unix Makefiles" client.runner('cmake .. -G "%s" -DCMAKE_BUILD_TYPE=Release' % generator, cwd=base_release) + self.assertNotIn("Debug", client.out) client.runner('cmake --build . --config Release', cwd=base_release) + self.assertNotIn("Debug", client.out) cmd_release = os.path.normpath("./A/build/Release/bin/app") cmd_debug = os.path.normpath("./A/build/Debug/bin/app") @@ -270,6 +272,7 @@ def files(name, depend=None): "Hello World", "Bye Moon", output=client.out) client.runner('cmake --build . --config Release', cwd=base_release) + self.assertNotIn("Debug", client.out) client.runner(cmd_release, cwd=client.current_folder) self.assertIn("Bye Moon C Release!", client.out) self.assertIn("Hello World B Release!", client.out) @@ -280,13 +283,23 @@ def files(name, depend=None): "Hello World", "Bye Moon", output=client.out) time.sleep(1) client.runner('cmake --build . --config Release', cwd=base_release) + self.assertNotIn("Debug", client.out) client.runner(cmd_release, cwd=client.current_folder) self.assertIn("Bye Moon C Release!", client.out) self.assertIn("Bye Moon B Release!", client.out) self.assertIn("Hello World A Release!", client.out) + client.runner("dir") + print "LS OUT ", client.out + client.runner("dir") + print "LS OUT ", client.out + client.runner("dir") + print "LS OUT ", client.out client.runner('cmake .. -G "%s" -DCMAKE_BUILD_TYPE=Debug' % generator, cwd=base_debug) + print client.out + self.assertNotIn("Release", client.out) client.runner('cmake --build . --config Debug', cwd=base_debug) + self.assertNotIn("Release", client.out) client.runner(cmd_debug, cwd=client.current_folder) self.assertIn("Bye Moon C Debug!", client.out) self.assertIn("Bye Moon B Debug!", client.out) @@ -298,6 +311,7 @@ def files(name, depend=None): time.sleep(1) client.runner('cmake --build . --config Debug', cwd=base_debug) + self.assertNotIn("Release", client.out) client.runner(cmd_debug, cwd=client.current_folder) self.assertIn("Hello World C Debug!", client.out) self.assertIn("Bye Moon B Debug!", client.out) @@ -364,7 +378,9 @@ def files(name, depend=None): generator = "Visual Studio 15 Win64" client.runner('cmake .. -G "%s" -DCMAKE_BUILD_TYPE=Release' % generator, cwd=build) + self.assertNotIn("Debug", client.out) client.runner('cmake --build . --config Release', cwd=build) + self.assertNotIn("Debug", client.out) cmd_release = os.path.normpath("./A/build/Release/app") cmd_debug = os.path.normpath("./A/build/Debug/app") @@ -378,6 +394,7 @@ def files(name, depend=None): "Hello World", "Bye Moon", output=client.out) client.runner('cmake --build . --config Release', cwd=build) + self.assertNotIn("Debug", client.out) client.runner(cmd_release, cwd=client.current_folder) self.assertIn("Bye Moon C Release!", client.out) self.assertIn("Hello World B Release!", client.out) @@ -387,13 +404,16 @@ def files(name, depend=None): "Hello World", "Bye Moon", output=client.out) client.runner('cmake --build . --config Release', cwd=build) + self.assertNotIn("Debug", client.out) client.runner(cmd_release, cwd=client.current_folder) self.assertIn("Bye Moon C Release!", client.out) self.assertIn("Bye Moon B Release!", client.out) self.assertIn("Hello World A Release!", client.out) client.runner('cmake .. -G "%s" -DCMAKE_BUILD_TYPE=Debug' % generator, cwd=build) + self.assertNotIn("Release", client.out) client.runner('cmake --build . --config Debug', cwd=build) + self.assertNotIn("Release", client.out) client.runner(cmd_debug, cwd=client.current_folder) self.assertIn("Bye Moon C Debug!", client.out) self.assertIn("Bye Moon B Debug!", client.out) @@ -403,6 +423,7 @@ def files(name, depend=None): "Bye Moon", "Hello World", output=client.out) client.runner('cmake --build . --config Debug', cwd=build) + self.assertNotIn("Release", client.out) client.runner(cmd_debug, cwd=client.current_folder) self.assertIn("Hello World C Debug!", client.out) self.assertIn("Bye Moon B Debug!", client.out) From 848266d2aadc985e2e4e161fceeb74c6e6081448 Mon Sep 17 00:00:00 2001 From: memsharded Date: Fri, 8 Feb 2019 10:27:15 +0100 Subject: [PATCH 15/41] checks --- conans/test/integration/workspace_test.py | 34 +++++++++-------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/conans/test/integration/workspace_test.py b/conans/test/integration/workspace_test.py index f91c466364e..f7577a9b5c4 100644 --- a/conans/test/integration/workspace_test.py +++ b/conans/test/integration/workspace_test.py @@ -256,9 +256,7 @@ def files(name, depend=None): generator = "Visual Studio 15 Win64" if platform.system() == "Windows" else "Unix Makefiles" client.runner('cmake .. -G "%s" -DCMAKE_BUILD_TYPE=Release' % generator, cwd=base_release) - self.assertNotIn("Debug", client.out) client.runner('cmake --build . --config Release', cwd=base_release) - self.assertNotIn("Debug", client.out) cmd_release = os.path.normpath("./A/build/Release/bin/app") cmd_debug = os.path.normpath("./A/build/Debug/bin/app") @@ -272,7 +270,7 @@ def files(name, depend=None): "Hello World", "Bye Moon", output=client.out) client.runner('cmake --build . --config Release', cwd=base_release) - self.assertNotIn("Debug", client.out) + client.runner(cmd_release, cwd=client.current_folder) self.assertIn("Bye Moon C Release!", client.out) self.assertIn("Hello World B Release!", client.out) @@ -283,23 +281,16 @@ def files(name, depend=None): "Hello World", "Bye Moon", output=client.out) time.sleep(1) client.runner('cmake --build . --config Release', cwd=base_release) - self.assertNotIn("Debug", client.out) client.runner(cmd_release, cwd=client.current_folder) self.assertIn("Bye Moon C Release!", client.out) self.assertIn("Bye Moon B Release!", client.out) self.assertIn("Hello World A Release!", client.out) - client.runner("dir") - print "LS OUT ", client.out - client.runner("dir") - print "LS OUT ", client.out - client.runner("dir") - print "LS OUT ", client.out + self.assertNotIn("Debug", client.out) + client.init_dynamic_vars() + client.runner('cmake .. -G "%s" -DCMAKE_BUILD_TYPE=Debug' % generator, cwd=base_debug) - print client.out - self.assertNotIn("Release", client.out) client.runner('cmake --build . --config Debug', cwd=base_debug) - self.assertNotIn("Release", client.out) client.runner(cmd_debug, cwd=client.current_folder) self.assertIn("Bye Moon C Debug!", client.out) self.assertIn("Bye Moon B Debug!", client.out) @@ -311,12 +302,13 @@ def files(name, depend=None): time.sleep(1) client.runner('cmake --build . --config Debug', cwd=base_debug) - self.assertNotIn("Release", client.out) client.runner(cmd_debug, cwd=client.current_folder) self.assertIn("Hello World C Debug!", client.out) self.assertIn("Bye Moon B Debug!", client.out) self.assertIn("Hello World A Debug!", client.out) + self.assertNotIn("Release", client.out) + @unittest.skipUnless(platform.system() == "Windows", "only windows") def complete_multi_conf_build_test(self): client = TestClient() @@ -378,9 +370,7 @@ def files(name, depend=None): generator = "Visual Studio 15 Win64" client.runner('cmake .. -G "%s" -DCMAKE_BUILD_TYPE=Release' % generator, cwd=build) - self.assertNotIn("Debug", client.out) client.runner('cmake --build . --config Release', cwd=build) - self.assertNotIn("Debug", client.out) cmd_release = os.path.normpath("./A/build/Release/app") cmd_debug = os.path.normpath("./A/build/Debug/app") @@ -394,7 +384,6 @@ def files(name, depend=None): "Hello World", "Bye Moon", output=client.out) client.runner('cmake --build . --config Release', cwd=build) - self.assertNotIn("Debug", client.out) client.runner(cmd_release, cwd=client.current_folder) self.assertIn("Bye Moon C Release!", client.out) self.assertIn("Hello World B Release!", client.out) @@ -404,16 +393,18 @@ def files(name, depend=None): "Hello World", "Bye Moon", output=client.out) client.runner('cmake --build . --config Release', cwd=build) - self.assertNotIn("Debug", client.out) client.runner(cmd_release, cwd=client.current_folder) self.assertIn("Bye Moon C Release!", client.out) self.assertIn("Bye Moon B Release!", client.out) self.assertIn("Hello World A Release!", client.out) + self.assertNotIn("Debug", client.out) + client.runner('cmake .. -G "%s" -DCMAKE_BUILD_TYPE=Debug' % generator, cwd=build) - self.assertNotIn("Release", client.out) + # CMake configure will find the Release libraries, as we are in cmake-multi mode + # Need to reset the output after that + client.init_dynamic_vars() # Reset output client.runner('cmake --build . --config Debug', cwd=build) - self.assertNotIn("Release", client.out) client.runner(cmd_debug, cwd=client.current_folder) self.assertIn("Bye Moon C Debug!", client.out) self.assertIn("Bye Moon B Debug!", client.out) @@ -423,12 +414,13 @@ def files(name, depend=None): "Bye Moon", "Hello World", output=client.out) client.runner('cmake --build . --config Debug', cwd=build) - self.assertNotIn("Release", client.out) client.runner(cmd_debug, cwd=client.current_folder) self.assertIn("Hello World C Debug!", client.out) self.assertIn("Bye Moon B Debug!", client.out) self.assertIn("Hello World A Debug!", client.out) + self.assertNotIn("Release", client.out) + def build_requires_test(self): # https://github.com/conan-io/conan/issues/3075 client = TestClient() From f82bb47c7f970ae1ad9fb59f8643f966abd2f91a Mon Sep 17 00:00:00 2001 From: memsharded Date: Mon, 11 Feb 2019 12:12:20 +0100 Subject: [PATCH 16/41] fixed dedents --- conans/client/command.py | 4 +- conans/client/conan_api.py | 3 +- conans/model/editable_cpp_info.py | 2 +- conans/test/integration/workspace_test.py | 150 +++++++++++----------- 4 files changed, 78 insertions(+), 81 deletions(-) diff --git a/conans/client/command.py b/conans/client/command.py index 0f0661fed30..20f355b8dc2 100644 --- a/conans/client/command.py +++ b/conans/client/command.py @@ -1389,14 +1389,12 @@ def alias(self, *args): self._conan.export_alias(args.reference, args.target) def workspace(self, *args): - """ handle workspaces - + """ command to manage workspaces """ parser = argparse.ArgumentParser(description=self.workspace.__doc__, prog="conan workspace") subparsers = parser.add_subparsers(dest='subcommand', help='sub-command help') - # create the parser for the "a" command install_parser = subparsers.add_parser('install', help='install this workspace') install_parser.add_argument('path', help='path to workspace file or folder') _add_common_install_arguments(install_parser, build_help=_help_build_policies) diff --git a/conans/client/conan_api.py b/conans/client/conan_api.py index 1452e8876de..32a78458f58 100644 --- a/conans/client/conan_api.py +++ b/conans/client/conan_api.py @@ -476,8 +476,7 @@ def workspace_install(self, path, settings=None, options=None, env=None, self._cache.editable_packages.update(workspace.get_editable_dict()) recorder = ActionRecorder() - references = workspace.root - deps_graph, _ = self._graph_manager.load_graph(references, None, graph_info, build, + deps_graph, _ = self._graph_manager.load_graph(workspace.root, None, graph_info, build, False, update, remote_name, recorder) print_graph(deps_graph, self._user_io.out) diff --git a/conans/model/editable_cpp_info.py b/conans/model/editable_cpp_info.py index 5bd33353394..4548d157049 100644 --- a/conans/model/editable_cpp_info.py +++ b/conans/model/editable_cpp_info.py @@ -49,7 +49,7 @@ def folder(self, ref, name, settings, options): @staticmethod def load(filepath): - parser = configparser.ConfigParser(allow_no_value=True,) + parser = configparser.ConfigParser(allow_no_value=True) parser.optionxform = str try: parser.read(filepath) diff --git a/conans/test/integration/workspace_test.py b/conans/test/integration/workspace_test.py index c2f36b8bf12..70c27fb89bb 100644 --- a/conans/test/integration/workspace_test.py +++ b/conans/test/integration/workspace_test.py @@ -101,19 +101,19 @@ def files(name, depend=None): client.save(files("A", "B"), path=os.path.join(client.current_folder, "A")) project = dedent(""" - HelloB/0.1@lasote/stable: - folder: B - HelloC/0.1@lasote/stable: - folder: C - HelloA/0.1@lasote/stable: - folder: A - layout: layout - root: HelloA/0.1@lasote/stable - """) + HelloB/0.1@lasote/stable: + folder: B + HelloC/0.1@lasote/stable: + folder: C + HelloA/0.1@lasote/stable: + folder: A + layout: layout + root: HelloA/0.1@lasote/stable + """) layout = dedent(""" - [folders] - build: - """) + [folders] + build: + """) client.save({"conanws.yml": project, "layout": layout}) client.run("workspace install conanws.yml") @@ -146,25 +146,25 @@ def files(name, depend=None): client.save(a, path=A) project = dedent(""" - HelloB/0.1@lasote/stable: - folder: B - HelloC/0.1@lasote/stable: - folder: C - HelloA/0.1@lasote/stable: - folder: A - layout: layout - root: HelloA/0.1@lasote/stable - """) + HelloB/0.1@lasote/stable: + folder: B + HelloC/0.1@lasote/stable: + folder: C + HelloA/0.1@lasote/stable: + folder: A + layout: layout + root: HelloA/0.1@lasote/stable + """) layout = dedent(""" - [folders] - build: build/{settings.build_type} + [folders] + build: build/{settings.build_type} - [includedirs] - src + [includedirs] + src - [libdirs] - build/{settings.build_type}/lib - """) + [libdirs] + build/{settings.build_type}/lib + """) client.save({"conanws.yml": project, "layout": layout}) client.run("workspace install conanws.yml") @@ -218,32 +218,32 @@ def files(name, depend=None): client.save(a, path=A) project = dedent(""" - HelloB/0.1@lasote/stable: - folder: B - HelloC/0.1@lasote/stable: - folder: C - HelloA/0.1@lasote/stable: - folder: A - layout: layout - generator: cmake - root: HelloA/0.1@lasote/stable - """) + HelloB/0.1@lasote/stable: + folder: B + HelloC/0.1@lasote/stable: + folder: C + HelloA/0.1@lasote/stable: + folder: A + layout: layout + generator: cmake + root: HelloA/0.1@lasote/stable + """) layout = dedent(""" - [folders] - build: build/{settings.build_type} - src: src + [folders] + build: build/{settings.build_type} + src: src - [includedirs] - src + [includedirs] + src - [libdirs] - build/{settings.build_type}/lib - """) + [libdirs] + build/{settings.build_type}/lib + """) metacmake = dedent(""" - cmake_minimum_required(VERSION 3.3) - project(MyProject CXX) - include(${CMAKE_BINARY_DIR}/conanworkspace.cmake) - """) + cmake_minimum_required(VERSION 3.3) + project(MyProject CXX) + include(${CMAKE_BINARY_DIR}/conanworkspace.cmake) + """) client.save({"conanws.yml": project, "layout": layout, "CMakeLists.txt": metacmake}) @@ -334,32 +334,32 @@ def files(name, depend=None): client.save(a, path=A) project = dedent(""" - HelloB/0.1@lasote/stable: - folder: B - HelloC/0.1@lasote/stable: - folder: C - HelloA/0.1@lasote/stable: - folder: A - layout: layout - generator: cmake - root: HelloA/0.1@lasote/stable - """) + HelloB/0.1@lasote/stable: + folder: B + HelloC/0.1@lasote/stable: + folder: C + HelloA/0.1@lasote/stable: + folder: A + layout: layout + generator: cmake + root: HelloA/0.1@lasote/stable + """) layout = dedent(""" - [folders] - build: build - src: src + [folders] + build: build + src: src - [includedirs] - src + [includedirs] + src - [libdirs] - build/{settings.build_type} - """) + [libdirs] + build/{settings.build_type} + """) metacmake = dedent(""" - cmake_minimum_required(VERSION 3.3) - project(MyProject CXX) - include(${CMAKE_BINARY_DIR}/conanworkspace.cmake) - """) + cmake_minimum_required(VERSION 3.3) + project(MyProject CXX) + include(${CMAKE_BINARY_DIR}/conanworkspace.cmake) + """) client.save({"conanws.yml": project, "layout": layout, "CMakeLists.txt": metacmake}) @@ -461,9 +461,9 @@ def files(name, depend=None): root: HelloA/0.1@lasote/stable """) layout = dedent(""" - [folders] - build: build - """) + [folders] + build: build + """) client.save({"conanws.yml": project, "layout": layout}) From f2133fe6d3de583213a80473f20797a24bb1db39 Mon Sep 17 00:00:00 2001 From: memsharded Date: Mon, 11 Feb 2019 14:18:08 +0100 Subject: [PATCH 17/41] review --- conans/client/conan_api.py | 5 +---- conans/client/installer.py | 2 +- conans/model/editable_cpp_info.py | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/conans/client/conan_api.py b/conans/client/conan_api.py index 7b49755bec6..80e01a4fe3d 100644 --- a/conans/client/conan_api.py +++ b/conans/client/conan_api.py @@ -465,10 +465,7 @@ def workspace_install(self, path, settings=None, options=None, env=None, remote_name=None, build=None, profile_name=None, update=False, cwd=None): cwd = cwd or get_cwd() - if os.path.isabs(path): - abs_path = path - else: - abs_path = os.path.normpath(os.path.join(cwd, path)) + abs_path = os.path.normpath(os.path.join(cwd, path)) workspace = Workspace(abs_path, self._cache) graph_info = get_graph_info(profile_name, settings, options, env, cwd, None, diff --git a/conans/client/installer.py b/conans/client/installer.py index caa82c957f1..e926cff0243 100644 --- a/conans/client/installer.py +++ b/conans/client/installer.py @@ -324,7 +324,7 @@ def _handle_node_editable(self, node, graph_info): settings=node.conanfile.settings, options=node.conanfile.options) if build_folder is not None: - build_folder = os.path.join(package_layout.conan(), build_folder) + build_folder = os.path.join(base_path, build_folder) output = node.conanfile.output write_generators(node.conanfile, build_folder, output) save(os.path.join(build_folder, CONANINFO), node.conanfile.info.dumps()) diff --git a/conans/model/editable_cpp_info.py b/conans/model/editable_cpp_info.py index 4548d157049..67629ef6dd8 100644 --- a/conans/model/editable_cpp_info.py +++ b/conans/model/editable_cpp_info.py @@ -67,7 +67,7 @@ def load(filepath): % (cpp_info_dir, filepath)) if ref: try: - r = ConanFileReference.loads(ref) + r = ConanFileReference.loads(ref, validate=True) if r.revision: raise ConanException("Don't provide revision in Editable layouts") except ConanException: From efe39dba4f3a34e6dd35f5468e2541c49e965e48 Mon Sep 17 00:00:00 2001 From: memsharded Date: Wed, 13 Feb 2019 18:43:11 +0100 Subject: [PATCH 18/41] review --- conans/client/cache/editable.py | 3 + conans/client/command.py | 55 ++++++++++--------- conans/client/conan_api.py | 11 +++- conans/client/installer.py | 2 +- conans/model/editable_cpp_info.py | 27 +++++---- conans/model/workspace.py | 4 +- .../package_editable_layout.py | 4 +- conans/search/search.py | 16 ++---- .../editable/commands/info_on_child_test.py | 4 +- .../functional/editable/commands/info_test.py | 4 +- .../editable/commands/inspect_test.py | 4 +- .../editable/consume_header_only_test.py | 4 +- .../consume_settings_and_options_test.py | 4 +- .../editable/forbidden_commands_test.py | 5 +- .../functional/editable/graph_related_test.py | 10 ++-- .../test/functional/editable/layouts_test.py | 16 +++--- .../functional/editable/link_create_test.py | 19 ++++++- .../functional/editable/link_remove_test.py | 6 +- .../editable/transitive_editable_test.py | 2 +- conans/test/integration/workspace_test.py | 28 +++++----- .../model/editable_cpp_info/apply_test.py | 8 +-- .../model/editable_cpp_info/parse_test.py | 10 ++-- .../editable_cpp_info/work_on_items_test.py | 12 ++-- 23 files changed, 143 insertions(+), 115 deletions(-) diff --git a/conans/client/cache/editable.py b/conans/client/cache/editable.py index a7264080af2..f7585e82c32 100644 --- a/conans/client/cache/editable.py +++ b/conans/client/cache/editable.py @@ -21,6 +21,9 @@ def __init__(self, cache_folder): else: self._edited_refs = {} # {ref: {"path": path, "layout": layout}} + def refs(self): + return self._edited_refs + def save(self): d = {str(ref): d for ref, d in self._edited_refs.items()} save(self._edited_file, json.dumps(d)) diff --git a/conans/client/command.py b/conans/client/command.py index 20f355b8dc2..e7ffadf8ebf 100644 --- a/conans/client/command.py +++ b/conans/client/command.py @@ -1406,50 +1406,53 @@ def workspace(self, *args): args.remote, args.build, args.profile, args.update) - def link(self, *args): - """ Links a conan reference (e.g lib/1.0@conan/stable) with a local folder path. - + def editable(self, *args): + """ Manage editable packages """ - parser = argparse.ArgumentParser(description=self.link.__doc__, - prog="conan link") - parser.add_argument('target', help='Path to the package folder in the user workspace', - nargs='?',) - parser.add_argument('reference', help='Reference to link. e.g.: mylib/1.X@user/channel') - parser.add_argument("--remove", action='store_true', default=False, - help='Remove linked reference (target not required)') - parser.add_argument("-l", "--layout", - help='Relative or absolute path to a file containing the layout.' - ' Relative paths will be resolved first relative to current dir, ' - 'then to local cache "layouts" folder') + parser = argparse.ArgumentParser(description=self.editable.__doc__, + prog="conan editable") + subparsers = parser.add_subparsers(dest='subcommand', help='sub-command help') - args = parser.parse_args(*args) - self._warn_python2() + add_parser = subparsers.add_parser('add', help='Put a package in editable mode') + add_parser.add_argument('target', help='Path to the package folder in the user workspace') + add_parser.add_argument('reference', help='Package reference e.g.: mylib/1.X@user/channel') + add_parser.add_argument("-l", "--layout", + help='Relative or absolute path to a file containing the layout.' + ' Relative paths will be resolved first relative to current dir, ' + 'then to local cache "layouts" folder') - # Args sanity check - if args.remove and args.target: - raise ConanException("Do not provide the 'target' argument for removal") + remove_parser = subparsers.add_parser('remove', help='Disable editable mode for a package') + remove_parser.add_argument('reference', + help='Package reference e.g.: mylib/1.X@user/channel') - if not args.remove and not args.target: - raise ConanException("Argument 'target' is required to link a reference") + subparsers.add_parser('list', help='List packages in editable mode') - if not args.remove: - self._conan.link(args.target, args.reference, args.layout, cwd=os.getcwd()) + args = parser.parse_args(*args) + self._warn_python2() + + if args.subcommand == "add": + self._conan.editable_add(args.target, args.reference, args.layout, cwd=os.getcwd()) self._outputer.writeln("Reference '{}' linked to directory " "'{}'".format(args.reference, os.path.dirname(args.target))) - else: - ret = self._conan.unlink(args.reference) + elif args.subcommand == "remove": + ret = self._conan.editable_remove(args.reference) if ret: self._outputer.writeln("Removed linkage for reference '{}'".format(args.reference)) else: self._user_io.out.warn("Reference '{}' was not installed " "as editable".format(args.reference)) + elif args.subcommand == "list": + for k, v in self._conan.editable_list().items(): + self._user_io.out.info("%s" % k) + self._user_io.out.writeln(" Path: %s" % v["path"]) + self._user_io.out.writeln(" Layout: %s" % v["layout"]) def _show_help(self): """Prints a summary of all commands """ grps = [("Consumer commands", ("install", "config", "get", "info", "search")), ("Creator commands", ("new", "create", "upload", "export", "export-pkg", "test")), - ("Package development commands", ("source", "build", "package", "link", + ("Package development commands", ("source", "build", "package", "editable", "workspace")), ("Misc commands", ("profile", "remote", "user", "imports", "copy", "remove", "alias", "download", "inspect", "help"))] diff --git a/conans/client/conan_api.py b/conans/client/conan_api.py index 80e01a4fe3d..662775e2223 100644 --- a/conans/client/conan_api.py +++ b/conans/client/conan_api.py @@ -472,7 +472,7 @@ def workspace_install(self, path, settings=None, options=None, env=None, self._cache, self._user_io.out) self._user_io.out.success("Using workspace file from %s" % workspace._base_folder) - self._cache.editable_packages.update(workspace.get_editable_dict()) + self._cache.editable_packages = workspace.get_editable_dict() recorder = ActionRecorder() deps_graph, _ = self._graph_manager.load_graph(workspace.root, None, graph_info, build, @@ -1006,7 +1006,8 @@ def get_package_revisions(self, reference, remote_name=None): remote = self.get_remote_by_name(remote_name) return self._remote_manager.get_package_revisions(pref, remote=remote) - def link(self, path, reference, layout, cwd): + @api_method + def editable_add(self, path, reference, layout, cwd): # Retrieve conanfile.py from target_path target_path = _get_conanfile_path(path=path, cwd=cwd, py=True) @@ -1025,10 +1026,14 @@ def link(self, path, reference, layout, cwd): self._cache.editable_packages.link(ref, os.path.dirname(target_path), layout_abs_path) @api_method - def unlink(self, reference): + def editable_remove(self, reference): ref = ConanFileReference.loads(reference, validate=True) return self._cache.editable_packages.remove(ref) + @api_method + def editable_list(self): + return {str(k): v for k, v in self._cache.editable_packages.refs().items()} + Conan = ConanAPIV1 diff --git a/conans/client/installer.py b/conans/client/installer.py index e926cff0243..d96fe55075e 100644 --- a/conans/client/installer.py +++ b/conans/client/installer.py @@ -320,7 +320,7 @@ def _handle_node_editable(self, node, graph_info): settings=node.conanfile.settings, options=node.conanfile.options) - build_folder = editable_cpp_info.folder(node.ref, "build", + build_folder = editable_cpp_info.folder(node.ref, "build_folder", settings=node.conanfile.settings, options=node.conanfile.options) if build_folder is not None: diff --git a/conans/model/editable_cpp_info.py b/conans/model/editable_cpp_info.py index 67629ef6dd8..541e2153765 100644 --- a/conans/model/editable_cpp_info.py +++ b/conans/model/editable_cpp_info.py @@ -19,18 +19,19 @@ def get_editable_abs_path(path, cwd, cache_folder): layout_abs_path = os.path.join(cache_folder, LAYOUTS_FOLDER, path) if not os.path.isfile(layout_abs_path): raise ConanException("Couldn't find layout file: %s" % path) - EditableCppInfo.load(layout_abs_path) # Try if it loads ok + EditableLayout.load(layout_abs_path) # Try if it loads ok return layout_abs_path # Default only in cache layout_abs_path = os.path.join(cache_folder, LAYOUTS_FOLDER, DEFAULT_LAYOUT_FILE) if os.path.isfile(layout_abs_path): - EditableCppInfo.load(layout_abs_path) + EditableLayout.load(layout_abs_path) return layout_abs_path -class EditableCppInfo(object): +class EditableLayout(object): cpp_info_dirs = ['includedirs', 'libdirs', 'resdirs', 'bindirs', 'builddirs', 'srcdirs'] + folders = ['build_folder', 'source_folder'] def __init__(self, data, folders): self._data = data @@ -45,7 +46,7 @@ def folder(self, ref, name, settings, options): try: return self._work_on_item(path, settings, options) except Exception as e: - raise ConanException("Error getting folder '%s' from layout: %s" % (str(name), str(e))) + raise ConanException("Error getting fHolder '%s' from layout: %s" % (str(name), str(e))) @staticmethod def load(filepath): @@ -58,13 +59,17 @@ def load(filepath): data = OrderedDict() folders = {} for section in parser.sections(): - ref, cpp_info_dir = section.rsplit(":", 1) if ':' in section else (None, section) - if cpp_info_dir == "folders": - folders[ref] = {k: v for k, v in parser.items(section)} + ref, section_name = section.rsplit(":", 1) if ':' in section else (None, section) + if section_name in EditableLayout.folders: + items = [k for k, _ in parser.items(section)] or [""] + if len(items) > 1: + raise ConanException("'%s' with more than one value in layout file: %s" + % (section_name, filepath)) + folders.setdefault(ref, {})[section_name] = items[0] continue - if cpp_info_dir not in EditableCppInfo.cpp_info_dirs: + if section_name not in EditableLayout.cpp_info_dirs: raise ConanException("Wrong cpp_info field '%s' in layout file: %s" - % (cpp_info_dir, filepath)) + % (section_name, filepath)) if ref: try: r = ConanFileReference.loads(ref, validate=True) @@ -73,9 +78,9 @@ def load(filepath): except ConanException: raise ConanException("Wrong package reference '%s' in layout file: %s" % (ref, filepath)) - data.setdefault(ref, {})[cpp_info_dir] = [k for k, _ in parser.items(section)] + data.setdefault(ref, {})[section_name] = [k for k, _ in parser.items(section)] - return EditableCppInfo(data, folders) + return EditableLayout(data, folders) @staticmethod def _work_on_item(value, settings, options): diff --git a/conans/model/workspace.py b/conans/model/workspace.py index 64e7b9038ce..20b6ddad4dc 100644 --- a/conans/model/workspace.py +++ b/conans/model/workspace.py @@ -38,8 +38,8 @@ def generate(self, cwd, graph): layout = self._cache.package_layout(ref) editable = layout.editable_cpp_info() conanfile = editables[ref] - build = editable.folder(ref, "build", conanfile.settings, conanfile.options) - src = editable.folder(ref, "src", conanfile.settings, conanfile.options) + build = editable.folder(ref, "build_folder", conanfile.settings, conanfile.options) + src = editable.folder(ref, "source_folder", conanfile.settings, conanfile.options) if src: src = os.path.join(ws_pkg.root_folder, src).replace("\\", "/") cmake += 'set(PACKAGE_%s_SRC "%s")\n' % (ref.name, src) diff --git a/conans/paths/package_layouts/package_editable_layout.py b/conans/paths/package_layouts/package_editable_layout.py index a81a063082f..4eea3676e84 100644 --- a/conans/paths/package_layouts/package_editable_layout.py +++ b/conans/paths/package_layouts/package_editable_layout.py @@ -3,7 +3,7 @@ import os from conans.errors import ConanException -from conans.model.editable_cpp_info import EditableCppInfo +from conans.model.editable_cpp_info import EditableLayout from conans.model.ref import ConanFileReference from conans.model.ref import PackageReference from conans.paths import CONANFILE @@ -30,7 +30,7 @@ def conanfile(self): def editable_cpp_info(self): if self._layout_file: if os.path.isfile(self._layout_file): - return EditableCppInfo.load(self._layout_file) + return EditableLayout.load(self._layout_file) else: raise ConanException("Layout file not found: %s" % self._layout_file) diff --git a/conans/search/search.py b/conans/search/search.py index 51fc7d9dc77..1ae1992544e 100644 --- a/conans/search/search.py +++ b/conans/search/search.py @@ -99,16 +99,12 @@ def search_recipes(cache, pattern=None, ignorecase=True): pattern = re.compile(pattern, re.IGNORECASE) if ignorecase else re.compile(pattern) subdirs = list_folder_subdirs(basedir=cache.store, level=4) - if not pattern: - return sorted([ConanFileReference(*folder.split("/")) for folder in subdirs]) - else: - ret = [] - for subdir in subdirs: - ref = ConanFileReference(*subdir.split("/")) - if _partial_match(pattern, ref): - ret.append(ref) - - return sorted(ret) + refs = [ConanFileReference(*folder.split("/")) for folder in subdirs] + refs.extend(cache.editable_packages.refs().keys()) + refs = sorted(refs) + if pattern: + refs = [r for r in refs if _partial_match(pattern, r)] + return refs def _partial_match(pattern, ref): diff --git a/conans/test/functional/editable/commands/info_on_child_test.py b/conans/test/functional/editable/commands/info_on_child_test.py index aa05445ceb5..605ec21da55 100644 --- a/conans/test/functional/editable/commands/info_on_child_test.py +++ b/conans/test/functional/editable/commands/info_on_child_test.py @@ -39,7 +39,7 @@ def setUp(self): body='requires = "{}"'.format(self.ref_parent)), "mylayout": self.conan_package_layout, }, path=lib_folder) - self.t.run('link "{}" {}'.format(lib_folder, self.ref)) + self.t.run('editable add "{}" {}'.format(lib_folder, self.ref)) self.assertTrue(self.t.cache.installed_as_editable(self.ref)) # Create child @@ -48,7 +48,7 @@ def setUp(self): self.t.run('export . {}'.format(self.ref_child)) def tearDown(self): - self.t.run('link {} --remove'.format(self.ref)) + self.t.run('editable remove {}'.format(self.ref)) self.assertFalse(self.t.cache.installed_as_editable(self.ref)) @parameterized.expand([(True, ), (False, )]) diff --git a/conans/test/functional/editable/commands/info_test.py b/conans/test/functional/editable/commands/info_test.py index 5f5d449164f..777093fc9ba 100644 --- a/conans/test/functional/editable/commands/info_test.py +++ b/conans/test/functional/editable/commands/info_test.py @@ -33,11 +33,11 @@ def setUp(self): self.conanfile_base.format( body='requires = "{}"'.format(self.ref_parent)), "mylayout": self.conan_package_layout, }) - self.t.run('link . {}'.format(self.ref)) + self.t.run('editable add . {}'.format(self.ref)) self.assertTrue(self.t.cache.installed_as_editable(self.ref)) def tearDown(self): - self.t.run('link {} --remove'.format(self.ref)) + self.t.run('editable remove {}'.format(self.ref)) self.assertFalse(self.t.cache.installed_as_editable(self.ref)) diff --git a/conans/test/functional/editable/commands/inspect_test.py b/conans/test/functional/editable/commands/inspect_test.py index fd52e2634df..a6900df6b2a 100644 --- a/conans/test/functional/editable/commands/inspect_test.py +++ b/conans/test/functional/editable/commands/inspect_test.py @@ -33,11 +33,11 @@ def setUp(self): self.conanfile_base.format( body='requires = "{}"'.format(self.ref_parent)), "mylayout": self.conan_package_layout, }) - self.t.run('link . {}'.format(self.ref)) + self.t.run('editable add . {}'.format(self.ref)) self.assertTrue(self.t.cache.installed_as_editable(self.ref)) def tearDown(self): - self.t.run('link {} --remove'.format(self.ref)) + self.t.run('editable remove {}'.format(self.ref)) self.assertFalse(self.t.cache.installed_as_editable(self.ref)) def test_reference(self): diff --git a/conans/test/functional/editable/consume_header_only_test.py b/conans/test/functional/editable/consume_header_only_test.py index c68403b8de1..1879f1d655e 100644 --- a/conans/test/functional/editable/consume_header_only_test.py +++ b/conans/test/functional/editable/consume_header_only_test.py @@ -95,9 +95,9 @@ def test_header_only(self, use_repo_file, use_cache_file): use_cache_file=use_cache_file, base_folder=base_folder) if use_repo_file: - client_editable.run("link . MyLib/0.1@user/editable --layout=mylayout") + client_editable.run("editable add . MyLib/0.1@user/editable --layout=mylayout") else: - client_editable.run("link . MyLib/0.1@user/editable") + client_editable.run("editable add . MyLib/0.1@user/editable") # Consumer project client = TestClient(base_folder=base_folder) diff --git a/conans/test/functional/editable/consume_settings_and_options_test.py b/conans/test/functional/editable/consume_settings_and_options_test.py index c7f9b0c1534..df7e1d6bf8c 100644 --- a/conans/test/functional/editable/consume_settings_and_options_test.py +++ b/conans/test/functional/editable/consume_settings_and_options_test.py @@ -89,9 +89,9 @@ def test_settings_options(self, build_type, shared, use_repo_file): client_editable = HeaderOnlyLibTestClient(use_repo_file=use_repo_file, base_folder=base_folder) if use_repo_file: - client_editable.run("link . MyLib/0.1@user/editable -l=mylayout") + client_editable.run("editable add . MyLib/0.1@user/editable -l=mylayout") else: - client_editable.run("link . MyLib/0.1@user/editable") + client_editable.run("editable add . MyLib/0.1@user/editable") # Consumer project client = TestClient(base_folder=base_folder) diff --git a/conans/test/functional/editable/forbidden_commands_test.py b/conans/test/functional/editable/forbidden_commands_test.py index 10bc1f29507..e2d9e503aaf 100644 --- a/conans/test/functional/editable/forbidden_commands_test.py +++ b/conans/test/functional/editable/forbidden_commands_test.py @@ -21,7 +21,7 @@ class APck(ConanFile): t.save(files={'conanfile.py': conanfile, "mylayout": "", }) t.run("export . lib/version@user/name") - t.run('link . {}'.format(ref)) + t.run('editable add . {}'.format(ref)) self.assertTrue(t.cache.installed_as_editable(ref)) t.run('remove {} --force'.format(ref), assert_error=True) self.assertIn("Package 'lib/version@user/name' is installed as editable, unlink it first " @@ -34,6 +34,7 @@ class APck(ConanFile): t.out) self.assertTrue(t.cache.installed_as_editable(ref)) + class ForbiddenCommandsTest(unittest.TestCase): conanfile = textwrap.dedent("""\ from conans import ConanFile @@ -50,7 +51,7 @@ def setUp(self): self.t = TestClient(servers=self.servers, users={"default": [("lasote", "mypass")]}) self.t.save(files={'conanfile.py': self.conanfile, "mylayout": "", }) - self.t.run('link . {}'.format(self.ref)) + self.t.run('editable add . {}'.format(self.ref)) self.assertTrue(self.t.cache.installed_as_editable(self.ref)) def test_export(self): diff --git a/conans/test/functional/editable/graph_related_test.py b/conans/test/functional/editable/graph_related_test.py index 8f7d07f030a..acc4850e48c 100644 --- a/conans/test/functional/editable/graph_related_test.py +++ b/conans/test/functional/editable/graph_related_test.py @@ -33,7 +33,7 @@ def setUp(self): self.assertFalse(os.path.exists(self.t.cache.conan(self.ref))) def tearDown(self): - self.t.run('link {} --remove'.format(self.ref)) + self.t.run('editable remove {}'.format(self.ref)) self.assertFalse(self.t.cache.installed_as_editable(self.ref)) @@ -52,7 +52,7 @@ def setUp(self): 'package', 'source']) def tearDown(self): - self.t.run('link {} --remove'.format(self.ref)) + self.t.run('editable remove {}'.format(self.ref)) self.assertTrue(os.path.exists(self.t.cache.conan(self.ref))) self.assertListEqual(sorted(os.listdir(self.t.cache.conan(self.ref))), ['build', 'export', 'export_source', 'locks', 'metadata.json', @@ -64,7 +64,7 @@ class RelatedToGraphBehavior(object): def test_do_nothing(self): self.t.save(files={'conanfile.py': conanfile, "mylayout": conan_package_layout, }) - self.t.run('link . {}'.format(self.ref)) + self.t.run('editable add . {}'.format(self.ref)) self.assertTrue(self.t.cache.installed_as_editable(self.ref)) @parameterized.expand([(True, ), (False, )]) @@ -81,7 +81,7 @@ def test_install_requirements(self, update): self.t.save(files={'conanfile.py': conanfile_base.format(body='requires = "{}"'.format(ref_parent)), "mylayout": conan_package_layout, }) - self.t.run('link . {}'.format(self.ref)) + self.t.run('editable add . {}'.format(self.ref)) # Install our project and check that everything is in place update = ' --update' if update else '' @@ -107,7 +107,7 @@ def test_middle_graph(self, update): conanfile_base.format(body='requires = "{}"'.format(ref_parent)), "mylayout": conan_package_layout, }, path=path_to_lib) - self.t.run('link "{}" {}'.format(path_to_lib, self.ref)) + self.t.run('editable add "{}" {}'.format(path_to_lib, self.ref)) # Create a child an install it (in other folder, do not override the link!) path_to_child = os.path.join(self.t.current_folder, 'child') diff --git a/conans/test/functional/editable/layouts_test.py b/conans/test/functional/editable/layouts_test.py index 8bb42d71cdd..4077e1a1eb4 100644 --- a/conans/test/functional/editable/layouts_test.py +++ b/conans/test/functional/editable/layouts_test.py @@ -23,7 +23,7 @@ class Pkg(ConanFile): client.save({"conanfile.py": conanfile, "layout": ""}) - client.run("link . mytool/0.1@user/testing -l=layout") + client.run("editable add . mytool/0.1@user/testing -l=layout") self.assertIn("Using layout file:", client.out) client2 = TestClient(client.base_folder) consumer = textwrap.dedent(""" @@ -67,7 +67,7 @@ class Pkg(ConanFile): client.save({"conanfile.py": conanfile, "layout_win": layout_repo.format("win"), "layout_linux": layout_repo.format("linux")}) - client.run("link . mytool/0.1@user/testing") + client.run("editable add . mytool/0.1@user/testing") client2 = TestClient(client.base_folder) consumer = textwrap.dedent(""" [requires] @@ -82,7 +82,7 @@ class Pkg(ConanFile): # Using the repo file layouts for layout in ("win", "linux", "win_cache", "linux_cache", "win_cache2", "linux_cache2"): - client.run("link . mytool/0.1@user/testing -l=layout_%s" % layout) + client.run("editable add . mytool/0.1@user/testing -l=layout_%s" % layout) client2.run("install . -g cmake") self.assertIn("mytool/0.1@user/testing from user folder - Editable", client2.out) cmake = load(os.path.join(client2.current_folder, "conanbuildinfo.cmake")) @@ -107,7 +107,7 @@ class Pkg(ConanFile): client.save({"conanfile.py": conanfile, "layout/win": layout_repo.format("layout/win"), "layout/linux": layout_repo.format("layout/linux")}) - client.run("link . mytool/0.1@user/testing") + client.run("editable add . mytool/0.1@user/testing") client2 = TestClient(client.base_folder) consumer = textwrap.dedent(""" [requires] @@ -122,7 +122,7 @@ class Pkg(ConanFile): # Using the cache file layouts for layout in ("win/cache", "linux/cache", "layout/win", "layout/linux"): - client.run("link . mytool/0.1@user/testing -l=%s" % layout) + client.run("editable add . mytool/0.1@user/testing -l=%s" % layout) client2.run("install . -g cmake") self.assertIn("mytool/0.1@user/testing from user folder - Editable", client2.out) cmake = load(os.path.join(client2.current_folder, "conanbuildinfo.cmake")) @@ -142,7 +142,7 @@ def package_info(self): """) client.save({"conanfile.py": conanfile}) - client.run("link . mytool/0.1@user/testing") + client.run("editable add . mytool/0.1@user/testing") client2 = TestClient(client.base_folder) consumer = textwrap.dedent(""" [requires] @@ -171,7 +171,7 @@ class Pkg(ConanFile): client.save({"conanfile.py": conanfile, "layout": layout_repo}) - client.run("link . mytool/0.1@user/testing -l=layout") + client.run("editable add . mytool/0.1@user/testing -l=layout") client2 = TestClient(client.base_folder) consumer = textwrap.dedent(""" [requires] @@ -207,7 +207,7 @@ class Pkg(ConanFile): layout_path = os.path.join(tmp_folder, "layout") save(layout_path, layoutabs) client.save({"conanfile.py": conanfile}) - client.run('link . mytool/0.1@user/testing -l="%s"' % layout_path) + client.run('editable add . mytool/0.1@user/testing -l="%s"' % layout_path) client2 = TestClient(client.base_folder) consumer = textwrap.dedent(""" [requires] diff --git a/conans/test/functional/editable/link_create_test.py b/conans/test/functional/editable/link_create_test.py index a41ff1c007a..7470823afb8 100644 --- a/conans/test/functional/editable/link_create_test.py +++ b/conans/test/functional/editable/link_create_test.py @@ -25,16 +25,29 @@ def test_link_wrong_layout(self): ref = ConanFileReference.loads('lib/version@user/name') t = TestClient() t.save(files={'conanfile.py': self.conanfile, "mylayout": ""}) - t.run('link . {} --layout=missing'.format(ref), assert_error=True) + t.run('editable add . {} --layout=missing'.format(ref), assert_error=True) self.assertIn("ERROR: Couldn't find layout file: missing", t.out) def test_install_ok(self): ref = ConanFileReference.loads('lib/version@user/name') t = TestClient() t.save(files={'conanfile.py': self.conanfile}) - t.run('link . {}'.format(ref)) + t.run('editable add . {}'.format(ref)) self.assertIn("Reference 'lib/version@user/name' linked to directory '", t.out) + def test_editable_list_search(self): + ref = ConanFileReference.loads('lib/version@user/name') + t = TestClient() + t.save(files={'conanfile.py': self.conanfile}) + t.run('editable add . {}'.format(ref)) + t.run("editable list") + self.assertIn("lib/version@user/name", t.out) + self.assertIn(" Layout: None", t.out) + self.assertIn(" Path:", t.out) + + t.run("search") + self.assertIn("lib/version@user/name", t.out) + def test_install_wrong_reference(self): ref = ConanFileReference.loads('lib/version@user/name') @@ -47,6 +60,6 @@ class Pck(ConanFile): version = "version" """)}) t.run('export . {}'.format(ref)) - t.run('link . wrong/version@user/channel', assert_error=True) + t.run('editable add . wrong/version@user/channel', assert_error=True) self.assertIn("ERROR: Name and version from reference (wrong/version@user/channel) and " "target conanfile.py (lib/version) must match", t.out) diff --git a/conans/test/functional/editable/link_remove_test.py b/conans/test/functional/editable/link_remove_test.py index fdd05b35b86..82a8c6bcb4f 100644 --- a/conans/test/functional/editable/link_remove_test.py +++ b/conans/test/functional/editable/link_remove_test.py @@ -21,16 +21,16 @@ def setUp(self): self.t = TestClient() self.t.save(files={'conanfile.py': self.conanfile, "mylayout": "", }) - self.t.run('link . {} -l=mylayout'.format(self.ref)) + self.t.run('editable add . {} -l=mylayout'.format(self.ref)) self.assertTrue(self.t.cache.installed_as_editable(self.ref)) def test_unlink(self): - self.t.run('link {} --remove'.format(self.ref)) + self.t.run('editable remove {}'.format(self.ref)) self.assertIn("Removed linkage for reference '{}'".format(self.ref), self.t.out) self.assertFalse(self.t.cache.installed_as_editable(self.ref)) def test_unlink_not_linked(self): reference = 'otherlib/version@user/name' self.t.run('search {}'.format(reference), assert_error=True) - self.t.run('link {} --remove'.format(reference)) + self.t.run('editable remove {}'.format(reference)) self.assertIn("Reference '{}' was not installed as editable".format(reference), self.t.out) diff --git a/conans/test/functional/editable/transitive_editable_test.py b/conans/test/functional/editable/transitive_editable_test.py index c340769a60f..a8ae82c6749 100644 --- a/conans/test/functional/editable/transitive_editable_test.py +++ b/conans/test/functional/editable/transitive_editable_test.py @@ -15,7 +15,7 @@ def test_transitive_editables(self): client = TestClient() conanfileC = TestConanFile("LibC", "0.1") client.save({"conanfile.py": str(conanfileC)}) - client.run("link . LibC/0.1@user/testing") + client.run("editable add . LibC/0.1@user/testing") client2 = TestClient(client.base_folder) conanfileB = TestConanFile("LibB", "0.1", requires=["LibC/0.1@user/testing"]) diff --git a/conans/test/integration/workspace_test.py b/conans/test/integration/workspace_test.py index 70c27fb89bb..1818bab59a4 100644 --- a/conans/test/integration/workspace_test.py +++ b/conans/test/integration/workspace_test.py @@ -111,8 +111,8 @@ def files(name, depend=None): root: HelloA/0.1@lasote/stable """) layout = dedent(""" - [folders] - build: + [build_folder] + """) client.save({"conanws.yml": project, "layout": layout}) @@ -156,8 +156,8 @@ def files(name, depend=None): root: HelloA/0.1@lasote/stable """) layout = dedent(""" - [folders] - build: build/{settings.build_type} + [build_folder] + build/{settings.build_type} [includedirs] src @@ -229,9 +229,11 @@ def files(name, depend=None): root: HelloA/0.1@lasote/stable """) layout = dedent(""" - [folders] - build: build/{settings.build_type} - src: src + [build_folder] + build/{settings.build_type} + + [source_folder] + src [includedirs] src @@ -345,10 +347,10 @@ def files(name, depend=None): root: HelloA/0.1@lasote/stable """) layout = dedent(""" - [folders] - build: build - src: src - + [build_folder] + build + [source_folder] + src [includedirs] src @@ -461,8 +463,8 @@ def files(name, depend=None): root: HelloA/0.1@lasote/stable """) layout = dedent(""" - [folders] - build: build + [build_folder] + build """) client.save({"conanws.yml": project, "layout": layout}) diff --git a/conans/test/unittests/model/editable_cpp_info/apply_test.py b/conans/test/unittests/model/editable_cpp_info/apply_test.py index 387fdc39d44..6c38256b4bb 100644 --- a/conans/test/unittests/model/editable_cpp_info/apply_test.py +++ b/conans/test/unittests/model/editable_cpp_info/apply_test.py @@ -6,7 +6,7 @@ import textwrap import unittest -from conans.model.editable_cpp_info import EditableCppInfo +from conans.model.editable_cpp_info import EditableLayout from conans.model.build_info import CppInfo from conans.test.utils.test_files import temp_folder from conans.util.files import save @@ -29,7 +29,7 @@ """) -class ApplyEditableCppInfoTest(unittest.TestCase): +class ApplyEditableLayoutTest(unittest.TestCase): def setUp(self): self.test_folder = temp_folder() @@ -42,7 +42,7 @@ def tearDown(self): def test_require_no_namespace(self): content = base_content.format(namespace="", path_prefix="") save(self.layout_filepath, content) - editable_cpp_info = EditableCppInfo.load(self.layout_filepath) + editable_cpp_info = EditableLayout.load(self.layout_filepath) cpp_info = CppInfo(None) editable_cpp_info.apply_to(self.ref, cpp_info, settings=None, options=None) self.assertListEqual(cpp_info.includedirs, ['dirs/includedirs']) @@ -57,7 +57,7 @@ def test_require_namespace(self): base_content.format(namespace="libA/0.1@user/channel:", path_prefix="libA/") ]) save(self.layout_filepath, content) - editable_cpp_info = EditableCppInfo.load(self.layout_filepath) + editable_cpp_info = EditableLayout.load(self.layout_filepath) cpp_info = CppInfo(None) editable_cpp_info.apply_to(self.ref, cpp_info, settings=None, options=None) self.assertListEqual(cpp_info.includedirs, ['libA/dirs/includedirs']) diff --git a/conans/test/unittests/model/editable_cpp_info/parse_test.py b/conans/test/unittests/model/editable_cpp_info/parse_test.py index cad0b75be42..1c3ae67a261 100644 --- a/conans/test/unittests/model/editable_cpp_info/parse_test.py +++ b/conans/test/unittests/model/editable_cpp_info/parse_test.py @@ -6,7 +6,7 @@ import unittest from conans.errors import ConanException -from conans.model.editable_cpp_info import EditableCppInfo +from conans.model.editable_cpp_info import EditableLayout from conans.test.utils.test_files import temp_folder from conans.util.files import save @@ -26,14 +26,14 @@ def field_error_test(self): """) save(self.layout_filepath, content) with self.assertRaisesRegexp(ConanException, "Wrong cpp_info field 'includedrs' in layout"): - _ = EditableCppInfo.load(self.layout_filepath) + _ = EditableLayout.load(self.layout_filepath) content = textwrap.dedent(""" [*:includedrs] something """) save(self.layout_filepath, content) with self.assertRaisesRegexp(ConanException, "Wrong cpp_info field 'includedrs' in layout"): - _ = EditableCppInfo.load(self.layout_filepath) + _ = EditableLayout.load(self.layout_filepath) content = textwrap.dedent(""" [*:includedirs] @@ -41,7 +41,7 @@ def field_error_test(self): """) save(self.layout_filepath, content) with self.assertRaisesRegexp(ConanException, "Wrong package reference '\*' in layout file"): - _ = EditableCppInfo.load(self.layout_filepath) + _ = EditableLayout.load(self.layout_filepath) content = textwrap.dedent(""" [pkg/version@user/channel:revision:includedirs] @@ -50,4 +50,4 @@ def field_error_test(self): save(self.layout_filepath, content) with self.assertRaisesRegexp(ConanException, "Wrong package reference " "'pkg/version@user/channel:revision' in layout file"): - _ = EditableCppInfo.load(self.layout_filepath) + _ = EditableLayout.load(self.layout_filepath) diff --git a/conans/test/unittests/model/editable_cpp_info/work_on_items_test.py b/conans/test/unittests/model/editable_cpp_info/work_on_items_test.py index dbe1dc3e557..39d09e3ef85 100644 --- a/conans/test/unittests/model/editable_cpp_info/work_on_items_test.py +++ b/conans/test/unittests/model/editable_cpp_info/work_on_items_test.py @@ -3,14 +3,14 @@ import unittest from conans.client.conf import default_settings_yml -from conans.model.editable_cpp_info import EditableCppInfo +from conans.model.editable_cpp_info import EditableLayout from conans.model.settings import Settings class WorkOnItemsTest(unittest.TestCase): def test_empty(self): - self.assertEqual("", EditableCppInfo._work_on_item("", None, None)) + self.assertEqual("", EditableLayout._work_on_item("", None, None)) def test_placeholders(self): settings = Settings.loads(default_settings_yml) @@ -19,18 +19,18 @@ def test_placeholders(self): settings.build_type = 'Debug' self.assertEqual('src/Visual Studio14/Debug/include', - EditableCppInfo._work_on_item("src/{settings.compiler}{settings.compiler.version}/{settings.build_type}/include", + EditableLayout._work_on_item("src/{settings.compiler}{settings.compiler.version}/{settings.build_type}/include", settings=settings, options=None)) self.assertEqual('C:/Visual Studio/include/', - EditableCppInfo._work_on_item("C:\\{settings.compiler}\\include\\", + EditableLayout._work_on_item("C:\\{settings.compiler}\\include\\", settings=settings, options=None)) self.assertEqual('C:/Visual Studio/include/', - EditableCppInfo._work_on_item("C:\{settings.compiler}\include\\", + EditableLayout._work_on_item("C:\{settings.compiler}\include\\", settings=settings, options=None)) self.assertEqual('/usr/path with spaces/Visual Studio/dir', - EditableCppInfo._work_on_item("/usr/path with spaces/{settings.compiler}/dir", + EditableLayout._work_on_item("/usr/path with spaces/{settings.compiler}/dir", settings=settings, options=None)) From 29051d2224b56d9c04cc2bd6d4947cf5d25bdc91 Mon Sep 17 00:00:00 2001 From: memsharded Date: Thu, 14 Feb 2019 01:38:22 +0100 Subject: [PATCH 19/41] fixing tests --- conans/test/unittests/model/version_ranges_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conans/test/unittests/model/version_ranges_test.py b/conans/test/unittests/model/version_ranges_test.py index 44bd5da2122..2b7c5d1c579 100644 --- a/conans/test/unittests/model/version_ranges_test.py +++ b/conans/test/unittests/model/version_ranges_test.py @@ -10,9 +10,9 @@ from conans.errors import ConanException from conans.model.ref import ConanFileReference from conans.model.requires import Requirements -from conans.paths.simple_paths import SimplePaths from conans.test.unittests.model.fake_retriever import Retriever from conans.test.utils.tools import TestBufferConanOutput, test_processed_profile +from conans.client.cache.cache import ClientCache def _clear_revs(requires): @@ -165,7 +165,7 @@ def setUp(self): self.loader = ConanFileLoader(None, self.output, ConanPythonRequire(None, None)) self.retriever = Retriever(self.loader) self.remote_search = MockSearchRemote() - paths = SimplePaths(self.retriever.folder) + paths = ClientCache(self.retriever.folder, self.retriever.folder, self.output) self.resolver = RangeResolver(paths, self.remote_search) self.builder = DepsGraphBuilder(self.retriever, self.output, self.loader, self.resolver, None) From cb889ea3dcc5678ceefd0d3426e6b7ce0ce25ec7 Mon Sep 17 00:00:00 2001 From: memsharded Date: Thu, 14 Feb 2019 02:11:07 +0100 Subject: [PATCH 20/41] more time.sleep in test --- conans/test/integration/workspace_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conans/test/integration/workspace_test.py b/conans/test/integration/workspace_test.py index 1818bab59a4..28cf733f16d 100644 --- a/conans/test/integration/workspace_test.py +++ b/conans/test/integration/workspace_test.py @@ -270,11 +270,11 @@ def files(name, depend=None): self.assertIn("Hello World B Release!", client.out) self.assertIn("Hello World A Release!", client.out) + time.sleep(1) tools.replace_in_file(os.path.join(client.current_folder, "C/src/hello.cpp"), "Hello World", "Bye Moon", output=client.out) - + time.sleep(1) client.runner('cmake --build . --config Release', cwd=base_release) - client.runner(cmd_release, cwd=client.current_folder) self.assertIn("Bye Moon C Release!", client.out) self.assertIn("Hello World B Release!", client.out) From 5d2153e4929b34fc328064e7c58424aae6e39956 Mon Sep 17 00:00:00 2001 From: memsharded Date: Tue, 19 Feb 2019 01:21:55 +0100 Subject: [PATCH 21/41] solve merge issues --- conans/client/cmd/export_pkg.py | 2 +- conans/test/unittests/model/transitive_reqs_test.py | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/conans/client/cmd/export_pkg.py b/conans/client/cmd/export_pkg.py index 4e8a7034d1f..2ea394e981a 100644 --- a/conans/client/cmd/export_pkg.py +++ b/conans/client/cmd/export_pkg.py @@ -20,7 +20,7 @@ def export_pkg(cache, graph_manager, hook_manager, recorder, output, # to be downloaded from remotes deps_graph, _ = graph_manager.load_graph(ref, None, graph_info=graph_info, build_mode=[ref.name], check_updates=False, update=False, - remote_name=None, recorder=recorder, workspace=None) + remote_name=None, recorder=recorder) # this is a bit tricky, but works. The root (virtual), has only 1 neighbor, # which is the exported pkg nodes = deps_graph.root.neighbors() diff --git a/conans/test/unittests/model/transitive_reqs_test.py b/conans/test/unittests/model/transitive_reqs_test.py index 2c615416c02..1fd63b58731 100644 --- a/conans/test/unittests/model/transitive_reqs_test.py +++ b/conans/test/unittests/model/transitive_reqs_test.py @@ -16,12 +16,16 @@ from conans.test.unittests.model.fake_retriever import Retriever from conans.test.utils.tools import NO_SETTINGS_PACKAGE_ID, TestBufferConanOutput,\ test_processed_profile -from conans.client.graph.graph_binaries import GraphBinariesAnalyzer +import os + from mock import Mock + +from conans.client.cache.cache import ClientCache from conans.client.graph.build_mode import BuildMode -from conans.test.utils.conanfile import TestConanFile -from conans.paths.simple_paths import SimplePaths +from conans.client.graph.graph_binaries import GraphBinariesAnalyzer from conans.client.graph.range_resolver import RangeResolver +from conans.test.utils.conanfile import TestConanFile + say_content = TestConanFile("Say", "0.1") say_content2 = TestConanFile("Say", "0.2") @@ -77,7 +81,8 @@ def setUp(self): self.output = TestBufferConanOutput() self.loader = ConanFileLoader(None, self.output, ConanPythonRequire(None, None)) self.retriever = Retriever(self.loader) - paths = SimplePaths(self.retriever.folder) + paths = ClientCache(self.retriever.folder, self.retriever.folder, + self.output) self.remote_search = MockSearchRemote() self.resolver = RangeResolver(paths, self.remote_search) self.builder = DepsGraphBuilder(self.retriever, self.output, self.loader, From b0300aac5e6736d8dd9bd69a1ab878c2788fdc83 Mon Sep 17 00:00:00 2001 From: memsharded Date: Tue, 19 Feb 2019 22:22:08 +0100 Subject: [PATCH 22/41] adding generators --- conans/client/conan_api.py | 8 ++++ conans/model/workspace.py | 22 ++++++++--- conans/test/integration/workspace_test.py | 47 +++++++++++++++++++++++ 3 files changed, 71 insertions(+), 6 deletions(-) diff --git a/conans/client/conan_api.py b/conans/client/conan_api.py index f12e2f10ede..e0a6ef040cd 100644 --- a/conans/client/conan_api.py +++ b/conans/client/conan_api.py @@ -61,6 +61,7 @@ from conans.util.files import exception_message_safe, mkdir, save_files from conans.util.log import configure_logger from conans.util.tracer import log_command, log_exception +from conans.client.graph.graph import RECIPE_EDITABLE default_manifest_folder = '.conan_manifests' @@ -480,6 +481,13 @@ def workspace_install(self, path, settings=None, options=None, env=None, print_graph(deps_graph, self._user_io.out) + # Inject the generators before installing + for node in deps_graph.nodes: + if node.recipe == RECIPE_EDITABLE: + generators = workspace[node.ref].generators + if generators is not None: + node.conanfile.generators = generators + installer = BinaryInstaller(self._cache, self._user_io.out, self._remote_manager, recorder=recorder, hook_manager=self._hook_manager) installer.install(deps_graph, keep_build=False, graph_info=graph_info) diff --git a/conans/model/workspace.py b/conans/model/workspace.py index d543b2fc2c4..15904aceb7c 100644 --- a/conans/model/workspace.py +++ b/conans/model/workspace.py @@ -12,7 +12,7 @@ class LocalPackage(object): - def __init__(self, base_folder, data, cache, ws_layout): + def __init__(self, base_folder, data, cache, ws_layout, ws_generators): self._base_folder = base_folder self._conanfile_folder = data.get("folder") # The folder with the conanfile layout = data.get("layout") @@ -22,6 +22,13 @@ def __init__(self, base_folder, data, cache, ws_layout): else: self.layout = ws_layout + generators = data.get("generators") + if isinstance(generators, str): + generators = [generators] + if generators is None: + generators = ws_generators + self.generators = generators + @property def root_folder(self): return os.path.abspath(os.path.join(self._base_folder, self._conanfile_folder)) @@ -91,17 +98,20 @@ def _loads(self, text): yml = yaml.safe_load(text) self._generator = yml.pop("generator", None) yml.pop("name", None) - self._layout = yml.pop("layout", None) - if self._layout: - self._layout = get_editable_abs_path(self._layout, self._base_folder, - self._cache.conan_folder) + layout = yml.pop("layout", None) + if layout: + layout = get_editable_abs_path(layout, self._base_folder, + self._cache.conan_folder) + generators = yml.pop("generators", None) + if isinstance(generators, str): + generators = [generators] self._root = [ConanFileReference.loads(s.strip()) for s in yml.pop("root", "").split(",") if s.strip()] if not self._root: raise ConanException("Conan workspace needs at least 1 root conanfile") for package_name, data in yml.items(): workspace_package = LocalPackage(self._base_folder, data, - self._cache, self._layout) + self._cache, layout, generators) package_name = ConanFileReference.loads(package_name) self._workspace_packages[package_name] = workspace_package for package_name in self._root: diff --git a/conans/test/integration/workspace_test.py b/conans/test/integration/workspace_test.py index 59cf155bcf6..71ad9d6e053 100644 --- a/conans/test/integration/workspace_test.py +++ b/conans/test/integration/workspace_test.py @@ -569,3 +569,50 @@ def files(name, depend=None): cmake = load(os.path.join(client.current_folder, "A", "build", "conanbuildinfo.cmake")) self.assertIn("myincludeC", cmake) self.assertIn("myincludeB", cmake) + + def generators_test(self): + client = TestClient() + + def files(name, depend=None): + deps = ('"Hello%s/0.1@lasote/stable"' % depend) if depend else "None" + return {"conanfile.py": conanfile_build.format(deps=deps, name=name)} + + client.save(files("C"), path=os.path.join(client.current_folder, "C")) + client.save(files("B", "C"), path=os.path.join(client.current_folder, "B")) + client.save(files("A", "B"), path=os.path.join(client.current_folder, "A")) + + project = dedent(""" + HelloB/0.1@lasote/stable: + folder: B + generators: [make, qmake] + HelloC/0.1@lasote/stable: + folder: C + HelloA/0.1@lasote/stable: + folder: A + generators: visual_studio + layout: layout + generators: cmake + generator: cmake + root: HelloA/0.1@lasote/stable + """) + layout = dedent(""" + [build_folder] + + """) + client.save({"conanws.yml": project, + "layout": layout}) + client.run("workspace install conanws.yml") + self.assertIn("HelloA/0.1@lasote/stable from user folder - Editable", client.out) + self.assertIn("HelloB/0.1@lasote/stable from user folder - Editable", client.out) + self.assertIn("HelloC/0.1@lasote/stable from user folder - Editable", client.out) + + self.assertTrue(os.path.exists(os.path.join(client.current_folder, "B", + "conanbuildinfo.mak"))) + self.assertTrue(os.path.exists(os.path.join(client.current_folder, "B", + "conanbuildinfo.pri"))) + self.assertTrue(os.path.exists(os.path.join(client.current_folder, "A", + "conanbuildinfo.props"))) + self.assertTrue(os.path.exists(os.path.join(client.current_folder, "C", + "conanbuildinfo.cmake"))) + self.assertTrue(os.path.exists(os.path.join(client.current_folder, + "conanworkspace.cmake"))) From d0a98f508b8b7fe1e080ba1967ce3a83f8c2cefd Mon Sep 17 00:00:00 2001 From: memsharded Date: Tue, 19 Feb 2019 23:29:48 +0100 Subject: [PATCH 23/41] make sure develop=True for editable packages --- conans/client/graph/graph_builder.py | 1 + .../test/functional/editable/layouts_test.py | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/conans/client/graph/graph_builder.py b/conans/client/graph/graph_builder.py index c9c827b92d7..7d1a6587e84 100644 --- a/conans/client/graph/graph_builder.py +++ b/conans/client/graph/graph_builder.py @@ -235,6 +235,7 @@ def _create_new_node(self, current_node, dep_graph, requirement, public_deps, na ref=requirement.ref) if recipe_status == RECIPE_EDITABLE: dep_conanfile.in_local_cache = False + dep_conanfile.develop = True if getattr(dep_conanfile, "alias", None): alias_ref = alias_ref or new_ref.copy_clear_rev() diff --git a/conans/test/functional/editable/layouts_test.py b/conans/test/functional/editable/layouts_test.py index 4077e1a1eb4..c8b21f75787 100644 --- a/conans/test/functional/editable/layouts_test.py +++ b/conans/test/functional/editable/layouts_test.py @@ -157,6 +157,27 @@ def package_info(self): include_dirs = re.search('set\(CONAN_INCLUDE_DIRS_MYTOOL "(.*)"\)', cmake).group(1) self.assertTrue(include_dirs.endswith("include_%s" % build_type.lower())) + def test_develop(self): + client = TestClient() + conanfile = textwrap.dedent(""" + from conans import ConanFile + class Pkg(ConanFile): + def package_info(self): + if not self.in_local_cache: + self.output.info("Develop!!=%s!!" % self.develop) + """) + + client.save({"conanfile.py": conanfile}) + client.run("editable add . mytool/0.1@user/testing") + client2 = TestClient(client.base_folder) + consumer = textwrap.dedent(""" + [requires] + mytool/0.1@user/testing + """) + client2.save({"conanfile.txt": consumer}) + client2.run("install .") + self.assertIn("mytool/0.1@user/testing: Develop!!=True!!", client2.out) + def test_parameterized_paths(self): client = TestClient() conanfile = textwrap.dedent(""" From f57d8890787f0f2f50d183b5eebf35a67b552702 Mon Sep 17 00:00:00 2001 From: memsharded Date: Wed, 20 Feb 2019 19:12:17 +0100 Subject: [PATCH 24/41] review --- conans/model/editable_cpp_info.py | 3 - conans/model/workspace.py | 22 ++-- conans/test/integration/workspace_test.py | 116 ++++++++++++---------- 3 files changed, 74 insertions(+), 67 deletions(-) diff --git a/conans/model/editable_cpp_info.py b/conans/model/editable_cpp_info.py index 541e2153765..c4e6ac4d1a9 100644 --- a/conans/model/editable_cpp_info.py +++ b/conans/model/editable_cpp_info.py @@ -92,9 +92,6 @@ def apply_to(self, ref, cpp_info, settings=None, options=None): d = self._data data = d.get(str(ref)) or d.get(None) or {} - if data: # Invalidate previously existing dirs - for info_dir in self.cpp_info_dirs: - setattr(cpp_info, info_dir, []) try: for key, items in data.items(): setattr(cpp_info, key, [self._work_on_item(item, settings, options) diff --git a/conans/model/workspace.py b/conans/model/workspace.py index 15904aceb7c..328f489081c 100644 --- a/conans/model/workspace.py +++ b/conans/model/workspace.py @@ -14,7 +14,7 @@ class LocalPackage(object): def __init__(self, base_folder, data, cache, ws_layout, ws_generators): self._base_folder = base_folder - self._conanfile_folder = data.get("folder") # The folder with the conanfile + self._conanfile_folder = data.get("path") # The folder with the conanfile layout = data.get("layout") if layout: self.layout = get_editable_abs_path(data.get("layout"), self._base_folder, @@ -39,7 +39,7 @@ class Workspace(object): def generate(self, cwd, graph): editables = {node.ref: node.conanfile for node in graph.nodes if node.recipe == RECIPE_EDITABLE} - if self._generator == "cmake": + if self._ws_generator == "cmake": cmake = "" add_subdirs = "" for node in graph.ordered_iterate(): @@ -71,7 +71,7 @@ def generate(self, cwd, graph): def __init__(self, path, cache): self._cache = cache - self._generator = None + self._ws_generator = None self._workspace_packages = OrderedDict() # {reference: LocalPackage} self._base_folder = os.path.dirname(path) try: @@ -96,12 +96,12 @@ def root(self): def _loads(self, text): yml = yaml.safe_load(text) - self._generator = yml.pop("generator", None) + self._ws_generator = yml.pop("workspace_generator", None) yml.pop("name", None) - layout = yml.pop("layout", None) - if layout: - layout = get_editable_abs_path(layout, self._base_folder, - self._cache.conan_folder) + ws_layout = yml.pop("layout", None) + if ws_layout: + ws_layout = get_editable_abs_path(ws_layout, self._base_folder, + self._cache.conan_folder) generators = yml.pop("generators", None) if isinstance(generators, str): generators = [generators] @@ -109,9 +109,11 @@ def _loads(self, text): for s in yml.pop("root", "").split(",") if s.strip()] if not self._root: raise ConanException("Conan workspace needs at least 1 root conanfile") - for package_name, data in yml.items(): + + editables = yml.pop("editables", None) + for package_name, data in editables.items(): workspace_package = LocalPackage(self._base_folder, data, - self._cache, layout, generators) + self._cache, ws_layout, generators) package_name = ConanFileReference.loads(package_name) self._workspace_packages[package_name] = workspace_package for package_name in self._root: diff --git a/conans/test/integration/workspace_test.py b/conans/test/integration/workspace_test.py index 71ad9d6e053..92008f2a7fb 100644 --- a/conans/test/integration/workspace_test.py +++ b/conans/test/integration/workspace_test.py @@ -101,12 +101,13 @@ def files(name, depend=None): client.save(files("A", "B"), path=os.path.join(client.current_folder, "A")) project = dedent(""" - HelloB/0.1@lasote/stable: - folder: B - HelloC/0.1@lasote/stable: - folder: C - HelloA/0.1@lasote/stable: - folder: A + editables: + HelloB/0.1@lasote/stable: + path: B + HelloC/0.1@lasote/stable: + path: C + HelloA/0.1@lasote/stable: + path: A layout: layout root: HelloA/0.1@lasote/stable """) @@ -145,12 +146,13 @@ def files(name, depend=None): client.save(a, path=os.path.join(client.current_folder, "A")) project = dedent(""" - HelloB/0.1@lasote/stable: - folder: B - HelloC/0.1@lasote/stable: - folder: C - HelloA/0.1@lasote/stable: - folder: A + editables: + HelloB/0.1@lasote/stable: + path: B + HelloC/0.1@lasote/stable: + path: C + HelloA/0.1@lasote/stable: + path: A layout: layout root: HelloA/0.1@lasote/stable """) @@ -216,14 +218,15 @@ def files(name, depend=None): client.save(a, path=os.path.join(client.current_folder, "A")) project = dedent(""" - HelloB/0.1@lasote/stable: - folder: B - HelloC/0.1@lasote/stable: - folder: C - HelloA/0.1@lasote/stable: - folder: A + editables: + HelloB/0.1@lasote/stable: + path: B + HelloC/0.1@lasote/stable: + path: C + HelloA/0.1@lasote/stable: + path: A layout: layout - generator: cmake + workspace_generator: cmake root: HelloA/0.1@lasote/stable """) layout = dedent(""" @@ -334,14 +337,15 @@ def files(name, depend=None): client.save(a, path=os.path.join(client.current_folder, "A")) project = dedent(""" - HelloB/0.1@lasote/stable: - folder: B - HelloC/0.1@lasote/stable: - folder: C - HelloA/0.1@lasote/stable: - folder: A + editables: + HelloB/0.1@lasote/stable: + path: B + HelloC/0.1@lasote/stable: + path: C + HelloA/0.1@lasote/stable: + path: A layout: layout - generator: cmake + workspace_generator: cmake root: HelloA/0.1@lasote/stable """) layout = dedent(""" @@ -452,12 +456,13 @@ def files(name, depend=None): client.save(files("A", "B"), path=os.path.join(client.current_folder, "A")) project = dedent(""" - HelloB/0.1@lasote/stable: - folder: B - HelloC/0.1@lasote/stable: - folder: C - HelloA/0.1@lasote/stable: - folder: A + editables: + HelloB/0.1@lasote/stable: + path: B + HelloC/0.1@lasote/stable: + path: C + HelloA/0.1@lasote/stable: + path: A layout: layout root: HelloA/0.1@lasote/stable """) @@ -505,10 +510,11 @@ def files(name, depend=None): client.save(files("A"), path=os.path.join(client.current_folder, "A")) project = dedent(""" - HelloA/0.1@lasote/stable: - folder: A - Tool/0.1@user/testing: - folder: Tool + editables: + HelloA/0.1@lasote/stable: + path: A + Tool/0.1@user/testing: + path: Tool layout: layout root: HelloA/0.1@lasote/stable """) @@ -539,15 +545,16 @@ def files(name, depend=None): client.save(files("A", "B"), path=os.path.join(client.current_folder, "A")) project = dedent(""" - HelloB/0.1@lasote/stable: - folder: B - layout: B/layoutB - HelloC/0.1@lasote/stable: - folder: C - layout: C/layoutC - HelloA/0.1@lasote/stable: - folder: A - layout: A/layoutA + editables: + HelloB/0.1@lasote/stable: + path: B + layout: B/layoutB + HelloC/0.1@lasote/stable: + path: C + layout: C/layoutC + HelloA/0.1@lasote/stable: + path: A + layout: A/layoutA root: HelloA/0.1@lasote/stable """) layout = dedent(""" @@ -582,17 +589,18 @@ def files(name, depend=None): client.save(files("A", "B"), path=os.path.join(client.current_folder, "A")) project = dedent(""" - HelloB/0.1@lasote/stable: - folder: B - generators: [make, qmake] - HelloC/0.1@lasote/stable: - folder: C - HelloA/0.1@lasote/stable: - folder: A - generators: visual_studio + editables: + HelloB/0.1@lasote/stable: + path: B + generators: [make, qmake] + HelloC/0.1@lasote/stable: + path: C + HelloA/0.1@lasote/stable: + path: A + generators: visual_studio layout: layout generators: cmake - generator: cmake + workspace_generator: cmake root: HelloA/0.1@lasote/stable """) layout = dedent(""" From 8b75efff78306fee44a4ce1180718dd6dd9f1f79 Mon Sep 17 00:00:00 2001 From: memsharded Date: Thu, 21 Feb 2019 11:30:18 +0100 Subject: [PATCH 25/41] fix tests --- .../unittests/model/editable_cpp_info/apply_test.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/conans/test/unittests/model/editable_cpp_info/apply_test.py b/conans/test/unittests/model/editable_cpp_info/apply_test.py index 6c38256b4bb..011c2932b0c 100644 --- a/conans/test/unittests/model/editable_cpp_info/apply_test.py +++ b/conans/test/unittests/model/editable_cpp_info/apply_test.py @@ -48,8 +48,8 @@ def test_require_no_namespace(self): self.assertListEqual(cpp_info.includedirs, ['dirs/includedirs']) self.assertListEqual(cpp_info.libdirs, ['dirs/libdirs']) self.assertListEqual(cpp_info.resdirs, ['dirs/resdirs']) - # The default defined by package_info() is removed - self.assertListEqual(cpp_info.bindirs, []) + # The default defined by package_info() is respected + self.assertListEqual(cpp_info.bindirs, ["bin"]) def test_require_namespace(self): content = '\n\n'.join([ @@ -63,8 +63,8 @@ def test_require_namespace(self): self.assertListEqual(cpp_info.includedirs, ['libA/dirs/includedirs']) self.assertListEqual(cpp_info.libdirs, ['libA/dirs/libdirs']) self.assertListEqual(cpp_info.resdirs, ['libA/dirs/resdirs']) - # The default defined by package_info() is removed - self.assertListEqual(cpp_info.bindirs, []) + # The default defined by package_info() is respected + self.assertListEqual(cpp_info.bindirs, ['bin']) cpp_info = CppInfo(None) other = ConanFileReference.loads("other/0.1@user/channel") @@ -72,5 +72,5 @@ def test_require_namespace(self): self.assertListEqual(cpp_info.includedirs, ['dirs/includedirs']) self.assertListEqual(cpp_info.libdirs, ['dirs/libdirs']) self.assertListEqual(cpp_info.resdirs, ['dirs/resdirs']) - # The default defined by package_info() is removed - self.assertListEqual(cpp_info.bindirs, []) + # The default defined by package_info() is respected + self.assertListEqual(cpp_info.bindirs, ['bin']) From 0529a36fae5acd29d375c7e9696d8793bf8eec4a Mon Sep 17 00:00:00 2001 From: memsharded Date: Fri, 22 Feb 2019 11:21:11 +0100 Subject: [PATCH 26/41] configuration print of workspaces --- conans/client/conan_api.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/conans/client/conan_api.py b/conans/client/conan_api.py index 0200a510c55..a9ba7874370 100644 --- a/conans/client/conan_api.py +++ b/conans/client/conan_api.py @@ -473,6 +473,9 @@ def workspace_install(self, path, settings=None, options=None, env=None, graph_info = get_graph_info(profile_name, settings, options, env, cwd, None, self._cache, self._user_io.out) + self._user_io.out.info("Configuration:") + self._user_io.out.writeln(graph_info.profile.dumps()) + self._cache.editable_packages.override(workspace.get_editable_dict()) recorder = ActionRecorder() From 0a4b5d6712db8e908a5c556c18057f70b1c7b5f2 Mon Sep 17 00:00:00 2001 From: "Javier G. Sogo" Date: Fri, 22 Feb 2019 16:49:53 +0100 Subject: [PATCH 27/41] add jinja for layout file parsing --- conans/model/editable_cpp_info.py | 78 ++++++++++--------- .../package_editable_layout.py | 2 +- conans/requirements.txt | 1 + .../consume_settings_and_options_test.py | 6 +- .../test/functional/editable/layouts_test.py | 7 +- .../model/editable_cpp_info/apply_test.py | 9 +-- .../model/editable_cpp_info/load_data_test.py | 54 +++++++++++++ .../model/editable_cpp_info/parse_test.py | 49 +++++------- .../editable_cpp_info/work_on_items_test.py | 36 --------- conans/util/jinja.py | 11 +++ 10 files changed, 138 insertions(+), 115 deletions(-) create mode 100644 conans/test/unittests/model/editable_cpp_info/load_data_test.py delete mode 100644 conans/test/unittests/model/editable_cpp_info/work_on_items_test.py create mode 100644 conans/util/jinja.py diff --git a/conans/model/editable_cpp_info.py b/conans/model/editable_cpp_info.py index 948ef621082..2412c369cd2 100644 --- a/conans/model/editable_cpp_info.py +++ b/conans/model/editable_cpp_info.py @@ -1,8 +1,11 @@ # coding=utf-8 import os from collections import OrderedDict - +import tempfile +from io import StringIO from six.moves import configparser +from conans.util.files import load +from conans.util.jinja import render_layout_file from conans.errors import ConanException from conans.model.ref import ConanFileReference @@ -14,69 +17,68 @@ def get_editable_abs_path(path, cwd, cache_folder): # Check the layout file exists, is correct, and get its abs-path if path: - layout_abs_path = path if os.path.isabs(path) else os.path.normpath(os.path.join(cwd, path)) + layout_abs_path = os.path.normpath(os.path.join(cwd, path)) if not os.path.isfile(layout_abs_path): layout_abs_path = os.path.join(cache_folder, LAYOUTS_FOLDER, path) if not os.path.isfile(layout_abs_path): raise ConanException("Couldn't find layout file: %s" % path) - EditableCppInfo.load(layout_abs_path) # Try if it loads ok return layout_abs_path # Default only in cache - layout_abs_path = os.path.join(cache_folder, LAYOUTS_FOLDER, DEFAULT_LAYOUT_FILE) - if os.path.isfile(layout_abs_path): - EditableCppInfo.load(layout_abs_path) - return layout_abs_path + layout_default_path = os.path.join(cache_folder, LAYOUTS_FOLDER, DEFAULT_LAYOUT_FILE) + if os.path.isfile(layout_default_path): + return layout_default_path class EditableCppInfo(object): cpp_info_dirs = ['includedirs', 'libdirs', 'resdirs', 'bindirs', 'builddirs', 'srcdirs'] - def __init__(self, data): - self._data = data + def __init__(self, filepath): + self._filepath = filepath - @staticmethod - def load(filepath): - parser = configparser.ConfigParser(allow_no_value=True) - parser.optionxform = str + def _parse_layout_file(self, ref, settings, options): + content = load(self._filepath) try: - parser.read(filepath) - except configparser.Error as e: - raise ConanException("Error parsing layout file: %s\n%s" % (filepath, str(e))) + content = render_layout_file(content, ref=ref, settings=settings, options=options) + + parser = configparser.ConfigParser(allow_no_value=True) + parser.optionxform = str + parser.readfp(StringIO(content)) + except (configparser.Error, ConanException) as e: + raise ConanException("Error parsing layout file '%s' (for reference '%s')\n%s" % + (self._filepath, str(ref), str(e))) + + return parser + + def _load_data(self, ref, settings, options): + parser = self._parse_layout_file(ref, settings, options) + + # Build a convenient data structure data = OrderedDict() for section in parser.sections(): - ref, cpp_info_dir = section.rsplit(":", 1) if ':' in section else (None, section) + reference, cpp_info_dir = section.rsplit(":", 1) if ':' in section else (None, section) if cpp_info_dir not in EditableCppInfo.cpp_info_dirs: raise ConanException("Wrong cpp_info field '%s' in layout file: %s" - % (cpp_info_dir, filepath)) - if ref: + % (cpp_info_dir, self._filepath)) + if reference: try: - r = ConanFileReference.loads(ref) + r = ConanFileReference.loads(reference) if r.revision: raise ConanException except ConanException: raise ConanException("Wrong package reference '%s' in layout file: %s" - % (ref, filepath)) - data.setdefault(ref, {})[cpp_info_dir] = [k for k, _ in parser.items(section)] - - return EditableCppInfo(data) - - @staticmethod - def _work_on_item(value, settings, options): - value = value.format(settings=settings, options=options) - value = value.replace('\\', '/') - return value + % (reference, self._filepath)) + data.setdefault(reference, {})[cpp_info_dir] = [k for k, _ in parser.items(section)] + return data def apply_to(self, ref, cpp_info, settings=None, options=None): - d = self._data - data = d.get(str(ref)) or d.get(None) or {} + data = self._load_data(ref, settings=settings, options=options) + + # Apply the data to the cpp_info + data = data.get(str(ref)) or data.get(None) or {} if data: # Invalidate previously existing dirs for info_dir in self.cpp_info_dirs: setattr(cpp_info, info_dir, []) - try: - for key, items in data.items(): - setattr(cpp_info, key, [self._work_on_item(item, settings, options) - for item in items]) - except Exception as e: - raise ConanException("Error applying layout in '%s': %s" % (str(ref), str(e))) + for key, items in data.items(): + setattr(cpp_info, key, items) diff --git a/conans/paths/package_layouts/package_editable_layout.py b/conans/paths/package_layouts/package_editable_layout.py index 3ca70b1d914..519aacf8071 100644 --- a/conans/paths/package_layouts/package_editable_layout.py +++ b/conans/paths/package_layouts/package_editable_layout.py @@ -30,7 +30,7 @@ def conanfile(self): def editable_cpp_info(self): if self._layout_file: if os.path.isfile(self._layout_file): - return EditableCppInfo.load(self._layout_file) + return EditableCppInfo(self._layout_file) else: raise ConanException("Layout file not found: %s" % self._layout_file) diff --git a/conans/requirements.txt b/conans/requirements.txt index d787cd05cee..b5c3e9e02ea 100644 --- a/conans/requirements.txt +++ b/conans/requirements.txt @@ -13,3 +13,4 @@ pygments>=2.0, <3.0 astroid>=1.6.5 deprecation>=2.0, <2.1 tqdm>=4.28.1, <5 +Jinja2==2.10 diff --git a/conans/test/functional/editable/consume_settings_and_options_test.py b/conans/test/functional/editable/consume_settings_and_options_test.py index c7f9b0c1534..58dd878646c 100644 --- a/conans/test/functional/editable/consume_settings_and_options_test.py +++ b/conans/test/functional/editable/consume_settings_and_options_test.py @@ -48,7 +48,7 @@ def package_info(self): """ conan_package_layout = """ -[{namespace}includedirs] +[%sincludedirs] src/include/{{settings.build_type}}/{{options.shared}} """ @@ -67,11 +67,11 @@ def __init__(self, use_repo_file, *args, **kwargs): } if use_repo_file: - files["mylayout"] = self.conan_package_layout.format(namespace="") + files["mylayout"] = self.conan_package_layout % "" else: file_path = os.path.join(self.cache.conan_folder, LAYOUTS_FOLDER, DEFAULT_LAYOUT_FILE) save(file_path, - self.conan_package_layout.format(namespace="MyLib/0.1@user/editable:")) + self.conan_package_layout % "MyLib/0.1@user/editable:") self.save(files) diff --git a/conans/test/functional/editable/layouts_test.py b/conans/test/functional/editable/layouts_test.py index 8bb42d71cdd..2a60d73a672 100644 --- a/conans/test/functional/editable/layouts_test.py +++ b/conans/test/functional/editable/layouts_test.py @@ -166,7 +166,7 @@ class Pkg(ConanFile): """) layout_repo = textwrap.dedent(""" [includedirs] - include_{settings.build_type} + include_{{settings.build_type}} """) client.save({"conanfile.py": conanfile, @@ -179,8 +179,9 @@ class Pkg(ConanFile): """) client2.save({"conanfile.txt": consumer}) client2.run("install . -g cmake -s build_type=Debug", assert_error=True) - self.assertIn("ERROR: Error applying layout in 'mytool/0.1@user/testing': " - "'settings.build_type' doesn't exist", client2.out) + self.assertIn("ERROR: Error parsing layout file '{}' (for reference " + "'mytool/0.1@user/testing')\n'settings.build_type' doesn't exist".format( + os.path.join(client.current_folder, 'layout')), client2.out) # Now add settings to conanfile client.save({"conanfile.py": conanfile.replace("pass", 'settings = "build_type"')}) diff --git a/conans/test/unittests/model/editable_cpp_info/apply_test.py b/conans/test/unittests/model/editable_cpp_info/apply_test.py index 387fdc39d44..d3a766526ab 100644 --- a/conans/test/unittests/model/editable_cpp_info/apply_test.py +++ b/conans/test/unittests/model/editable_cpp_info/apply_test.py @@ -35,6 +35,7 @@ def setUp(self): self.test_folder = temp_folder() self.layout_filepath = os.path.join(self.test_folder, "layout") self.ref = ConanFileReference.loads("libA/0.1@user/channel") + self.editable_cpp_info = EditableCppInfo(self.layout_filepath) def tearDown(self): shutil.rmtree(self.test_folder) @@ -42,9 +43,8 @@ def tearDown(self): def test_require_no_namespace(self): content = base_content.format(namespace="", path_prefix="") save(self.layout_filepath, content) - editable_cpp_info = EditableCppInfo.load(self.layout_filepath) cpp_info = CppInfo(None) - editable_cpp_info.apply_to(self.ref, cpp_info, settings=None, options=None) + self.editable_cpp_info.apply_to(self.ref, cpp_info, settings=None, options=None) self.assertListEqual(cpp_info.includedirs, ['dirs/includedirs']) self.assertListEqual(cpp_info.libdirs, ['dirs/libdirs']) self.assertListEqual(cpp_info.resdirs, ['dirs/resdirs']) @@ -57,9 +57,8 @@ def test_require_namespace(self): base_content.format(namespace="libA/0.1@user/channel:", path_prefix="libA/") ]) save(self.layout_filepath, content) - editable_cpp_info = EditableCppInfo.load(self.layout_filepath) cpp_info = CppInfo(None) - editable_cpp_info.apply_to(self.ref, cpp_info, settings=None, options=None) + self.editable_cpp_info.apply_to(self.ref, cpp_info, settings=None, options=None) self.assertListEqual(cpp_info.includedirs, ['libA/dirs/includedirs']) self.assertListEqual(cpp_info.libdirs, ['libA/dirs/libdirs']) self.assertListEqual(cpp_info.resdirs, ['libA/dirs/resdirs']) @@ -68,7 +67,7 @@ def test_require_namespace(self): cpp_info = CppInfo(None) other = ConanFileReference.loads("other/0.1@user/channel") - editable_cpp_info.apply_to(other, cpp_info, settings=None, options=None) + self.editable_cpp_info.apply_to(other, cpp_info, settings=None, options=None) self.assertListEqual(cpp_info.includedirs, ['dirs/includedirs']) self.assertListEqual(cpp_info.libdirs, ['dirs/libdirs']) self.assertListEqual(cpp_info.resdirs, ['dirs/resdirs']) diff --git a/conans/test/unittests/model/editable_cpp_info/load_data_test.py b/conans/test/unittests/model/editable_cpp_info/load_data_test.py new file mode 100644 index 00000000000..d01e744c9f8 --- /dev/null +++ b/conans/test/unittests/model/editable_cpp_info/load_data_test.py @@ -0,0 +1,54 @@ +# coding=utf-8 + +import textwrap +import os +import shutil +import unittest + +from conans.errors import ConanException +from conans.model.editable_cpp_info import EditableCppInfo +from conans.test.utils.test_files import temp_folder +from conans.util.files import save + + +class ParseTest(unittest.TestCase): + def setUp(self): + self.test_folder = temp_folder() + self.layout_filepath = os.path.join(self.test_folder, "layout") + self.editable_cpp_info = EditableCppInfo(self.layout_filepath) + + def tearDown(self): + shutil.rmtree(self.test_folder) + + def test_field_error(self): + content = textwrap.dedent(""" + [includedrs] + something + """) + save(self.layout_filepath, content) + with self.assertRaisesRegexp(ConanException, "Wrong cpp_info field 'includedrs' in layout"): + _ = self.editable_cpp_info._load_data(ref=None, settings=None, options=None) + content = textwrap.dedent(""" + [*:includedrs] + something + """) + save(self.layout_filepath, content) + with self.assertRaisesRegexp(ConanException, "Wrong cpp_info field 'includedrs' in layout"): + _ = self.editable_cpp_info._load_data(ref=None, settings=None, options=None) + + content = textwrap.dedent(""" + [*:includedirs] + something + """) + save(self.layout_filepath, content) + with self.assertRaisesRegexp(ConanException, "Wrong package reference '\*' in layout file"): + _ = self.editable_cpp_info._load_data(ref=None, settings=None, options=None) + + content = textwrap.dedent(""" + [pkg/version@user/channel:revision:includedirs] + something + """) + save(self.layout_filepath, content) + with self.assertRaisesRegexp(ConanException, "Wrong package reference " + "'pkg/version@user/channel:revision' in layout file"): + _ = self.editable_cpp_info._load_data(ref=None, settings=None, options=None) diff --git a/conans/test/unittests/model/editable_cpp_info/parse_test.py b/conans/test/unittests/model/editable_cpp_info/parse_test.py index cad0b75be42..4601658db9c 100644 --- a/conans/test/unittests/model/editable_cpp_info/parse_test.py +++ b/conans/test/unittests/model/editable_cpp_info/parse_test.py @@ -9,45 +9,36 @@ from conans.model.editable_cpp_info import EditableCppInfo from conans.test.utils.test_files import temp_folder from conans.util.files import save - +from conans.client.conf import default_settings_yml +from conans.model.settings import Settings +from conans.model.options import Options, OptionsValues, PackageOptions class ParseTest(unittest.TestCase): def setUp(self): self.test_folder = temp_folder() self.layout_filepath = os.path.join(self.test_folder, "layout") + self.editable_cpp_info = EditableCppInfo(self.layout_filepath) + + self.settings = Settings.loads(default_settings_yml) + self.options = Options(PackageOptions({"shared": [True, False]})) def tearDown(self): shutil.rmtree(self.test_folder) - def field_error_test(self): - content = textwrap.dedent(""" - [includedrs] - something - """) - save(self.layout_filepath, content) - with self.assertRaisesRegexp(ConanException, "Wrong cpp_info field 'includedrs' in layout"): - _ = EditableCppInfo.load(self.layout_filepath) - content = textwrap.dedent(""" - [*:includedrs] - something - """) - save(self.layout_filepath, content) - with self.assertRaisesRegexp(ConanException, "Wrong cpp_info field 'includedrs' in layout"): - _ = EditableCppInfo.load(self.layout_filepath) + def test_jinja_render(self): + self.options.shared = True + self.settings.build_type = "Debug" content = textwrap.dedent(""" - [*:includedirs] - something - """) + [includedirs] + {% if options.shared %} + path/to/shared/{{ settings.build_type }} + {% else %} + not/expected + {% endif %} + """) save(self.layout_filepath, content) - with self.assertRaisesRegexp(ConanException, "Wrong package reference '\*' in layout file"): - _ = EditableCppInfo.load(self.layout_filepath) - content = textwrap.dedent(""" - [pkg/version@user/channel:revision:includedirs] - something - """) - save(self.layout_filepath, content) - with self.assertRaisesRegexp(ConanException, "Wrong package reference " - "'pkg/version@user/channel:revision' in layout file"): - _ = EditableCppInfo.load(self.layout_filepath) + data = self.editable_cpp_info._load_data(ref=None, settings=self.settings, + options=self.options) + self.assertEqual(data[None], {'includedirs': ["path/to/shared/Debug"]}) diff --git a/conans/test/unittests/model/editable_cpp_info/work_on_items_test.py b/conans/test/unittests/model/editable_cpp_info/work_on_items_test.py deleted file mode 100644 index dbe1dc3e557..00000000000 --- a/conans/test/unittests/model/editable_cpp_info/work_on_items_test.py +++ /dev/null @@ -1,36 +0,0 @@ -# coding=utf-8 - -import unittest - -from conans.client.conf import default_settings_yml -from conans.model.editable_cpp_info import EditableCppInfo -from conans.model.settings import Settings - - -class WorkOnItemsTest(unittest.TestCase): - - def test_empty(self): - self.assertEqual("", EditableCppInfo._work_on_item("", None, None)) - - def test_placeholders(self): - settings = Settings.loads(default_settings_yml) - settings.compiler = 'Visual Studio' - settings.compiler.version = '14' - settings.build_type = 'Debug' - - self.assertEqual('src/Visual Studio14/Debug/include', - EditableCppInfo._work_on_item("src/{settings.compiler}{settings.compiler.version}/{settings.build_type}/include", - settings=settings, - options=None)) - self.assertEqual('C:/Visual Studio/include/', - EditableCppInfo._work_on_item("C:\\{settings.compiler}\\include\\", - settings=settings, - options=None)) - self.assertEqual('C:/Visual Studio/include/', - EditableCppInfo._work_on_item("C:\{settings.compiler}\include\\", - settings=settings, - options=None)) - self.assertEqual('/usr/path with spaces/Visual Studio/dir', - EditableCppInfo._work_on_item("/usr/path with spaces/{settings.compiler}/dir", - settings=settings, - options=None)) diff --git a/conans/util/jinja.py b/conans/util/jinja.py new file mode 100644 index 00000000000..a6fc252b1c6 --- /dev/null +++ b/conans/util/jinja.py @@ -0,0 +1,11 @@ +# coding=utf-8 + +from jinja2 import Template +from conans.errors import ConanException + + +def render_layout_file(content, ref=None, settings=None, options=None): + t = Template(content) + #settings = {k: v for k, v in settings.values_list} if settings else None + #options = {k: v for k, v in options.values.as_list()} if options else None + return t.render(reference=str(ref), settings=settings, options=options) From ebf014f642b2dfb603433b41afd91232edf75024 Mon Sep 17 00:00:00 2001 From: "Javier G. Sogo" Date: Fri, 22 Feb 2019 16:51:50 +0100 Subject: [PATCH 28/41] reorder imports --- conans/model/editable_cpp_info.py | 6 +++--- .../functional/editable/consume_header_only_test.py | 5 ++--- .../editable/consume_settings_and_options_test.py | 3 ++- conans/test/functional/editable/layouts_test.py | 4 ++-- .../unittests/model/editable_cpp_info/apply_test.py | 5 ++--- .../model/editable_cpp_info/load_data_test.py | 2 +- .../unittests/model/editable_cpp_info/parse_test.py | 10 +++++----- conans/util/{jinja.py => templates.py} | 3 --- 8 files changed, 17 insertions(+), 21 deletions(-) rename conans/util/{jinja.py => templates.py} (52%) diff --git a/conans/model/editable_cpp_info.py b/conans/model/editable_cpp_info.py index 2412c369cd2..67c629643b0 100644 --- a/conans/model/editable_cpp_info.py +++ b/conans/model/editable_cpp_info.py @@ -1,14 +1,14 @@ # coding=utf-8 import os from collections import OrderedDict -import tempfile from io import StringIO + from six.moves import configparser -from conans.util.files import load -from conans.util.jinja import render_layout_file from conans.errors import ConanException from conans.model.ref import ConanFileReference +from conans.util.files import load +from conans.util.templates import render_layout_file DEFAULT_LAYOUT_FILE = "default" LAYOUTS_FOLDER = 'layouts' diff --git a/conans/test/functional/editable/consume_header_only_test.py b/conans/test/functional/editable/consume_header_only_test.py index c68403b8de1..881a4c6a1fa 100644 --- a/conans/test/functional/editable/consume_header_only_test.py +++ b/conans/test/functional/editable/consume_header_only_test.py @@ -2,16 +2,15 @@ import os import tempfile -import unittest import textwrap +import unittest from parameterized import parameterized - +from conans.model.editable_cpp_info import DEFAULT_LAYOUT_FILE, LAYOUTS_FOLDER from conans.test import CONAN_TEST_FOLDER from conans.test.utils.tools import TestClient from conans.util.files import save -from conans.model.editable_cpp_info import DEFAULT_LAYOUT_FILE, LAYOUTS_FOLDER class HeaderOnlyLibTestClient(TestClient): diff --git a/conans/test/functional/editable/consume_settings_and_options_test.py b/conans/test/functional/editable/consume_settings_and_options_test.py index 58dd878646c..0d0125c9b0b 100644 --- a/conans/test/functional/editable/consume_settings_and_options_test.py +++ b/conans/test/functional/editable/consume_settings_and_options_test.py @@ -4,12 +4,13 @@ import os import tempfile import unittest + from parameterized import parameterized +from conans.model.editable_cpp_info import DEFAULT_LAYOUT_FILE, LAYOUTS_FOLDER from conans.test import CONAN_TEST_FOLDER from conans.test.utils.tools import TestClient from conans.util.files import save -from conans.model.editable_cpp_info import DEFAULT_LAYOUT_FILE, LAYOUTS_FOLDER class HeaderOnlyLibTestClient(TestClient): diff --git a/conans/test/functional/editable/layouts_test.py b/conans/test/functional/editable/layouts_test.py index 2a60d73a672..4a515aad307 100644 --- a/conans/test/functional/editable/layouts_test.py +++ b/conans/test/functional/editable/layouts_test.py @@ -5,10 +5,10 @@ import textwrap import unittest -from conans.test.utils.tools import TestClient -from conans.util.files import load, save_files, save from conans.model.editable_cpp_info import LAYOUTS_FOLDER from conans.test.utils.test_files import temp_folder +from conans.test.utils.tools import TestClient +from conans.util.files import load, save_files, save class LayoutTest(unittest.TestCase): diff --git a/conans/test/unittests/model/editable_cpp_info/apply_test.py b/conans/test/unittests/model/editable_cpp_info/apply_test.py index d3a766526ab..9d06a27188e 100644 --- a/conans/test/unittests/model/editable_cpp_info/apply_test.py +++ b/conans/test/unittests/model/editable_cpp_info/apply_test.py @@ -6,12 +6,11 @@ import textwrap import unittest -from conans.model.editable_cpp_info import EditableCppInfo from conans.model.build_info import CppInfo +from conans.model.editable_cpp_info import EditableCppInfo +from conans.model.ref import ConanFileReference from conans.test.utils.test_files import temp_folder from conans.util.files import save -from conans.model.ref import ConanFileReference - base_content = textwrap.dedent("""\ [{namespace}includedirs] diff --git a/conans/test/unittests/model/editable_cpp_info/load_data_test.py b/conans/test/unittests/model/editable_cpp_info/load_data_test.py index d01e744c9f8..47edf8e9aca 100644 --- a/conans/test/unittests/model/editable_cpp_info/load_data_test.py +++ b/conans/test/unittests/model/editable_cpp_info/load_data_test.py @@ -1,8 +1,8 @@ # coding=utf-8 -import textwrap import os import shutil +import textwrap import unittest from conans.errors import ConanException diff --git a/conans/test/unittests/model/editable_cpp_info/parse_test.py b/conans/test/unittests/model/editable_cpp_info/parse_test.py index 4601658db9c..a2c30dba8a7 100644 --- a/conans/test/unittests/model/editable_cpp_info/parse_test.py +++ b/conans/test/unittests/model/editable_cpp_info/parse_test.py @@ -1,17 +1,17 @@ # coding=utf-8 -import textwrap import os import shutil +import textwrap import unittest -from conans.errors import ConanException +from conans.client.conf import default_settings_yml from conans.model.editable_cpp_info import EditableCppInfo +from conans.model.options import Options, PackageOptions +from conans.model.settings import Settings from conans.test.utils.test_files import temp_folder from conans.util.files import save -from conans.client.conf import default_settings_yml -from conans.model.settings import Settings -from conans.model.options import Options, OptionsValues, PackageOptions + class ParseTest(unittest.TestCase): def setUp(self): diff --git a/conans/util/jinja.py b/conans/util/templates.py similarity index 52% rename from conans/util/jinja.py rename to conans/util/templates.py index a6fc252b1c6..ec8b3875a15 100644 --- a/conans/util/jinja.py +++ b/conans/util/templates.py @@ -1,11 +1,8 @@ # coding=utf-8 from jinja2 import Template -from conans.errors import ConanException def render_layout_file(content, ref=None, settings=None, options=None): t = Template(content) - #settings = {k: v for k, v in settings.values_list} if settings else None - #options = {k: v for k, v in options.values.as_list()} if options else None return t.render(reference=str(ref), settings=settings, options=options) From 2656bfdbc1d687a78158fe1e74b82117056f88b6 Mon Sep 17 00:00:00 2001 From: memsharded Date: Fri, 22 Feb 2019 19:44:43 +0100 Subject: [PATCH 29/41] arg.path name changed --- conans/client/command.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/conans/client/command.py b/conans/client/command.py index 5a546d762e9..56c640f9d93 100644 --- a/conans/client/command.py +++ b/conans/client/command.py @@ -1432,7 +1432,7 @@ def editable(self, *args): subparsers = parser.add_subparsers(dest='subcommand', help='sub-command help') add_parser = subparsers.add_parser('add', help='Put a package in editable mode') - add_parser.add_argument('target', help='Path to the package folder in the user workspace') + add_parser.add_argument('path', help='Path to the package folder in the user workspace') add_parser.add_argument('reference', help='Package reference e.g.: mylib/1.X@user/channel') add_parser.add_argument("-l", "--layout", help='Relative or absolute path to a file containing the layout.' @@ -1449,9 +1449,9 @@ def editable(self, *args): self._warn_python2() if args.subcommand == "add": - self._conan.editable_add(args.target, args.reference, args.layout, cwd=os.getcwd()) + self._conan.editable_add(args.path, args.reference, args.layout, cwd=os.getcwd()) self._outputer.writeln("Reference '{}' linked to directory " - "'{}'".format(args.reference, os.path.dirname(args.target))) + "'{}'".format(args.reference, os.path.dirname(args.path))) elif args.subcommand == "remove": ret = self._conan.editable_remove(args.reference) if ret: From 5d1377adebda2f6c1db7062fe4e08af41317465e Mon Sep 17 00:00:00 2001 From: memsharded Date: Fri, 22 Feb 2019 20:26:14 +0100 Subject: [PATCH 30/41] fixed tests --- conans/client/build/cmake.py | 6 +++--- conans/test/integration/workspace_test.py | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/conans/client/build/cmake.py b/conans/client/build/cmake.py index b9dc3c6e8c7..9c41dbbdb8e 100644 --- a/conans/client/build/cmake.py +++ b/conans/client/build/cmake.py @@ -14,7 +14,6 @@ from conans.client.tools.oss import cpu_count, args_to_string from conans.util.config_parser import get_bool_from_text from conans.util.files import mkdir, get_abs_path, walk, decode_text -from conans.util.env_reader import get_env class CMake(object): @@ -31,8 +30,9 @@ def __init__(self, conanfile, generator=None, cmake_system_name=True, :param build_type: Overrides default build type coming from settings :param toolset: Toolset name to use (such as llvm-vs2014) or none for default one, applies only to certain generators (e.g. Visual Studio) - :param set_cmake_flags: whether or not to set CMake flags like CMAKE_CXX_FLAGS, CMAKE_C_FLAGS, etc. - it's vital to set for certain projects (e.g. using CMAKE_SIZEOF_VOID_P or CMAKE_LIBRARY_ARCHITECTURE) + :param set_cmake_flags: whether or not to set CMake flags like CMAKE_CXX_FLAGS, + CMAKE_C_FLAGS, etc. it's vital to set for certain projects + (e.g. using CMAKE_SIZEOF_VOID_P or CMAKE_LIBRARY_ARCHITECTURE) :param msbuild_verbosity: verbosity level for MSBuild (in case of Visual Studio generator) :param cmake_program: Path to the custom cmake executable """ diff --git a/conans/test/integration/workspace_test.py b/conans/test/integration/workspace_test.py index 92008f2a7fb..e8fec573e2c 100644 --- a/conans/test/integration/workspace_test.py +++ b/conans/test/integration/workspace_test.py @@ -259,6 +259,7 @@ def files(name, depend=None): client.run("workspace install ../conanws.yml") with client.chdir("build_debug"): client.run("workspace install ../conanws.yml -s build_type=Debug") + client.init_dynamic_vars() generator = "Visual Studio 15 Win64" if platform.system() == "Windows" else "Unix Makefiles" client.runner('cmake .. -G "%s" -DCMAKE_BUILD_TYPE=Release' % generator, cwd=base_release) @@ -375,6 +376,7 @@ def files(name, depend=None): client.run("workspace install ../conanws.yml") client.run("workspace install ../conanws.yml -s build_type=Debug") + client.init_dynamic_vars() generator = "Visual Studio 15 Win64" client.runner('cmake .. -G "%s" -DCMAKE_BUILD_TYPE=Release' % generator, cwd=build) client.runner('cmake --build . --config Release', cwd=build) From 957a5186e5d212d222ee21febb47e53f328bee2d Mon Sep 17 00:00:00 2001 From: "Javier G. Sogo" Date: Mon, 25 Feb 2019 10:27:04 +0100 Subject: [PATCH 31/41] validate reference, it is read from user input --- conans/model/editable_cpp_info.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conans/model/editable_cpp_info.py b/conans/model/editable_cpp_info.py index 67c629643b0..4db17f01249 100644 --- a/conans/model/editable_cpp_info.py +++ b/conans/model/editable_cpp_info.py @@ -62,7 +62,7 @@ def _load_data(self, ref, settings, options): % (cpp_info_dir, self._filepath)) if reference: try: - r = ConanFileReference.loads(reference) + r = ConanFileReference.loads(reference, validate=True) if r.revision: raise ConanException except ConanException: From c0668e8ba026e52366881e616d6d09f144298329 Mon Sep 17 00:00:00 2001 From: "Javier G. Sogo" Date: Mon, 25 Feb 2019 10:55:06 +0100 Subject: [PATCH 32/41] parse tests --- conans/model/editable_cpp_info.py | 2 +- conans/test/unittests/model/editable_cpp_info/parse_test.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/conans/model/editable_cpp_info.py b/conans/model/editable_cpp_info.py index bfbe95a77a4..a98e6bdeaa5 100644 --- a/conans/model/editable_cpp_info.py +++ b/conans/model/editable_cpp_info.py @@ -82,7 +82,7 @@ def _load_data(self, ref, settings, options): % (section_name, self._filepath)) if reference: try: - r = ConanFileReference.loads(ref, validate=True) + r = ConanFileReference.loads(reference, validate=True) if r.revision: raise ConanException("Don't provide revision in Editable layouts") except ConanException: diff --git a/conans/test/unittests/model/editable_cpp_info/parse_test.py b/conans/test/unittests/model/editable_cpp_info/parse_test.py index f2d72849389..d80e92a1343 100644 --- a/conans/test/unittests/model/editable_cpp_info/parse_test.py +++ b/conans/test/unittests/model/editable_cpp_info/parse_test.py @@ -6,12 +6,12 @@ import unittest from conans.client.conf import default_settings_yml +from conans.errors import ConanException from conans.model.editable_cpp_info import EditableLayout from conans.model.options import Options, PackageOptions from conans.model.settings import Settings from conans.test.utils.test_files import temp_folder from conans.util.files import save -from conans.errors import ConanException class ParseTest(unittest.TestCase): @@ -40,8 +40,8 @@ def test_jinja_render(self): """) save(self.layout_filepath, content) - data = self.editable_cpp_info._load_data(ref=None, settings=self.settings, - options=self.options) + data, folders = self.editable_cpp_info._load_data(ref=None, settings=self.settings, + options=self.options) self.assertEqual(data[None], {'includedirs': ["path/to/shared/Debug"]}) def test_wrong_field(self): From 556453fafe907d3b78f3b704d0319d8108f7402d Mon Sep 17 00:00:00 2001 From: "Javier G. Sogo" Date: Mon, 25 Feb 2019 10:56:21 +0100 Subject: [PATCH 33/41] load_data_tests contains the tests for wrong fields --- .../model/editable_cpp_info/load_data_test.py | 4 ++-- .../model/editable_cpp_info/parse_test.py | 22 ------------------- 2 files changed, 2 insertions(+), 24 deletions(-) diff --git a/conans/test/unittests/model/editable_cpp_info/load_data_test.py b/conans/test/unittests/model/editable_cpp_info/load_data_test.py index 47edf8e9aca..55e1daa3db4 100644 --- a/conans/test/unittests/model/editable_cpp_info/load_data_test.py +++ b/conans/test/unittests/model/editable_cpp_info/load_data_test.py @@ -6,7 +6,7 @@ import unittest from conans.errors import ConanException -from conans.model.editable_cpp_info import EditableCppInfo +from conans.model.editable_cpp_info import EditableLayout from conans.test.utils.test_files import temp_folder from conans.util.files import save @@ -15,7 +15,7 @@ class ParseTest(unittest.TestCase): def setUp(self): self.test_folder = temp_folder() self.layout_filepath = os.path.join(self.test_folder, "layout") - self.editable_cpp_info = EditableCppInfo(self.layout_filepath) + self.editable_cpp_info = EditableLayout(self.layout_filepath) def tearDown(self): shutil.rmtree(self.test_folder) diff --git a/conans/test/unittests/model/editable_cpp_info/parse_test.py b/conans/test/unittests/model/editable_cpp_info/parse_test.py index d80e92a1343..48a365db6e4 100644 --- a/conans/test/unittests/model/editable_cpp_info/parse_test.py +++ b/conans/test/unittests/model/editable_cpp_info/parse_test.py @@ -43,25 +43,3 @@ def test_jinja_render(self): data, folders = self.editable_cpp_info._load_data(ref=None, settings=self.settings, options=self.options) self.assertEqual(data[None], {'includedirs': ["path/to/shared/Debug"]}) - - def test_wrong_field(self): - content = textwrap.dedent(""" - [*:includedirs] - something - """) - save(self.layout_filepath, content) - with self.assertRaisesRegexp(ConanException, "Wrong package reference '\*' in layout file"): - self.editable_cpp_info._load_data(ref=None, settings=self.settings, - options=self.options) - - def test_wrong_reference(self): - content = textwrap.dedent(""" - [pkg/version@user/channel:revision:includedirs] - something - """) - save(self.layout_filepath, content) - with self.assertRaisesRegexp(ConanException, "Wrong package reference" - " 'pkg/version@user/channel:revision' in layout" - " file"): - self.editable_cpp_info._load_data(ref=None, settings=self.settings, - options=self.options) From 677df0cfd05d96bcab73aa8713a165c035005e92 Mon Sep 17 00:00:00 2001 From: "Javier G. Sogo" Date: Mon, 25 Feb 2019 11:01:11 +0100 Subject: [PATCH 34/41] typo --- conans/model/editable_cpp_info.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conans/model/editable_cpp_info.py b/conans/model/editable_cpp_info.py index a98e6bdeaa5..4741ea42cf1 100644 --- a/conans/model/editable_cpp_info.py +++ b/conans/model/editable_cpp_info.py @@ -88,7 +88,7 @@ def _load_data(self, ref, settings, options): except ConanException: raise ConanException("Wrong package reference '%s' in layout file: %s" % (reference, self._filepath)) - data.setdefault(ref, {})[section_name] = [k for k, _ in parser.items(section)] + data.setdefault(reference, {})[section_name] = [k for k, _ in parser.items(section)] return data, folders def apply_to(self, ref, cpp_info, settings=None, options=None): From 18292d53924aedaaf8ae35442466655f85525213 Mon Sep 17 00:00:00 2001 From: "Javier G. Sogo" Date: Mon, 25 Feb 2019 11:12:42 +0100 Subject: [PATCH 35/41] fix test (jinja2 parsing uses double braces) --- conans/test/integration/workspace_test.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/conans/test/integration/workspace_test.py b/conans/test/integration/workspace_test.py index e8fec573e2c..0aeab02c816 100644 --- a/conans/test/integration/workspace_test.py +++ b/conans/test/integration/workspace_test.py @@ -158,13 +158,13 @@ def files(name, depend=None): """) layout = dedent(""" [build_folder] - build/{settings.build_type} + build/{{settings.build_type}} [includedirs] src [libdirs] - build/{settings.build_type}/lib + build/{{settings.build_type}}/lib """) client.save({"conanws.yml": project, "layout": layout}) @@ -231,7 +231,7 @@ def files(name, depend=None): """) layout = dedent(""" [build_folder] - build/{settings.build_type} + build/{{settings.build_type}} [source_folder] src @@ -240,7 +240,7 @@ def files(name, depend=None): src [libdirs] - build/{settings.build_type}/lib + build/{{settings.build_type}}/lib """) metacmake = dedent(""" @@ -358,7 +358,7 @@ def files(name, depend=None): src [libdirs] - build/{settings.build_type} + build/{{settings.build_type}} """) metacmake = dedent(""" cmake_minimum_required(VERSION 3.3) From 009c7c3dd57f49a7eab9ce26e5a0ae51e13cbff0 Mon Sep 17 00:00:00 2001 From: "Javier G. Sogo" Date: Mon, 25 Feb 2019 11:31:24 +0100 Subject: [PATCH 36/41] work_on_item still needed to fix backslashes --- conans/model/editable_cpp_info.py | 13 ++++++++---- .../model/editable_cpp_info/parse_test.py | 20 +++++++++++++++++-- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/conans/model/editable_cpp_info.py b/conans/model/editable_cpp_info.py index 4741ea42cf1..2029158acca 100644 --- a/conans/model/editable_cpp_info.py +++ b/conans/model/editable_cpp_info.py @@ -41,11 +41,15 @@ def folder(self, ref, name, settings, options): _, folders = self._load_data(ref, settings=settings, options=options) try: path = folders.get(str(ref)) or folders.get(None) or {} - path = path[name] - return path + return path[name] except KeyError: return None + @staticmethod + def _work_on_item(value): + value = value.replace('\\', '/') + return value + def _parse_layout_file(self, ref, settings, options): content = load(self._filepath) try: @@ -74,7 +78,7 @@ def _load_data(self, ref, settings, options): if len(items) > 1: raise ConanException("'%s' with more than one value in layout file: %s" % (section_name, self._filepath)) - folders.setdefault(reference, {})[section_name] = items[0] + folders.setdefault(reference, {})[section_name] = self._work_on_item(items[0]) continue if section_name not in EditableLayout.cpp_info_dirs: @@ -88,7 +92,8 @@ def _load_data(self, ref, settings, options): except ConanException: raise ConanException("Wrong package reference '%s' in layout file: %s" % (reference, self._filepath)) - data.setdefault(reference, {})[section_name] = [k for k, _ in parser.items(section)] + data.setdefault(reference, {})[section_name] =\ + [self._work_on_item(k) for k, _ in parser.items(section)] return data, folders def apply_to(self, ref, cpp_info, settings=None, options=None): diff --git a/conans/test/unittests/model/editable_cpp_info/parse_test.py b/conans/test/unittests/model/editable_cpp_info/parse_test.py index 48a365db6e4..babafb36b94 100644 --- a/conans/test/unittests/model/editable_cpp_info/parse_test.py +++ b/conans/test/unittests/model/editable_cpp_info/parse_test.py @@ -6,7 +6,6 @@ import unittest from conans.client.conf import default_settings_yml -from conans.errors import ConanException from conans.model.editable_cpp_info import EditableLayout from conans.model.options import Options, PackageOptions from conans.model.settings import Settings @@ -26,7 +25,7 @@ def setUp(self): def tearDown(self): shutil.rmtree(self.test_folder) - def test_jinja_render(self): + def test_render_basic(self): self.options.shared = True self.settings.build_type = "Debug" @@ -43,3 +42,20 @@ def test_jinja_render(self): data, folders = self.editable_cpp_info._load_data(ref=None, settings=self.settings, options=self.options) self.assertEqual(data[None], {'includedirs': ["path/to/shared/Debug"]}) + + def test_render_loop(self): + self.settings.build_type = "Debug" + + content = textwrap.dedent(""" + [includedirs] + {% for item in ["cmp1", "cmp2", "cmp3"] %} + components\{{ item }}\include\{% if item != "cmp3" %}{{ settings.build_type }}{% endif %} + {% endfor %} + """) + save(self.layout_filepath, content) + + data, folders = self.editable_cpp_info._load_data(ref=None, settings=self.settings, + options=self.options) + self.assertEqual(data[None], {'includedirs': ["components/cmp1/include/Debug", + "components/cmp2/include/Debug", + "components/cmp3/include/"]}) From 823b73726a6dc604d7138a2526e5f9415e036c8e Mon Sep 17 00:00:00 2001 From: "Javier G. Sogo" Date: Tue, 26 Feb 2019 15:44:52 +0100 Subject: [PATCH 37/41] reorder imports --- conans/test/unittests/model/editable_cpp_info/parse_test.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/conans/test/unittests/model/editable_cpp_info/parse_test.py b/conans/test/unittests/model/editable_cpp_info/parse_test.py index 5c49a68dc8c..babafb36b94 100644 --- a/conans/test/unittests/model/editable_cpp_info/parse_test.py +++ b/conans/test/unittests/model/editable_cpp_info/parse_test.py @@ -9,8 +9,6 @@ from conans.model.editable_cpp_info import EditableLayout from conans.model.options import Options, PackageOptions from conans.model.settings import Settings -from conans.errors import ConanException -from conans.model.editable_cpp_info import EditableLayout from conans.test.utils.test_files import temp_folder from conans.util.files import save From d8ec9c1ad4375aaa4200349b8d96a649035f70fc Mon Sep 17 00:00:00 2001 From: "Javier G. Sogo" Date: Tue, 26 Feb 2019 17:35:23 +0100 Subject: [PATCH 38/41] FileNotFoundError is unknown in py2 --- conans/client/tools/oss.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conans/client/tools/oss.py b/conans/client/tools/oss.py index 7521320b979..e61f7cc2457 100644 --- a/conans/client/tools/oss.py +++ b/conans/client/tools/oss.py @@ -306,7 +306,7 @@ def detect_windows_subsystem(): # https://github.com/Microsoft/WSL/issues/423#issuecomment-221627364 with open("/proc/sys/kernel/osrelease") as f: return WSL if f.read().endswith("Microsoft") else None - except FileNotFoundError: + except IOError: return None try: output = OSInfo.uname() From fe151048650c72a83dac9550f62f32b93437aa06 Mon Sep 17 00:00:00 2001 From: "Javier G. Sogo" Date: Tue, 26 Feb 2019 17:37:36 +0100 Subject: [PATCH 39/41] use six.StringIO --- conans/model/editable_cpp_info.py | 2 +- conans/test/utils/tools.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/conans/model/editable_cpp_info.py b/conans/model/editable_cpp_info.py index 69caabd9313..3164c43f5ef 100644 --- a/conans/model/editable_cpp_info.py +++ b/conans/model/editable_cpp_info.py @@ -1,8 +1,8 @@ # coding=utf-8 import os from collections import OrderedDict -from io import StringIO +from six import StringIO from six.moves import configparser from conans.errors import ConanException diff --git a/conans/test/utils/tools.py b/conans/test/utils/tools.py index 8fcc489c2bb..6e6a957107c 100644 --- a/conans/test/utils/tools.py +++ b/conans/test/utils/tools.py @@ -3,24 +3,24 @@ import os import random import shlex +import shutil import stat import subprocess import sys import tempfile +import threading +import time import unittest +import uuid from collections import Counter, OrderedDict from contextlib import contextmanager -from io import StringIO import bottle import nose import requests -import shutil import six -import threading -import time -import uuid from mock import Mock +from six import StringIO from six.moves.urllib.parse import quote, urlsplit, urlunsplit from webtest.app import TestApp From 1aa5016b8876c9d8c01fd73372754aa1b4495ba0 Mon Sep 17 00:00:00 2001 From: "Javier G. Sogo" Date: Wed, 27 Feb 2019 09:42:50 +0100 Subject: [PATCH 40/41] remove duplicated test --- conans/test/functional/editable/link_create_test.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/conans/test/functional/editable/link_create_test.py b/conans/test/functional/editable/link_create_test.py index e4389cc47f2..9c6b16722d6 100644 --- a/conans/test/functional/editable/link_create_test.py +++ b/conans/test/functional/editable/link_create_test.py @@ -48,19 +48,6 @@ def test_editable_list_search(self): t.run("search") self.assertIn("lib/version@user/name", t.out) - def test_editable_list_search(self): - ref = ConanFileReference.loads('lib/version@user/name') - t = TestClient() - t.save(files={'conanfile.py': self.conanfile}) - t.run('editable add . {}'.format(ref)) - t.run("editable list") - self.assertIn("lib/version@user/name", t.out) - self.assertIn(" Layout: None", t.out) - self.assertIn(" Path:", t.out) - - t.run("search") - self.assertIn("lib/version@user/name", t.out) - def test_install_wrong_reference(self): ref = ConanFileReference.loads('lib/version@user/name') From 80615c2318647d827ecb00552fefc4ece9ce66b3 Mon Sep 17 00:00:00 2001 From: "Javier G. Sogo" Date: Wed, 27 Feb 2019 10:37:00 +0100 Subject: [PATCH 41/41] relax Jinja2 requirement --- conans/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conans/requirements.txt b/conans/requirements.txt index b5c3e9e02ea..0ecd00db009 100644 --- a/conans/requirements.txt +++ b/conans/requirements.txt @@ -13,4 +13,4 @@ pygments>=2.0, <3.0 astroid>=1.6.5 deprecation>=2.0, <2.1 tqdm>=4.28.1, <5 -Jinja2==2.10 +Jinja2>=2.3, <3