Skip to content

Commit 5cd5791

Browse files
memshardedAbrilRBSuilianriesczoidolucaskdc
authored
Feature: workspace create (#18390)
* workspace Python files proposal * fixes * review * workspace create * wip * wip * tests passing * wip * wip * wip * wip * wip * tests passing, first proposal for orchestrated build + create * dynamic ref attributes for conan workspace create * test for conan workspace build too * wip * Update conan/cli/commands/workspace.py Co-authored-by: Abril Rincón Blanco <[email protected]> * wip * [feature] Add generic config for CMake and Meson install strip (#18429) * Use tools.install:strip for CMake Signed-off-by: Uilian Ries <[email protected]> * Add meson install strip Signed-off-by: Uilian Ries <[email protected]> * Validate strip flag when installing with meson Signed-off-by: Uilian Ries <[email protected]> * Improve strip config description Signed-off-by: Uilian Ries <[email protected]> * Fallback for tools.cmake:install_strip Signed-off-by: Uilian Ries <[email protected]> * Use deprecation flag for config Co-authored-by: James <[email protected]> * Reduce install strip property Signed-off-by: Uilian Ries <[email protected]> * Rename config to tools.build.install:strip Signed-off-by: Uilian Ries <[email protected]> * Rename config to tools.build.install_strip Signed-off-by: Uilian Ries <[email protected]> * Fix typo tools.build.install_strip Signed-off-by: Uilian Ries <[email protected]> --------- Signed-off-by: Uilian Ries <[email protected]> Co-authored-by: James <[email protected]> * Add support for sbom and lockfiles for conan audit list (#18437) * Add support for sbom and lockfiles for conan audit list * Ensure sbom is cyclone * Fix remote for list * Add test for pkglist with remote --------- Co-authored-by: Carlos Zoido <[email protected]> * fixing CMake presets on Windows with backslash (#18435) * fixing CMake presets on Windows with backslash * adding checks to test * Fix: parse -cc args when running "conan cache backup-upload" * [fix] Add support for Git tree-less repository when getting the URL (#18444) * Add test to validate Git treeless clone support Signed-off-by: Uilian Ries <[email protected]> * Remove git method from the remote url Signed-off-by: Uilian Ries <[email protected]> * rsplit FTW Signed-off-by: Uilian Ries <[email protected]> * Always return string Signed-off-by: Uilian Ries <[email protected]> * Filter out (fetch) and (push) Signed-off-by: Uilian Ries <[email protected]> --------- Signed-off-by: Uilian Ries <[email protected]> * fix issue with missing folder in local-recipes-index (#18449) * removed --local * renamed editables->packages * wip * wip * new test to check global.conf/-cc --------- Signed-off-by: Uilian Ries <[email protected]> Co-authored-by: Abril Rincón Blanco <[email protected]> Co-authored-by: Uilian Ries <[email protected]> Co-authored-by: Carlos Zoido <[email protected]> Co-authored-by: LUCAS K DAL CASTEL <[email protected]>
1 parent da267ca commit 5cd5791

File tree

10 files changed

+535
-156
lines changed

10 files changed

+535
-156
lines changed

conan/api/output.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,12 @@ def write(self, data, fg=None, bg=None, newline=False):
175175

176176
return self
177177

178+
def box(self, msg):
179+
color = Color.BRIGHT_GREEN
180+
self.writeln("\n**************************************************", fg=color)
181+
self.writeln(f'*{msg: ^48}*', fg=color)
182+
self.writeln(f"**************************************************\n", fg=color)
183+
178184
def _write_message(self, msg, fg=None, bg=None, newline=True):
179185
if isinstance(msg, dict):
180186
# For traces we can receive a dict already, we try to transform then into more natural

conan/api/subapi/command.py

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

34
from conan.api.output import ConanOutput
45
from conan.errors import ConanException
@@ -12,7 +13,7 @@ def __init__(self, conan_api):
1213

1314
def run(self, cmd):
1415
if isinstance(cmd, str):
15-
cmd = cmd.split()
16+
cmd = shlex.split(cmd)
1617
if isinstance(cmd, list):
1718
current_cmd = cmd[0]
1819
args = cmd[1:]

conan/api/subapi/workspace.py

Lines changed: 66 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
from conan.api.model import RecipeReference
99
from conan.api.output import ConanOutput
1010
from conan.cli import make_abs_path
11+
from conan.cli.printers.graph import print_graph_basic, print_graph_packages
1112
from conan.errors import ConanException
1213
from conan.internal.conan_app import ConanApp
14+
from conan.internal.graph.install_graph import ProfileArgs
1315
from conan.internal.model.workspace import Workspace, WORKSPACE_YML, WORKSPACE_PY, WORKSPACE_FOLDER
1416
from conan.tools.scm import Git
1517
from conan.internal.graph.graph import RECIPE_EDITABLE, DepsGraph, CONTEXT_HOST, RECIPE_VIRTUAL, Node, \
@@ -74,6 +76,7 @@ class WorkspaceAPI:
7476
TEST_ENABLED = False
7577

7678
def __init__(self, conan_api):
79+
self._enabled = True
7780
self._conan_api = conan_api
7881
self._folder = _find_ws_folder()
7982
if self._folder:
@@ -85,6 +88,9 @@ def __init__(self, conan_api):
8588
ConanOutput().warning(f"Workspace is a dev-only feature, exclusively for testing")
8689
self._ws = _load_workspace(self._folder, conan_api) # Error if not loading
8790

91+
def enable(self, value):
92+
self._enabled = value
93+
8894
@property
8995
def name(self):
9096
self._check_ws()
@@ -94,14 +100,14 @@ def folder(self):
94100
"""
95101
@return: the current workspace folder where the conanws.yml or conanws.py is located
96102
"""
103+
self._check_ws()
97104
return self._folder
98105

99-
@property
100-
def editable_packages(self):
106+
def packages(self):
101107
"""
102108
@return: Returns {RecipeReference: {"path": full abs-path, "output_folder": abs-path}}
103109
"""
104-
if not self._folder:
110+
if not self._folder or not self._enabled:
105111
return
106112
editables = self._ws.packages()
107113
editables = {RecipeReference.loads(r): v.copy() for r, v in editables.items()}
@@ -115,21 +121,6 @@ def editable_packages(self):
115121
v["output_folder"]))
116122
return editables
117123

