Introduce precooked project
[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
47 def get_cppflags(self):
48 return " -I{}/include".format(self.installation_path)
49
50 def get_ldflags(self):
51 return " -L{}/lib".format(self.installation_path)
52
53 def get_ld_library_path(self):
54 return "{}/lib".format(self.installation_path)
55
56 def get_env(self):
57 """Modify environment to reflect dependency"""
58 cpp_flags = ""
59 ld_flags = ""
60 ld_library_path = ""
61
62 env = os.environ.copy()
63
64 for var, value in self.special_env_variables.items():
65 if var in env:
de9b991b 66 # Raise for now since no special cases is known
fe7b987e
JR
67 _logger.warning("% Special var % is already defined",
68 self.label, var)
de9b991b
JR
69 raise Exception("Multiple definition of a special environment variable")
70 else:
71 env[var] = value
72
fe7b987e 73 for key, dep in self.dependencies.items():
de9b991b
JR
74 # Extra space just in case
75 cpp_flags += " {}".format(dep.get_cppflags())
76 ld_flags += " {}".format(dep.get_ldflags())
77 ld_library_path += "{}:".format(dep.get_ld_library_path())
78 for var, value in dep.special_env_variables.items():
79 if var in env:
de9b991b 80 # Raise for now since no special cases is known
fe7b987e
JR
81 _logger.warning("% Special var % is already defined",
82 self.label, var)
de9b991b
JR
83 raise Exception("Multiple definition of a special environment variable")
84 else:
85 env[var] = value
86
de9b991b
JR
87 if cpp_flags:
88 if 'CPPFLAGS' in env:
89 cpp_flags = env['CPPFLAGS'] + cpp_flags
90 env['CPPFLAGS'] = cpp_flags
fe7b987e 91 _logger.debug("% CPPFLAGS= %s", self.label, cpp_flags)
de9b991b
JR
92 if ld_flags:
93 if 'LDFLAGS' in env:
94 ld_flags = env['LDFLAGS'] + ld_flags
95 env['LDFLAGS'] = ld_flags
fe7b987e 96 _logger.debug("% LDFLAGS= %s", self.label, ld_flags)
de9b991b
JR
97 if ld_library_path:
98 if 'LD_LIBRARY_PATH' in env:
99 ld_library_path = env['LD_LIBRARY_PATH'] + ":" + ld_library_path
100 env['LD_LIBRARY_PATH'] = ld_library_path
fe7b987e 101 _logger.debug("% LD_LIBRARY_PATH= %s", self.label, ld_library_path)
de9b991b
JR
102 return env
103
104 def autobuild(self):
105 """
106 Perform the bootstrap, configuration, build and install the
107 project. Build dependencies if not already built
108 """
fe7b987e
JR
109 if (self.isConfigured and self.isBuilt and self.isInstalled):
110 return
111
112 if self._immutable:
113 raise Exception("Object is immutable. Illegal autobuild")
114
115 for key, dep in self.dependencies.items():
de9b991b
JR
116 dep.autobuild()
117
fe7b987e 118 if self.isConfigured ^ self.isBuilt ^ self.isInstalled:
de9b991b
JR
119 raise Exception("Project steps where manually triggered. Can't autobuild")
120
fe7b987e 121 _logger.debug("% Autobuild configure", self.label)
de9b991b 122 self.configure()
fe7b987e 123 _logger.debug("% Autobuild build", self.label)
de9b991b 124 self.build()
fe7b987e 125 _logger.debug("% Autobuild install", self.label)
de9b991b
JR
126 self.install()
127
128 def checkout(self):
fe7b987e
JR
129 if self._immutable:
130 raise Exception("Object is immutable. Illegal checkout")
131
de9b991b
JR
132 repo = git.Repo.clone_from(self.git_path, self.source_path)
133 commit = repo.commit(self.sha1)
134 repo.head.reference = commit
135 assert repo.head.is_detached
136 repo.head.reset(index=True, working_tree=True)
137
138 def bootstrap(self):
139 """
140 Bootstap the project. Raise subprocess.CalledProcessError on
141 bootstrap error.
142 """
fe7b987e
JR
143 if self._immutable:
144 raise Exception("Object is immutable. Illegal bootstrap")
145
146 out = os.path.join(self.log_path, "bootstrap.out")
147 err = os.path.join(self.log_path, "bootstrap.err")
148
de9b991b 149 os.chdir(self.source_path)
fe7b987e
JR
150 with open(out, 'w') as stdout, open(err, 'w') as stderr:
151 p = subprocess.run(['./bootstrap'], stdout=stdout, stderr=stderr)
de9b991b
JR
152 p.check_returncode()
153 return p
154
155 def configure(self):
156 """
157 Configure the project.
158 Raises subprocess.CalledProcessError on configure error
159 """
fe7b987e
JR
160 if self._immutable:
161 raise Exception("Object is immutable. Illegal configure")
162
de9b991b 163 # Check that all our dependencies were actually installed
fe7b987e 164 for key, dep in self.dependencies.items():
de9b991b
JR
165 if not dep.isInstalled:
166 # TODO: Custom exception here Dependency Error
167 raise Exception("Dependency project flagged as not installed")
168
fe7b987e
JR
169 out = os.path.join(self.log_path, "configure.out")
170 err = os.path.join(self.log_path, "configure.err")
171
de9b991b
JR
172 os.chdir(self.source_path)
173 args = ['./configure']
174 prefix = '--prefix={}'.format(self.installation_path)
175 args.append(prefix)
176 args.extend(self.custom_configure_flags)
177
178 # TODO: log output and add INFO log point
fe7b987e
JR
179 with open(out, 'w') as stdout, open(err, 'w') as stderr:
180 p = subprocess.run(args, env=self.get_env(), stdout=stdout,
181 stderr=stderr)
de9b991b
JR
182 p.check_returncode()
183 self.isConfigured = True
184 return p
185
186 def build(self):
187 """
188 Build the project. Raise subprocess.CalledProcessError on build
189 error.
190 """
fe7b987e
JR
191 if self._immutable:
192 raise Exception("Object is immutable. Illegal build")
193
194 out = os.path.join(self.log_path, "build.out")
195 err = os.path.join(self.log_path, "build.err")
196
de9b991b
JR
197 os.chdir(self.source_path)
198 args = ['make']
199 env = self.get_env()
200 env['CFLAGS'] = '-g -O0'
201
202 # Number of usable cpu
203 # https://docs.python.org/3/library/os.html#os.cpu_count
204 num_cpu = str(len(os.sched_getaffinity(0)))
205 args.append('-j')
206 args.append(num_cpu)
207
208 # TODO: log output and add INFO log point with args
fe7b987e
JR
209 with open(out, 'w') as stdout, open(err, 'w') as stderr:
210 p = subprocess.run(args, env=env, stdout=stdout,
211 stderr=stderr)
de9b991b
JR
212 p.check_returncode()
213 self.isBuilt = True
214 return p
215
216 def install(self):
217 """
218 Install the project. Raise subprocess.CalledProcessError on
219 bootstrap error
220 """
fe7b987e
JR
221 if self._immutable:
222 raise Exception("Object is immutable. Illegal install")
223
224 out = os.path.join(self.log_path, "build.out")
225 err = os.path.join(self.log_path, "build.err")
226
de9b991b
JR
227 os.chdir(self.source_path)
228 args = ['make', 'install']
229
230 # TODO: log output and add INFO log point
fe7b987e
JR
231 with open(out, 'w') as stdout, open(err, 'w') as stderr:
232 p = subprocess.run(args, env=self.get_env(), stdout=stdout,
233 stderr=stderr)
de9b991b
JR
234 p.check_returncode()
235 self.isInstalled = True
236 return p
237
238 def cleanup(self):
239 if os.path.exists(self.source_path):
240 shutil.rmtree(self.source_path)
241 if os.path.exists(self.installation_path):
242 shutil.rmtree(self.installation_path)
243
244
245class Lttng_modules(Project):
246 def bootstrap(self):
247 pass
248
249 def configure(self):
250 pass
251
252 def install(self):
fe7b987e
JR
253 if self._immutable:
254 raise Exception("Object is immutable. Illegal install")
de9b991b
JR
255 os.chdir(self.source_path)
256 args = ['make', 'INSTALL_MOD_PATH={}'.format(self.installation_path),
257 'modules_install']
258 p = subprocess.run(args, env=self.get_env(), stdout=subprocess.PIPE,
259 stderr=subprocess.PIPE)
260 p.check_returncode()
261
262 # Perform a local depmod
263 args = ['depmod', '-b', self.installation_path]
264 p = subprocess.run(args, env=self.get_env())
265 p.check_returncode()
266 self.isInstalled = True
267
268
269class Lttng_ust(Project):
270 def __init__(self, label, git_path, sha1, tmpdir):
271 super(Lttng_ust, self).__init__(label=label, git_path=git_path,
272 sha1=sha1, tmpdir=tmpdir)
273 self.custom_configure_flags.extend(['--disable-man-pages'])
274
275
276class Lttng_tools(Project):
277 pass
278
279
280class Babeltrace(Project):
281 pass
This page took 0.033502 seconds and 5 git commands to generate.