Skip to content

Commit e912a66

Browse files
authored
workspace clean proposal (#17763)
* first sketch for workspace build * wip * adding a template * fix test * wip * output-folder based workspace-clean * missing subcommand
1 parent 6b701e2 commit e912a66

File tree

4 files changed

+67
-1
lines changed

4 files changed

+67
-1
lines changed

conan/api/subapi/workspace.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,10 @@ def remove(self, path):
205205
self._check_ws()
206206
return self._ws.remove(path)
207207

208+
def clean(self):
209+
self._check_ws()
210+
return self._ws.clean()
211+
208212
def info(self):
209213
self._check_ws()
210214
return {"name": self.name,

conan/cli/commands/workspace.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,15 @@ def workspace_install(conan_api: ConanAPI, parser, subparser, *args):
216216
envs_generation=args.envs_generation)
217217

218218

219+
@conan_subcommand()
220+
def workspace_clean(conan_api: ConanAPI, parser, subparser, *args):
221+
"""
222+
Clean the temporary build folders when possible
223+
"""
224+
parser.parse_args(*args)
225+
conan_api.workspace.clean()
226+
227+
219228
@conan_command(group="Consumer")
220229
def workspace(conan_api, parser, *args): # noqa
221230
"""

conan/internal/model/workspace.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
import shutil
23

34
import yaml
45

@@ -19,7 +20,7 @@ def __init__(self, folder, conan_api):
1920
self.output = ConanOutput(scope=self.name())
2021

2122
def name(self):
22-
return os.path.basename(self.folder)
23+
return self.conan_data.get("name") or os.path.basename(self.folder)
2324

2425
def _conan_load_data(self):
2526
data_path = os.path.join(self.folder, "conanws.yml")
@@ -60,6 +61,19 @@ def remove(self, path):
6061
save(os.path.join(self.folder, "conanws.yml"), yaml.dump(self.conan_data))
6162
return found_ref
6263

64+
def clean(self):
65+
self.output.info("Default workspace clean: Removing the output-folder of each editable")
66+
for ref, info in self.conan_data.get("editables", {}).items():
67+
if not info.get("output_folder"):
68+
self.output.info(f"Editable {ref} doesn't have an output_folder defined")
69+
continue
70+
of = os.path.join(self.folder, info["output_folder"])
71+
try:
72+
self.output.info(f"Removing {ref} output folder: {of}")
73+
shutil.rmtree(of)
74+
except OSError as e:
75+
self.output.warning(f"Error removing {ref} output folder: {str(e)}")
76+
6377
def _conan_rel_path(self, path):
6478
if path is None:
6579
return None

test/integration/workspace/test_workspace.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,3 +583,42 @@ def test_workspace_with_local_recipes_index():
583583
assert "zlib/1.2.11" in c.out # It doesn't crash
584584
c.run("list zlib/1.2.11#*")
585585
assert "zlib/1.2.11" not in c.out
586+
587+
588+
class TestClean:
589+
def test_clean(self):
590+
# Using cmake_layout, we can clean the build folders
591+
c = TestClient()
592+
c.save({"conanws.yml": "name: my_workspace"})
593+
pkga = GenConanfile("pkga", "0.1").with_settings("build_type")
594+
pkgb = GenConanfile("pkgb", "0.1").with_requires("pkga/0.1").with_settings("build_type")
595+
c.save({"pkga/conanfile.py": pkga ,
596+
"pkgb/conanfile.py": pkgb,
597+
"pkgc/conanfile.py": GenConanfile("pkgc", "0.1")})
598+
c.run("workspace add pkga -of=build/pkga")
599+
c.run("workspace add pkgb -of=build/pkgb --product")
600+
c.run("workspace add pkgc")
601+
c.run("workspace build")
602+
assert os.path.exists(os.path.join(c.current_folder, "build", "pkga"))
603+
assert os.path.exists(os.path.join(c.current_folder, "build", "pkgb"))
604+
c.run("workspace clean")
605+
assert "my_workspace: Removing pkga/0.1 output folder" in c.out
606+
assert "my_workspace: Removing pkgb/0.1 output folder" in c.out
607+
assert "Editable pkgc/0.1 doesn't have an output_folder defined" in c.out
608+
assert not os.path.exists(os.path.join(c.current_folder, "build", "pkga"))
609+
assert not os.path.exists(os.path.join(c.current_folder, "build", "pkgb"))
610+
611+
def test_custom_clean(self):
612+
conanfilews = textwrap.dedent("""
613+
from conan import Workspace
614+
615+
class Ws(Workspace):
616+
def name(self):
617+
return "my_workspace"
618+
def clean(self):
619+
self.output.info("MY CLEAN!!!!")
620+
""")
621+
c = TestClient()
622+
c.save({"conanws.py": conanfilews})
623+
c.run("workspace clean")
624+
assert "my_workspace: MY CLEAN!!!" in c.out

0 commit comments

Comments
 (0)