118-
def select_editables(self, paths):
119-
filtered_refs = [self.editable_from_path(p) for p in paths or []]
120-
editables = self.editable_packages
121-
requires = [ref for ref in editables]
122-
if filtered_refs:
123-
ConanOutput().info(f"Filtering and installing only selected editable packages")
124-
requires = [ref for ref in requires if ref in filtered_refs]
125-
ConanOutput().info(f"Filtered references: {requires}")
126-
return requires
127-
128-
@property
129-
def products(self):
130-
self._check_ws()
131-
return self._ws.products()
132-
133124
def open(self, require, remotes, cwd=None):
134125
app = ConanApp(self._conan_api)
135126
ref = RecipeReference.loads(require)
@@ -167,7 +158,7 @@ def _check_ws(self):
167158
f"'{WORKSPACE_PY}' or '{WORKSPACE_YML}' file")
168159

169160
def add(self, path, name=None, version=None, user=None, channel=None, cwd=None,
170-
output_folder=None, remotes=None, product=False):
161+
output_folder=None, remotes=None):
171162
"""
172163
Add a new editable package to the current workspace (the current workspace must exist)
173164
@param path: The path to the folder containing the conanfile.py that defines the package
@@ -178,7 +169,6 @@ def add(self, path, name=None, version=None, user=None, channel=None, cwd=None,
178169
@param cwd:
179170
@param output_folder:
180171
@param remotes:
181-
@param product:
182172
@return: The reference of the added package
183173
"""
184174
self._check_ws()
@@ -191,7 +181,7 @@ def add(self, path, name=None, version=None, user=None, channel=None, cwd=None,
191181
ref.validate_ref()
192182
output_folder = make_abs_path(output_folder) if output_folder else None
193183
# Check the conanfile is there, and name/version matches
194-
self._ws.add(ref, full_path, output_folder, product)
184+
self._ws.add(ref, full_path, output_folder)
195185
return ref
196186

197187
@staticmethod
@@ -230,17 +220,10 @@ def info(self):
230220
self._check_ws()
231221
return {"name": self.name,
232222
"folder": self._folder,
233-
"products": self.products,
234223
"packages": self._ws.packages()}
235224

236-
def editable_from_path(self, path):
237-
editables = self._ws.packages()
238-
for ref, info in editables.items():
239-
if info["path"].replace("\\", "/") == path:
240-
return RecipeReference.loads(ref)
241-
242-
def collapse_editables(self, deps_graph, profile_host, profile_build):
243-
ConanOutput().title("Collapsing workspace editables")
225+
def super_build_graph(self, deps_graph, profile_host, profile_build):
226+
ConanOutput().title("Collapsing workspace packages")
244227

245228
root_class = self._ws.root_conanfile()
246229
if root_class is not None:
@@ -282,3 +265,56 @@ def collapse_editables(self, deps_graph, profile_host, profile_build):
282265
result.add_edge(root, t.node, r)
283266

284267
return result
268+
269+
def export(self, lockfile=None, remotes=None):
270+
self._check_ws()
271+
exported = []
272+
for ref, info in self.packages().items():
273+
exported_ref = self._conan_api.export.export(info["path"], ref.name, str(ref.version),
274+
ref.user, ref.channel,
275+
lockfile=lockfile, remotes=remotes)
276+
ref, _ = exported_ref
277+
exported.append(ref)
278+
return exported
279+
280+
281+
def select_packages(self, packages):
282+
self._check_ws()
283+
editable = self.packages()
284+
packages = packages or []
285+
selected_editables = {}
286+
for ref, info in editable.items():
287+
if packages and not any(ref.matches(p, False) for p in packages):
288+
continue
289+
selected_editables[ref] = info
290+
if not selected_editables:
291+
raise ConanException("There are no selected packages defined in the workspace")
292+
293+
return selected_editables
294+
295+
def build_order(self, packages, profile_host, profile_build, build_mode, lockfile, remotes,
296+
profile_args, update=False):
297+
ConanOutput().title(f"Computing dependency graph for each package")
298+
conan_api = self._conan_api
299+
from conan.internal.graph.install_graph import InstallGraph
300+
install_order = InstallGraph(None)
301+
302+
for ref, info in packages.items():
303+
ConanOutput().title(f"Computing the dependency graph for package: {ref}")
304+
305+
deps_graph = conan_api.graph.load_graph_requires([ref], None,
306+
profile_host, profile_build, lockfile,
307+
remotes, update)
308+
deps_graph.report_graph_error()
309+
print_graph_basic(deps_graph)
310+
conan_api.graph.analyze_binaries(deps_graph, build_mode, remotes=remotes, update=update,
311+
lockfile=lockfile)
312+
print_graph_packages(deps_graph)
313+
314+
ConanOutput().success(f"\nAggregating build-order for package: {ref}")
315+
install_graph = InstallGraph(deps_graph, order_by="recipe",
316+
profile_args=ProfileArgs.from_args(profile_args))
317+
install_graph.raise_errors()
318+
install_order.merge(install_graph)
319+
320+
return install_order

0 commit comments

Comments
 (0)