Implement Runtime wrapper
[deliverable/lttng-ivc.git] / lttng_ivc / utils / project.py
CommitLineData
de9b991b
JR
1import os
2import shutil
3import git
4import subprocess
5import logging
6
fe7b987e 7_logger = logging.getLogger('project')
de9b991b
JR
8
9class Project(object):
10
11 def __init__(self, label, git_path, sha1, tmpdir):
12 self.label = label
13 self.git_path = git_path
14 self.sha1 = sha1
15
16 """ Custom configure flags in the for of ['-x', 'arg']"""
17 self.custom_configure_flags = []
18 ccache = shutil.which("ccache")
19 if ccache is not None:
20 self.custom_configure_flags.append("CC={} gcc".format(ccache))
21 self.custom_configure_flags.append("CXX={} g++".format(ccache))
22
23 """ A collection of Project dependencies """
fe7b987e
JR
24 self.dependencies = {}
25 self._immutable = False
de9b991b
JR
26
27 # State
de9b991b
JR
28 self.isBuilt = False
29 self.isConfigured = False
30 self.isInstalled = False
31
fe7b987e
JR
32 self.basedir = tmpdir
33 self.log_path = os.path.join(tmpdir, "log")
34 self.source_path = os.path.join(tmpdir, "source")
35 self.installation_path = os.path.join(tmpdir, "install")
36
37 os.makedirs(self.log_path)
de9b991b
JR
38 os.makedirs(self.source_path)
39 os.makedirs(self.installation_path)
de9b991b
JR
40
41 self.special_env_variables = {}
42
43 # Init the repo for work
44 self.checkout()
45 self.bootstrap()
46
18aedaf9
JR
47 def add_special_env_variable(self, key, value):
48 if key in self.special_env_variables:
49 _logger.warning("{} Special var {} is already defined".format(
50 self.label, key))
51 raise Exception("Multiple definition of a special environment variable")
52 self.special_env_variables[key] = value
53
de9b991b 54 def get_cppflags(self):
18aedaf9
JR
55 cppflags = ["-I{}/include".format(self.installation_path)]
56 for key, dep in self.dependencies.items():
57 cppflags.append(dep.get_cppflags())
58
59 return " ".join(cppflags)
de9b991b
JR
60
61 def get_ldflags(self):
18aedaf9
JR
62 ldflags = ["-L{}/lib".format(self.installation_path)]
63 for key, dep in self.dependencies.items():
64 ldflags.append(dep.get_ldflags())
65 return " ".join(ldflags)
de9b991b
JR
66
67 def get_ld_library_path(self):
18aedaf9
JR
68 library_path = ["{}/lib".format(self.installation_path)]
69 for key, dep in self.dependencies.items():
70 library_path.append(dep.get_ld_library_path())
71 return ":".join(library_path)
72
73 def get_bin_path(self):
74 bin_path = ["{}/bin".format(self.installation_path)]
75 for key, dep in self.dependencies.items():
76 bin_path.append(dep.get_bin_path())
77 return ":".join(bin_path)
de9b991b
JR
78
79 def get_env(self):
80 """Modify environment to reflect dependency"""
18aedaf9
JR
81 env_var = {"CPPFLAGS": (self.get_cppflags(), " "),
82 "LDFLAGS": (self.get_ldflags(), " "),
83 "LD_LIBRARY_PATH": (self.get_ld_library_path(), ":"),
84 }
de9b991b
JR
85
86 env = os.environ.copy()
87
88 for var, value in self.special_env_variables.items():
89 if var in env:
de9b991b 90 # Raise for now since no special cases is known
18aedaf9
JR
91 _logger.warning("{} Special var {} is already defined".format(
92 self.label, var))
de9b991b
JR
93 raise Exception("Multiple definition of a special environment variable")
94 else:
95 env[var] = value
96
fe7b987e 97 for key, dep in self.dependencies.items():
de9b991b 98 # Extra space just in case
de9b991b
JR
99 for var, value in dep.special_env_variables.items():
100 if var in env:
de9b991b 101 # Raise for now since no special cases is known
18aedaf9
JR
102 _logger.warning("{} Special var {} is already defined".format(
103 self.label, var))
de9b991b
JR
104 raise Exception("Multiple definition of a special environment variable")
105 else:
106 env[var] = value
107
18aedaf9
JR
108 for var, (value, delimiter) in env_var.items():
109 tmp = [value]
110 if var in env:
111 tmp.append(env[var])
112 env[var] = delimiter.join(tmp)
113
de9b991b
JR
114 return env
115
116 def autobuild(self):
117 """
118 Perform the bootstrap, configuration, build and install the
119 project. Build dependencies if not already built
120 """
fe7b987e
JR
121 if (self.isConfigured and self.isBuilt and self.isInstalled):
122 return
123
124 if self._immutable:
125 raise Exception("Object is immutable. Illegal autobuild")
126
127 for key, dep in self.dependencies.items():
de9b991b
JR
128 dep.autobuild()
129
fe7b987e 130 if self.isConfigured ^ self.isBuilt ^ self.isInstalled:
de9b991b
JR
131 raise Exception("Project steps where manually triggered. Can't autobuild")
132
fe7b987e 133 _logger.debug("% Autobuild configure", self.label)
de9b991b 134 self.configure()
fe7b987e 135 _logger.debug("% Autobuild build", self.label)
de9b991b 136 self.build()
fe7b987e 137 _logger.debug("% Autobuild install", self.label)
de9b991b
JR
138 self.install()
139
140 def checkout(self):
fe7b987e
JR
141 if self._immutable:
142 raise Exception("Object is immutable. Illegal checkout")
143
de9b991b
JR
144 repo = git.Repo.clone_from(self.git_path, self.source_path)
145 commit = repo.commit(self.sha1)
146 repo.head.reference = commit
147 assert repo.head.is_detached
148 repo.head.reset(index=True, working_tree=True)
149
150 def bootstrap(self):
151 """
152 Bootstap the project. Raise subprocess.CalledProcessError on
153 bootstrap error.
154 """
fe7b987e
JR
155 if self._immutable:
156 raise Exception("Object is immutable. Illegal bootstrap")
157
158 out = os.path.join(self.log_path, "bootstrap.out")
159 err = os.path.join(self.log_path, "bootstrap.err")
160
de9b991b 161 os.chdir(self.source_path)
fe7b987e
JR
162 with open(out, 'w') as stdout, open(err, 'w') as stderr:
163 p = subprocess.run(['./bootstrap'], stdout=stdout, stderr=stderr)
de9b991b
JR
164 p.check_returncode()
165 return p
166
167 def configure(self):
168 """
169 Configure the project.
170 Raises subprocess.CalledProcessError on configure error
171 """
fe7b987e
JR
172 if self._immutable:
173 raise Exception("Object is immutable. Illegal configure")
174
de9b991b 175 # Check that all our dependencies were actually installed
fe7b987e 176 for key, dep in self.dependencies.items():
de9b991b
JR
177 if not dep.isInstalled:
178 # TODO: Custom exception here Dependency Error
179 raise Exception("Dependency project flagged as not installed")
180
fe7b987e
JR
181 out = os.path.join(self.log_path, "configure.out")
182 err = os.path.join(self.log_path, "configure.err")
183
de9b991b
JR
184 os.chdir(self.source_path)
185 args = ['./configure']
186 prefix = '--prefix={}'.format(self.installation_path)
187 args.append(prefix)
188 args.extend(self.custom_configure_flags)
189
190 # TODO: log output and add INFO log point
fe7b987e
JR
191 with open(out, 'w') as stdout, open(err, 'w') as stderr:
192 p = subprocess.run(args, env=self.get_env(), stdout=stdout,
193 stderr=stderr)
de9b991b
JR
194 p.check_returncode()
195 self.isConfigured = True
196 return p
197
198 def build(self):
199 """
200 Build the project. Raise subprocess.CalledProcessError on build
201 error.
202 """
fe7b987e
JR
203 if self._immutable:
204 raise Exception("Object is immutable. Illegal build")
205
206 out = os.path.join(self.log_path, "build.out")
207 err = os.path.join(self.log_path, "build.err")
208
de9b991b
JR
209 os.chdir(self.source_path)
210 args = ['make']
211 env = self.get_env()
212 env['CFLAGS'] = '-g -O0'
213
214 # Number of usable cpu
215 # https://docs.python.org/3/library/os.html#os.cpu_count
216 num_cpu = str(len(os.sched_getaffinity(0)))
217 args.append('-j')
218 args.append(num_cpu)
219
220 # TODO: log output and add INFO log point with args
fe7b987e
JR
221 with open(out, 'w') as stdout, open(err, 'w') as stderr:
222 p = subprocess.run(args, env=env, stdout=stdout,
223 stderr=stderr)
de9b991b
JR
224 p.check_returncode()
225 self.isBuilt = True
226 return p
227
228 def install(self):
229 """
230 Install the project. Raise subprocess.CalledProcessError on
231 bootstrap error
232 """
fe7b987e
JR
233 if self._immutable:
234 raise Exception("Object is immutable. Illegal install")
235
236 out = os.path.join(self.log_path, "build.out")
237 err = os.path.join(self.log_path, "build.err")
238
de9b991b
JR
239 os.chdir(self.source_path)
240 args = ['make', 'install']
241
242 # TODO: log output and add INFO log point
fe7b987e
JR
243 with open(out, 'w') as stdout, open(err, 'w') as stderr:
244 p = subprocess.run(args, env=self.get_env(), stdout=stdout,
245 stderr=stderr)
de9b991b
JR
246 p.check_returncode()
247 self.isInstalled = True
248 return p
249
250 def cleanup(self):
251 if os.path.exists(self.source_path):
252 shutil.rmtree(self.source_path)
253 if os.path.exists(self.installation_path):
254 shutil.rmtree(self.installation_path)
255
256
257class Lttng_modules(Project):
258 def bootstrap(self):
259 pass
260
261 def configure(self):
262 pass
263
264 def install(self):
fe7b987e
JR
265 if self._immutable:
266 raise Exception("Object is immutable. Illegal install")
de9b991b
JR
267 os.chdir(self.source_path)
268 args = ['make', 'INSTALL_MOD_PATH={}'.format(self.installation_path),
269 'modules_install']
270 p = subprocess.run(args, env=self.get_env(), stdout=subprocess.PIPE,
271 stderr=subprocess.PIPE)
272 p.check_returncode()
273
274 # Perform a local depmod
275 args = ['depmod', '-b', self.installation_path]
276 p = subprocess.run(args, env=self.get_env())
277 p.check_returncode()
278 self.isInstalled = True
279
280
281class Lttng_ust(Project):
282 def __init__(self, label, git_path, sha1, tmpdir):
283 super(Lttng_ust, self).__init__(label=label, git_path=git_path,
284 sha1=sha1, tmpdir=tmpdir)
285 self.custom_configure_flags.extend(['--disable-man-pages'])
286
287
288class Lttng_tools(Project):
18aedaf9
JR
289 def __init__(self, label, git_path, sha1, tmpdir):
290 super(Lttng_tools, self).__init__(label=label, git_path=git_path,
291 sha1=sha1, tmpdir=tmpdir)
292 self.add_special_env_variable("LTTNG_SESSION_CONFIG_XSD_PATH",
293 os.path.join(self.installation_path, "share/xml/lttng/"))
de9b991b
JR
294
295
296class Babeltrace(Project):
297 pass
This page took 0.035537 seconds and 5 git commands to generate.