Skip to content

Commit 3678ee1

Browse files
authored
Feature/workspace partial install (#17887)
* workspace install partial * remove --ref arg
1 parent 627b80e commit 3678ee1

File tree

3 files changed

+55
-6
lines changed

3 files changed

+55
-6
lines changed

conan/api/subapi/workspace.py

+10
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,16 @@ def editable_packages(self):
122122
v["output_folder"]))
123123
return editables
124124

125+
def select_editables(self, paths):
126+
filtered_refs = [self.editable_from_path(p) for p in paths or []]
127+
editables = self.editable_packages
128+
requires = [ref for ref in editables]
129+
if filtered_refs:
130+
ConanOutput().info(f"Filtering and installing only selected editable packages")
131+
requires = [ref for ref in requires if ref in filtered_refs]
132+
ConanOutput().info(f"Filtered references: {requires}")
133+
return requires
134+
125135
@property
126136
def products(self):
127137
self._check_ws()

conan/cli/commands/workspace.py

+7-6
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,7 @@ def workspace_add(conan_api: ConanAPI, parser, subparser, *args):
5050
subparser.add_argument('path', nargs="?",
5151
help='Path to the package folder in the user workspace')
5252
add_reference_args(subparser)
53-
subparser.add_argument("--ref", nargs="?",
54-
help="Open and add this reference")
53+
subparser.add_argument("--ref", help="Open and add this reference")
5554
subparser.add_argument("-of", "--output-folder",
5655
help='The root output folder for generated and build files')
5756
group = subparser.add_mutually_exclusive_group()
@@ -78,9 +77,10 @@ def workspace_add(conan_api: ConanAPI, parser, subparser, *args):
7877
@conan_subcommand()
7978
def workspace_remove(conan_api: ConanAPI, parser, subparser, *args):
8079
"""
81-
Remove packages to current workspace
80+
Remove packages from the current workspace
8281
"""
83-
subparser.add_argument('path', help='Path to the package folder in the user workspace')
82+
subparser.add_argument('path',
83+
help='Path to the package folder in the user workspace')
8484
args = parser.parse_args(*args)
8585
removed = conan_api.workspace.remove(make_abs_path(args.path))
8686
ConanOutput().info(f"Removed from workspace: {removed}")
@@ -170,6 +170,8 @@ def workspace_install(conan_api: ConanAPI, parser, subparser, *args):
170170
Install the workspace as a monolith, installing only external dependencies to the workspace,
171171
generating a single result (generators, etc) for the whole workspace.
172172
"""
173+
subparser.add_argument("path", nargs="*",
174+
help="Install only these editable packages, not all")
173175
subparser.add_argument("-g", "--generator", action="append", help='Generators to use')
174176
subparser.add_argument("-of", "--output-folder",
175177
help='The root output folder for generated and build files')
@@ -191,8 +193,7 @@ def workspace_install(conan_api: ConanAPI, parser, subparser, *args):
191193

192194
conan_api.workspace.info() # FIXME: Just to force error if WS not enabled
193195
# Build a dependency graph with all editables as requirements
194-
editables = conan_api.workspace.editable_packages
195-
requires = [ref for ref in editables]
196+
requires = conan_api.workspace.select_editables(args.path)
196197
if not requires:
197198
raise ConanException("This workspace cannot be installed, it doesn't have any editable")
198199
deps_graph = conan_api.graph.load_graph_requires(requires, [],

test/integration/workspace/test_workspace.py

+38
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import json
22
import os
3+
import shutil
34
import textwrap
45

56
import pytest
@@ -254,6 +255,19 @@ def test_remove_product(self):
254255
c.run("workspace info")
255256
assert "mydeppkg" not in c.out
256257

258+
def test_remove_removed_folder(self):
259+
c = TestClient(light=True)
260+
c.save({"conanws.yml": "",
261+
"mydeppkg/conanfile.py": GenConanfile("mydeppkg", "0.1")})
262+
c.run("workspace add mydeppkg")
263+
# If we now remove the folder
264+
shutil.rmtree(os.path.join(c.current_folder, "mydeppkg"))
265+
# It can still be removed by path, even if the path doesn't exist
266+
c.run("workspace remove mydeppkg")
267+
assert "Removed from workspace: mydeppkg/0.1" in c.out
268+
c.run("workspace info")
269+
assert "mydeppkg" not in c.out
270+
257271
def test_custom_add_remove(self):
258272
c = TestClient(light=True)
259273

@@ -524,6 +538,30 @@ def root_conanfile(self):
524538
c.run("workspace install", assert_error=True)
525539
assert "ERROR: Conanfile in conanws.py shouldn't have 'requires'" in c.out
526540

541+
def test_install_partial(self):
542+
# If we want to install only some part of the workspace
543+
c = TestClient()
544+
c.save({"dep/conanfile.py": GenConanfile()})
545+
c.run("create dep --name=dep1 --version=0.1")
546+
c.run("create dep --name=dep2 --version=0.1")
547+
c.save({"conanws.yml": "",
548+
"liba/conanfile.py": GenConanfile("liba", "0.1").with_requires("dep1/0.1"),
549+
"libb/conanfile.py": GenConanfile("libb", "0.1").with_requires("liba/0.1"),
550+
"libc/conanfile.py": GenConanfile("libc", "0.1").with_requires("libb/0.1",
551+
"dep2/0.1")},
552+
clean_first=True)
553+
c.run("workspace add liba")
554+
c.run("workspace add libb")
555+
c.run("workspace add libc")
556+
for arg in ("libb", "libb liba"):
557+
c.run(f"workspace install {arg} -g CMakeDeps -of=build")
558+
assert "dep1/0.1" in c.out
559+
assert "dep2/0.1" not in c.out
560+
assert "libc/0.1" not in c.out
561+
files = os.listdir(os.path.join(c.current_folder, "build"))
562+
assert "dep1-config.cmake" in files
563+
assert "dep2-config.cmake" not in files
564+
527565

528566
def test_workspace_with_local_recipes_index():
529567
c3i_folder = temp_folder()

0 commit comments

Comments
 (0)