From 760cfa80e3fc32dc7800f3afc855302d97f3e6fa Mon Sep 17 00:00:00 2001 From: memsharded Date: Fri, 11 Jan 2019 02:00:15 +0100 Subject: [PATCH 01/34] 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/34] 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/34] 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/34] 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/34] 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/34] 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/34] 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/34] 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/34] 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/34] 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/34] 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/34] 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/34] 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/34] 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/34] 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/34] 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/34] 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/34] 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/34] 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/34] 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/34] 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/34] 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/34] 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/34] 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/34] 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/34] 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 2656bfdbc1d687a78158fe1e74b82117056f88b6 Mon Sep 17 00:00:00 2001 From: memsharded Date: Fri, 22 Feb 2019 19:44:43 +0100 Subject: [PATCH 27/34] 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 28/34] 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 ca11c38f8df75d6230b4cd6e33e956df9c123fb8 Mon Sep 17 00:00:00 2001 From: memsharded Date: Mon, 25 Feb 2019 16:32:14 +0100 Subject: [PATCH 29/34] review! --- conans/client/cache/editable.py | 7 ++--- conans/client/command.py | 26 ++++++++++--------- conans/client/conan_api.py | 6 ++--- conans/client/installer.py | 7 +++-- conans/model/editable_cpp_info.py | 4 ++- conans/model/workspace.py | 14 +++++----- conans/search/search.py | 2 +- .../functional/editable/link_create_test.py | 2 +- .../functional/editable/link_remove_test.py | 2 +- 9 files changed, 37 insertions(+), 33 deletions(-) diff --git a/conans/client/cache/editable.py b/conans/client/cache/editable.py index 7d5ab0c447a..0bf08637ca6 100644 --- a/conans/client/cache/editable.py +++ b/conans/client/cache/editable.py @@ -6,7 +6,7 @@ from conans.util.files import load, save -EDITABLE_PACKAGES_FILE = 'editable_packages' +EDITABLE_PACKAGES_FILE = 'editable_packages.json' class EditablePackages(object): @@ -21,7 +21,8 @@ def __init__(self, cache_folder): else: self._edited_refs = {} # {ref: {"path": path, "layout": layout}} - def refs(self): + @property + def edited_refs(self): return self._edited_refs def save(self): @@ -32,7 +33,7 @@ def get(self, ref): ref = ref.copy_clear_rev() return self._edited_refs.get(ref) - def link(self, ref, path, layout): + def add(self, ref, path, layout): assert isinstance(ref, ConanFileReference) ref = ref.copy_clear_rev() self._edited_refs[ref] = {"path": path, "layout": layout} diff --git a/conans/client/command.py b/conans/client/command.py index 56c640f9d93..cea8cb2ee91 100644 --- a/conans/client/command.py +++ b/conans/client/command.py @@ -392,12 +392,13 @@ def install(self, *args): raise ConanException("A full reference was provided as first argument, second " "argument not allowed") + manifest_interactive = args.manifests_interactive info = self._conan.install_reference(ref, settings=args.settings, options=args.options, env=args.env, remote_name=args.remote, verify=args.verify, manifests=args.manifests, - manifests_interactive=args.manifests_interactive, + manifests_interactive=manifest_interactive, build=args.build, profile_names=args.profile, update=args.update, generators=args.generator, @@ -636,8 +637,8 @@ def build(self, *args): parser.add_argument("-if", "--install-folder", action=OnceArgument, help=_INSTALL_FOLDER_HELP) parser.add_argument("-pf", "--package-folder", action=OnceArgument, - help="Directory to install the package (when the build system or build() " - "method does it). Defaulted to the '{build_folder}/package' folder" + help="Directory to install the package (when the build system or build()" + " method does it). Defaulted to the '{build_folder}/package' folder" ". A relative path can be specified, relative to the current " " folder. Also an absolute path is allowed.") parser.add_argument("-sf", "--source-folder", action=OnceArgument, help=_SOURCE_FOLDER_HELP) @@ -840,7 +841,7 @@ def remove(self, *args): parser.add_argument("-l", "--locks", default=False, action="store_true", help="Remove locks") parser.add_argument("-o", "--outdated", default=False, action="store_true", - help="Remove only outdated from recipe packages. " \ + help="Remove only outdated from recipe packages. " "This flag can only be used with a reference") parser.add_argument('-p', '--packages', nargs="*", action=Extender, help="Select package to remove specifying the package ID") @@ -972,7 +973,8 @@ def user(self, *args): name = args.name password = args.password if not password: - name, password = self._user_io.request_login(remote_name=remote_name, username=name) + name, password = self._user_io.request_login(remote_name=remote_name, + username=name) remote_name, prev_user, user = self._conan.authenticate(name, remote_name=remote_name, password=password) @@ -998,7 +1000,7 @@ def search(self, *args): parser = argparse.ArgumentParser(description=self.search.__doc__, prog="conan search") parser.add_argument('pattern_or_reference', nargs='?', help=_PATTERN_OR_REFERENCE_HELP) parser.add_argument('-o', '--outdated', default=False, action='store_true', - help="Show only outdated from recipe packages. " \ + help="Show only outdated from recipe packages. " "This flag can only be used with a reference") parser.add_argument('-q', '--query', default=None, action=OnceArgument, help=_QUERY_HELP) parser.add_argument('-r', '--remote', action=OnceArgument, @@ -1178,7 +1180,8 @@ def remote(self, *args): # create the parser for the "a" command parser_list = subparsers.add_parser('list', help='List current remotes') parser_list.add_argument("-raw", "--raw", action='store_true', default=False, - help='Raw format. Valid for "remotes.txt" file for "conan config install"') + help='Raw format. Valid for "remotes.txt" file for ' + '"conan config install"') parser_add = subparsers.add_parser('add', help='Add a remote') parser_add.add_argument('remote', help='Name of the remote') parser_add.add_argument('url', help='URL of the remote') @@ -1216,7 +1219,6 @@ def remote(self, *args): parser_pupd.add_argument('reference', help='Package recipe reference') parser_pupd.add_argument('remote', help='Name of the remote') - list_pref = subparsers.add_parser('list_pref', help='List the package binaries and ' 'its associated remotes') list_pref.add_argument('reference', help='Package recipe reference') @@ -1227,7 +1229,7 @@ def remote(self, *args): add_pref.add_argument('remote', help='Name of the remote') remove_pref = subparsers.add_parser('remove_pref', help="Dissociate a package's reference " - "and its remote") + "and its remote") remove_pref.add_argument('package_reference', help='Binary package reference') update_pref = subparsers.add_parser('update_pref', help="Update the remote associated with " @@ -1450,12 +1452,12 @@ def editable(self, *args): if args.subcommand == "add": 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.path))) + self._user_io.out.success("Reference '{}' in editable mode".format(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)) + self._user_io.out.success("Removed editable mode for reference " + "'{}'".format(args.reference)) else: self._user_io.out.warn("Reference '{}' was not installed " "as editable".format(args.reference)) diff --git a/conans/client/conan_api.py b/conans/client/conan_api.py index a9ba7874370..f2010b5fa88 100644 --- a/conans/client/conan_api.py +++ b/conans/client/conan_api.py @@ -489,7 +489,7 @@ def workspace_install(self, path, settings=None, options=None, env=None, if node.recipe == RECIPE_EDITABLE: generators = workspace[node.ref].generators if generators is not None: - node.conanfile.generators = generators + node.conanfile.generators.extend(generators) installer = BinaryInstaller(self._cache, self._user_io.out, self._remote_manager, recorder=recorder, hook_manager=self._hook_manager) @@ -1071,7 +1071,7 @@ def editable_add(self, path, reference, layout, cwd): layout_abs_path = get_editable_abs_path(layout, cwd, self._cache.conan_folder) if layout_abs_path: self._user_io.out.success("Using layout file: %s" % layout_abs_path) - self._cache.editable_packages.link(ref, os.path.dirname(target_path), layout_abs_path) + self._cache.editable_packages.add(ref, os.path.dirname(target_path), layout_abs_path) @api_method def editable_remove(self, reference): @@ -1080,7 +1080,7 @@ def editable_remove(self, reference): @api_method def editable_list(self): - return {str(k): v for k, v in self._cache.editable_packages.refs().items()} + return {str(k): v for k, v in self._cache.editable_packages.edited_refs.items()} Conan = ConanAPIV1 diff --git a/conans/client/installer.py b/conans/client/installer.py index 1b7963b870d..9faaee419c1 100644 --- a/conans/client/installer.py +++ b/conans/client/installer.py @@ -8,7 +8,7 @@ from conans.client.generators import TXTGenerator, write_generators 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.importer import remove_imports, run_imports 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 @@ -18,6 +18,7 @@ conanfile_exception_formatter) from conans.model.build_info import CppInfo from conans.model.conan_file import get_env_context_manager +from conans.model.editable_cpp_info import EditableLayout from conans.model.env_info import EnvInfo from conans.model.manifest import FileTreeManifest from conans.model.ref import PackageReference @@ -163,7 +164,6 @@ def _build_package(self): # 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(self._conan_file, self.build_folder) try: @@ -318,7 +318,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_folder", + build_folder = editable_cpp_info.folder(node.ref, EditableLayout.BUILD_FOLDER, settings=node.conanfile.settings, options=node.conanfile.options) if build_folder is not None: @@ -333,7 +333,6 @@ def _handle_node_editable(self, node, graph_info): 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) diff --git a/conans/model/editable_cpp_info.py b/conans/model/editable_cpp_info.py index c4e6ac4d1a9..b2ab609199d 100644 --- a/conans/model/editable_cpp_info.py +++ b/conans/model/editable_cpp_info.py @@ -30,8 +30,10 @@ def get_editable_abs_path(path, cwd, cache_folder): class EditableLayout(object): + BUILD_FOLDER = "build_folder" + SOURCE_FOLDER = "source_folder" cpp_info_dirs = ['includedirs', 'libdirs', 'resdirs', 'bindirs', 'builddirs', 'srcdirs'] - folders = ['build_folder', 'source_folder'] + folders = [BUILD_FOLDER, SOURCE_FOLDER] def __init__(self, data, folders): self._data = data diff --git a/conans/model/workspace.py b/conans/model/workspace.py index 328f489081c..433257378d1 100644 --- a/conans/model/workspace.py +++ b/conans/model/workspace.py @@ -4,11 +4,11 @@ import yaml +from conans.client.graph.graph import RECIPE_EDITABLE from conans.errors import ConanException +from conans.model.editable_cpp_info import get_editable_abs_path, EditableLayout 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): @@ -37,8 +37,6 @@ def root_folder(self): 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._ws_generator == "cmake": cmake = "" add_subdirs = "" @@ -49,9 +47,11 @@ def generate(self, cwd, graph): ws_pkg = self._workspace_packages[ref] layout = self._cache.package_layout(ref) editable = layout.editable_cpp_info() - conanfile = editables[ref] - build = editable.folder(ref, "build_folder", conanfile.settings, conanfile.options) - src = editable.folder(ref, "source_folder", conanfile.settings, conanfile.options) + conanfile = node.conanfile + build = editable.folder(ref, EditableLayout.BUILD_FOLDER, conanfile.settings, + conanfile.options) + src = editable.folder(ref, EditableLayout.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/search/search.py b/conans/search/search.py index c4c47e845d9..723bf97346a 100644 --- a/conans/search/search.py +++ b/conans/search/search.py @@ -100,7 +100,7 @@ def search_recipes(cache, pattern=None, ignorecase=True): subdirs = list_folder_subdirs(basedir=cache.store, level=4) refs = [ConanFileReference(*folder.split("/")) for folder in subdirs] - refs.extend(cache.editable_packages.refs().keys()) + refs.extend(cache.editable_packages.edited_refs.keys()) if pattern: refs = [r for r in refs if _partial_match(pattern, r)] refs = sorted(refs) diff --git a/conans/test/functional/editable/link_create_test.py b/conans/test/functional/editable/link_create_test.py index 7470823afb8..9c6b16722d6 100644 --- a/conans/test/functional/editable/link_create_test.py +++ b/conans/test/functional/editable/link_create_test.py @@ -33,7 +33,7 @@ def test_install_ok(self): t = TestClient() t.save(files={'conanfile.py': self.conanfile}) t.run('editable add . {}'.format(ref)) - self.assertIn("Reference 'lib/version@user/name' linked to directory '", t.out) + self.assertIn("Reference 'lib/version@user/name' in editable mode", t.out) def test_editable_list_search(self): ref = ConanFileReference.loads('lib/version@user/name') diff --git a/conans/test/functional/editable/link_remove_test.py b/conans/test/functional/editable/link_remove_test.py index 82a8c6bcb4f..b2ee05d7d02 100644 --- a/conans/test/functional/editable/link_remove_test.py +++ b/conans/test/functional/editable/link_remove_test.py @@ -26,7 +26,7 @@ def setUp(self): def test_unlink(self): self.t.run('editable remove {}'.format(self.ref)) - self.assertIn("Removed linkage for reference '{}'".format(self.ref), self.t.out) + self.assertIn("Removed editable mode for reference '{}'".format(self.ref), self.t.out) self.assertFalse(self.t.cache.installed_as_editable(self.ref)) def test_unlink_not_linked(self): From b6a48198a3af9c7cee9a72272a9a4a9cea5d32cd Mon Sep 17 00:00:00 2001 From: memsharded Date: Mon, 25 Feb 2019 16:51:25 +0100 Subject: [PATCH 30/34] fixed bug in generators --- conans/client/conan_api.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/conans/client/conan_api.py b/conans/client/conan_api.py index f2010b5fa88..495f7352c49 100644 --- a/conans/client/conan_api.py +++ b/conans/client/conan_api.py @@ -489,7 +489,9 @@ def workspace_install(self, path, settings=None, options=None, env=None, if node.recipe == RECIPE_EDITABLE: generators = workspace[node.ref].generators if generators is not None: - node.conanfile.generators.extend(generators) + tmp = list(node.conanfile.generators) + tmp.extend([g for g in generators if g not in tmp]) + node.conanfile.generators = tmp installer = BinaryInstaller(self._cache, self._user_io.out, self._remote_manager, recorder=recorder, hook_manager=self._hook_manager) From 85fce390f0577017f287f33fa05d534b8f385d71 Mon Sep 17 00:00:00 2001 From: memsharded Date: Tue, 26 Feb 2019 12:32:00 +0100 Subject: [PATCH 31/34] fixing root folders in layout --- conans/client/conan_api.py | 2 +- conans/model/workspace.py | 12 +++++-- conans/test/integration/workspace_test.py | 42 +++++++++++++++++++++++ 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/conans/client/conan_api.py b/conans/client/conan_api.py index 495f7352c49..44d2e34a6d0 100644 --- a/conans/client/conan_api.py +++ b/conans/client/conan_api.py @@ -496,7 +496,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, deps_graph) + workspace.generate(cwd, deps_graph, self._user_io.out) @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 433257378d1..2b72fdabf3b 100644 --- a/conans/model/workspace.py +++ b/conans/model/workspace.py @@ -36,7 +36,7 @@ def root_folder(self): class Workspace(object): - def generate(self, cwd, graph): + def generate(self, cwd, graph, output): if self._ws_generator == "cmake": cmake = "" add_subdirs = "" @@ -52,16 +52,22 @@ def generate(self, cwd, graph): conanfile.options) src = editable.folder(ref, EditableLayout.SOURCE_FOLDER, conanfile.settings, conanfile.options) - if src: + if src is not None: src = os.path.join(ws_pkg.root_folder, src).replace("\\", "/") cmake += 'set(PACKAGE_%s_SRC "%s")\n' % (ref.name, src) - if build: + else: + output.warn("CMake workspace: source_folder is not defined for %s" % str(ref)) + if build is not None: build = os.path.join(ws_pkg.root_folder, build).replace("\\", "/") cmake += 'set(PACKAGE_%s_BUILD "%s")\n' % (ref.name, build) + else: + output.warn("CMake workspace: build_folder is not defined for %s" % str(ref)) if src and build: add_subdirs += (' add_subdirectory(${PACKAGE_%s_SRC} ${PACKAGE_%s_BUILD})\n' % (ref.name, ref.name)) + else: + output.warn("CMake workspace: cannot 'add_subdirectory()'") if add_subdirs: cmake += "macro(conan_workspace_subdirectories)\n" cmake += add_subdirs diff --git a/conans/test/integration/workspace_test.py b/conans/test/integration/workspace_test.py index e8fec573e2c..f0186326a91 100644 --- a/conans/test/integration/workspace_test.py +++ b/conans/test/integration/workspace_test.py @@ -626,3 +626,45 @@ def files(name, depend=None): "conanbuildinfo.cmake"))) self.assertTrue(os.path.exists(os.path.join(client.current_folder, "conanworkspace.cmake"))) + + def gen_subdirectories_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(""" + editables: + HelloB/0.1@lasote/stable: + path: B + HelloC/0.1@lasote/stable: + path: C + HelloA/0.1@lasote/stable: + path: A + layout: layout + workspace_generator: cmake + root: HelloA/0.1@lasote/stable + """) + layout = dedent(""" + [build_folder] + + [source_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) + + conanws_cmake = load(os.path.join(client.current_folder, "conanworkspace.cmake")) + self.assertIn("macro(conan_workspace_subdirectories)", conanws_cmake) + for p in ("HelloC", "HelloB", "HelloA"): + self.assertIn("add_subdirectory(${PACKAGE_%s_SRC} ${PACKAGE_%s_BUILD})" % (p, p), + conanws_cmake) From 5c780cdfa2fe14be1db0dbb7db16b3ad3244cf25 Mon Sep 17 00:00:00 2001 From: memsharded Date: Tue, 26 Feb 2019 13:11:14 +0100 Subject: [PATCH 32/34] checks for conanws file syntax --- conans/model/workspace.py | 23 +++++--- conans/test/integration/workspace_test.py | 65 ++++++++++++++++++++++- 2 files changed, 81 insertions(+), 7 deletions(-) diff --git a/conans/model/workspace.py b/conans/model/workspace.py index 2b72fdabf3b..99e6cb9a1e4 100644 --- a/conans/model/workspace.py +++ b/conans/model/workspace.py @@ -14,21 +14,26 @@ class LocalPackage(object): def __init__(self, base_folder, data, cache, ws_layout, ws_generators): self._base_folder = base_folder - self._conanfile_folder = data.get("path") # The folder with the conanfile - layout = data.get("layout") + self._conanfile_folder = data.pop("path", None) # The folder with the conanfile + if self._conanfile_folder is None: + raise ConanException("Workspace editable does not define path") + layout = data.pop("layout", None) if layout: - self.layout = get_editable_abs_path(data.get("layout"), self._base_folder, + self.layout = get_editable_abs_path(layout, self._base_folder, cache.conan_folder) else: self.layout = ws_layout - generators = data.get("generators") + generators = data.pop("generators", None) if isinstance(generators, str): generators = [generators] if generators is None: generators = ws_generators self.generators = generators + if data: + raise ConanException("Workspace unrecognized fields: %s" % data) + @property def root_folder(self): return os.path.abspath(os.path.join(self._base_folder, self._conanfile_folder)) @@ -116,12 +121,18 @@ def _loads(self, text): if not self._root: raise ConanException("Conan workspace needs at least 1 root conanfile") - editables = yml.pop("editables", None) + editables = yml.pop("editables", {}) for package_name, data in editables.items(): + if not data: + raise ConanException("Workspace editable %s does not define data" + % str(package_name)) workspace_package = LocalPackage(self._base_folder, data, self._cache, ws_layout, generators) 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: - raise ConanException("Root %s is not a local package" % package_name) + raise ConanException("Root %s is not defined as editable" % str(package_name)) + + if yml: + raise ConanException("Workspace unrecognized fields: %s" % yml) diff --git a/conans/test/integration/workspace_test.py b/conans/test/integration/workspace_test.py index f0186326a91..9946ef8aeb4 100644 --- a/conans/test/integration/workspace_test.py +++ b/conans/test/integration/workspace_test.py @@ -8,7 +8,10 @@ from conans.client import tools from conans.test.utils.tools import TestClient -from conans.util.files import load +from conans.util.files import load, save +from conans.test.utils.test_files import temp_folder +from conans.model.workspace import Workspace +from conans.errors import ConanException conanfile_build = """from conans import ConanFile, CMake @@ -89,6 +92,66 @@ def package_info(self): class WorkspaceTest(unittest.TestCase): + + def parse_test(self): + folder = temp_folder() + path = os.path.join(folder, "conanws.yml") + project = "root: Hellob/0.1@lasote/stable" + save(path, project) + with self.assertRaisesRegexp(ConanException, + "Root Hellob/0.1@lasote/stable is not defined as editable"): + Workspace(path, None) + + project = dedent(""" + editables: + HelloB/0.1@lasote/stable: + path: B + random: something + root: HelloB/0.1@lasote/stable + """) + save(path, project) + + with self.assertRaisesRegexp(ConanException, + "Workspace unrecognized fields: {'random': 'something'}"): + Workspace(path, None) + + project = dedent(""" + editables: + HelloB/0.1@lasote/stable: + path: B + root: HelloB/0.1@lasote/stable + random: something + """) + save(path, project) + + with self.assertRaisesRegexp(ConanException, + "Workspace unrecognized fields: {'random': 'something'}"): + Workspace(path, None) + + project = dedent(""" + editables: + HelloB/0.1@lasote/stable: + root: HelloB/0.1@lasote/stable + """) + save(path, project) + + with self.assertRaisesRegexp(ConanException, + "Workspace editable HelloB/0.1@lasote/stable " + "does not define data"): + Workspace(path, None) + + project = dedent(""" + editables: + HelloB/0.1@lasote/stable: + layout: layout + root: HelloB/0.1@lasote/stable + """) + save(path, project) + + with self.assertRaisesRegexp(ConanException, + "Workspace editable does not define path"): + Workspace(path, None) + def simple_test(self): client = TestClient() From 8d8a417371b527ef06ccfa7f871f1f076e74ffb4 Mon Sep 17 00:00:00 2001 From: memsharded Date: Tue, 26 Feb 2019 13:30:23 +0100 Subject: [PATCH 33/34] review parsing --- conans/model/workspace.py | 15 +++++++-------- conans/test/integration/workspace_test.py | 5 +++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/conans/model/workspace.py b/conans/model/workspace.py index 99e6cb9a1e4..10ae4c08b57 100644 --- a/conans/model/workspace.py +++ b/conans/model/workspace.py @@ -12,11 +12,13 @@ class LocalPackage(object): - def __init__(self, base_folder, data, cache, ws_layout, ws_generators): + def __init__(self, base_folder, data, cache, ws_layout, ws_generators, ref): + if not data: + raise ConanException("Workspace editable %s does not define path" % str(ref)) self._base_folder = base_folder self._conanfile_folder = data.pop("path", None) # The folder with the conanfile if self._conanfile_folder is None: - raise ConanException("Workspace editable does not define path") + raise ConanException("Workspace editable %s does not define path" % str(ref)) layout = data.pop("layout", None) if layout: self.layout = get_editable_abs_path(layout, self._base_folder, @@ -122,13 +124,10 @@ def _loads(self, text): raise ConanException("Conan workspace needs at least 1 root conanfile") editables = yml.pop("editables", {}) - for package_name, data in editables.items(): - if not data: - raise ConanException("Workspace editable %s does not define data" - % str(package_name)) + for ref, data in editables.items(): workspace_package = LocalPackage(self._base_folder, data, - self._cache, ws_layout, generators) - package_name = ConanFileReference.loads(package_name) + self._cache, ws_layout, generators, ref) + package_name = ConanFileReference.loads(ref) 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 9946ef8aeb4..52a5d5fdd3a 100644 --- a/conans/test/integration/workspace_test.py +++ b/conans/test/integration/workspace_test.py @@ -137,7 +137,7 @@ def parse_test(self): with self.assertRaisesRegexp(ConanException, "Workspace editable HelloB/0.1@lasote/stable " - "does not define data"): + "does not define path"): Workspace(path, None) project = dedent(""" @@ -149,7 +149,8 @@ def parse_test(self): save(path, project) with self.assertRaisesRegexp(ConanException, - "Workspace editable does not define path"): + "Workspace editable HelloB/0.1@lasote/stable " + "does not define path"): Workspace(path, None) def simple_test(self): From 1b64402cb93756c8271f3d29a0a85959adaedb43 Mon Sep 17 00:00:00 2001 From: memsharded Date: Tue, 26 Feb 2019 14:14:41 +0100 Subject: [PATCH 34/34] raise only in one place --- conans/model/workspace.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/conans/model/workspace.py b/conans/model/workspace.py index 10ae4c08b57..761a4ddfc1d 100644 --- a/conans/model/workspace.py +++ b/conans/model/workspace.py @@ -13,12 +13,10 @@ class LocalPackage(object): def __init__(self, base_folder, data, cache, ws_layout, ws_generators, ref): - if not data: + if not data or not data.get("path"): raise ConanException("Workspace editable %s does not define path" % str(ref)) self._base_folder = base_folder self._conanfile_folder = data.pop("path", None) # The folder with the conanfile - if self._conanfile_folder is None: - raise ConanException("Workspace editable %s does not define path" % str(ref)) layout = data.pop("layout", None) if layout: self.layout = get_editable_abs_path(layout, self._base_folder,