forked from conan-io/conan
/
workspace.py
136 lines (115 loc) · 5.57 KB
/
workspace.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import os
from collections import OrderedDict
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
class LocalPackage(object):
def __init__(self, base_folder, data, cache, ws_layout, ws_generators, ref):
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
layout = data.pop("layout", None)
if layout:
self.layout = get_editable_abs_path(layout, self._base_folder, cache.conan_folder)
else:
self.layout = ws_layout
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))
class Workspace(object):
def generate(self, cwd, graph, output):
if self._ws_generator == "cmake":
cmake = ""
add_subdirs = ""
for node in graph.ordered_iterate():
if node.recipe != RECIPE_EDITABLE:
continue
ref = node.ref
ws_pkg = self._workspace_packages[ref]
layout = self._cache.package_layout(ref)
editable = layout.editable_cpp_info()
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 is not None:
src = os.path.join(ws_pkg.root_folder, src).replace("\\", "/")
cmake += 'set(PACKAGE_%s_SRC "%s")\n' % (ref.name, src)
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
cmake += "endmacro()"
cmake_path = os.path.join(cwd, "conanworkspace.cmake")
save(cmake_path, cmake)
def __init__(self, path, cache):
self._cache = cache
self._ws_generator = None
self._workspace_packages = OrderedDict() # {reference: LocalPackage}
self._base_folder = os.path.dirname(path)
try:
content = load(path)
except IOError:
raise ConanException("Couldn't load workspace file in %s" % path)
try:
self._loads(content)
except Exception as e:
raise ConanException("There was an error parsing %s: %s" % (path, str(e)))
def get_editable_dict(self):
return {ref: {"path": ws_package.root_folder, "layout": ws_package.layout}
for ref, ws_package in self._workspace_packages.items()}
def __getitem__(self, ref):
return self._workspace_packages.get(ref)
@property
def root(self):
return self._root
def _loads(self, text):
yml = yaml.safe_load(text)
self._ws_generator = yml.pop("workspace_generator", None)
yml.pop("name", None)
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]
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")
editables = yml.pop("editables", {})
for ref, data in editables.items():
workspace_package = LocalPackage(self._base_folder, data,
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:
raise ConanException("Root %s is not defined as editable" % str(package_name))
if yml:
raise ConanException("Workspace unrecognized fields: %s" % yml)