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