if ccache is not None:
self.custom_configure_flags.append("CC={} gcc".format(ccache))
self.custom_configure_flags.append("CXX={} g++".format(ccache))
+ self.custom_configure_flags.append("CFLAGS=-g -O0".format(ccache))
""" A collection of Project dependencies """
self.dependencies = {}
self.source_path = os.path.join(tmpdir, "source")
self.installation_path = os.path.join(tmpdir, "install")
+ if os.path.isdir(self.basedir):
+ # Perform cleanup since it should not happen
+ shutil.rmtree(self.basedir)
+
os.makedirs(self.log_path)
os.makedirs(self.source_path)
os.makedirs(self.installation_path)
if self.isConfigured ^ self.isBuilt ^ self.isInstalled:
raise Exception("Project steps where manually triggered. Can't autobuild")
- _logger.debug("% Autobuild configure", self.label)
- self.configure()
- _logger.debug("% Autobuild build", self.label)
- self.build()
- _logger.debug("% Autobuild install", self.label)
- self.install()
+ _logger.debug("{} Autobuild configure".format(self.label))
+ try:
+ self.configure()
+ except subprocess.CalledProcessError as e:
+ _logger.error("{} Configure failed. See {} for more details.".format(self.label, self.log_path))
+ raise e
+
+ _logger.debug("{} Autobuild build".format(self.label))
+ try:
+ self.build()
+ except subprocess.CalledProcessError as e:
+ _logger.error("{} Build failed. See {} for more details.".format(self.label, self.log_path))
+ raise e
+
+ _logger.debug("{} Autobuild install".format(self.label))
+ try:
+ self.install()
+ except subprocess.CalledProcessError as e:
+ _logger.error("{} Install failed. See {} for more details.".format(self.label, self.log_path))
+ raise e
def checkout(self):
if self._immutable:
os.chdir(self.source_path)
args = ['make']
env = self.get_env()
- env['CFLAGS'] = '-g -O0'
# Number of usable cpu
# https://docs.python.org/3/library/os.html#os.cpu_count
num_cpu = str(len(os.sched_getaffinity(0)))
args.append('-j')
args.append(num_cpu)
+ args.append('V=1')
# TODO: log output and add INFO log point with args
with open(out, 'w') as stdout, open(err, 'w') as stderr:
if self._immutable:
raise Exception("Object is immutable. Illegal install")
- out = os.path.join(self.log_path, "build.out")
- err = os.path.join(self.log_path, "build.err")
+ out = os.path.join(self.log_path, "install.out")
+ err = os.path.join(self.log_path, "install.err")
os.chdir(self.source_path)
args = ['make', 'install']
class Lttng_modules(Project):
+ def __init__(self, label, git_path, sha1, tmpdir):
+ super(Lttng_modules, self).__init__(label=label, git_path=git_path,
+ sha1=sha1, tmpdir=tmpdir)
+ self.add_special_env_variable("MODPROBE_OPTIONS","-b {}".format(self.installation_path))
+
def bootstrap(self):
pass
import os
+import sys
import shlex
import subprocess
import uuid
import logging
+import shutil
+import contextlib
+import pprint
+import traceback
+from tempfile import TemporaryDirectory
+
+import lttng_ivc.settings as Settings
_logger = logging.getLogger("Runtime")
+@contextlib.contextmanager
+def get_runtime(runtime_dir):
+ runtime = Runtime(runtime_dir)
+ try:
+ yield runtime
+ finally:
+ runtime.close()
+
+
class Runtime(object):
def __init__(self, runtime_dir):
"""
self.__runtime_log = os.path.join(runtime_dir, "log")
self.__runtime_log_sub = os.path.join(self.__runtime_log, "subprocess")
+ """
+ Path of the copy of lttng_home folder after Runtime.close() is issued. This is
+ to be used for post runtime analysis and mostly debugging on error.
+ """
+ self.__post_runtime_lttng_home_path = os.path.join(runtime_dir,
+ "lttng_home")
+
self._runtime_log_aggregation = os.path.join(self.__runtime_log, "runtime.log")
self._run_command_count = 0
- self.lttng_home = os.path.join(runtime_dir, "lttng_home")
+ self.special_env_variables = {"LTTNG_UST_DEBUG": "1",
+ #"LTTNG_APP_SOCKET_TIMEOUT": "-1",
+ #"LTTNG_UST_REGISTER_TIMEOUT": "-1",
+ "LTTNG_NETWORK_SOCKET_TIMEOUT": "-1"}
- # TODO move exist_ok to false !!!! ONLY for testing
- os.makedirs(self.__runtime_log, exist_ok=True)
- os.makedirs(self.__runtime_log_sub, exist_ok=True)
- os.makedirs(self.lttng_home, exist_ok=True)
+ # Keep a reference on the object to keep it alive. It will close/clean on
+ # exit.
+ self.__lttng_home_dir = TemporaryDirectory(prefix=Settings.tmp_object_prefix)
+ self.lttng_home = self.__lttng_home_dir.name
+
+ if len(self.lttng_home) > 88:
+ raise Exception("TemporaryDirectory for lttng_home is to long. Use a short TMPDIR")
+
+ os.makedirs(self.__runtime_log)
+ os.makedirs(self.__runtime_log_sub)
def add_project(self, project):
self.__projects.append(project)
stdout, stderr = self.__stdout_stderr[subprocess_uuid]
stdout.close()
stderr.close()
+ return process
def subprocess_kill(self, subprocess_uuid):
process = self.__subprocess[subprocess_uuid]
stdout, stderr = self.__stdout_stderr[subprocess_uuid]
stdout.close()
stderr.close()
+ return process
def get_subprocess_stdout_path(self, subprocess_uuid):
stdout, stderr = self.__stdout_stderr[subprocess_uuid]
stdout, stderr = self.__stdout_stderr[subprocess_uuid]
return stderr.name
- def spawn_subprocess(self, command_line):
+ def spawn_subprocess(self, command_line, cwd=None):
args = shlex.split(command_line)
env = self.get_env()
+ if not os.path.isdir(self.lttng_home):
+ raise Exception("lttng home does not exist")
+
tmp_id = uuid.uuid1()
out_path = os.path.join(self.__runtime_log_sub, str(tmp_id) + ".out")
err_path = os.path.join(self.__runtime_log_sub, str(tmp_id) + ".err")
- stdout = open(out_path, "w")
- stderr = open(err_path, "w")
+
+ stdout = open(out_path, 'w')
+ stderr = open(err_path, 'w')
+
+ env_path = os.path.join(self.__runtime_log_sub, str(tmp_id) + ".env")
+ with open(env_path, 'w') as env_out:
+ pprint.pprint(env, stream=env_out)
p = subprocess.Popen(args, stdout=stdout, stderr=stderr, env=env)
self.__subprocess[tmp_id] = p
self.__stdout_stderr[tmp_id] = (stdout, stderr)
_logger.debug("Spawned sub pid: {} args: {} stdout: {} stderr{}".format(p.pid, p.args, out_path, err_path))
+ return tmp_id
- def run(self, command_line):
+ def run(self, command_line, cwd=None, check_return=True):
"""
Run the command and return a tuple of a (CompletedProcess, stdout_path,
stderr_path). The subprocess is already executed and returned. The
tmp_id = self._run_command_count
self._run_command_count += 1
+ cmd_map = os.path.join(self.__runtime_log, "cmd.map")
+ with open(cmd_map, 'a') as out:
+ out.write("{}: {}\n".format(tmp_id, args))
+
out_path = os.path.join(self.__runtime_log, str(tmp_id) + ".out")
err_path = os.path.join(self.__runtime_log, str(tmp_id) + ".err")
stdout = open(out_path, "w")
stderr = open(err_path, "w")
- stdout.write("Output for command #{} {}\n".format(tmp_id, command_line))
- stdout.write("Start >>>>>>>>>>>>>>>>\n")
- stdout.flush()
-
- stderr.write("Output for command #{} {}\n".format(tmp_id, command_line))
- stderr.write("Start >>>>>>>>>>>>>>>>\n")
- stderr.flush()
+ env_path = os.path.join(self.__runtime_log, str(tmp_id) + ".env")
+ with open(env_path, 'w') as env_out:
+ pprint.pprint(env, stream=env_out)
- cp = subprocess.run(args, stdout=stdout, stderr=stderr, env=env)
+ cp = subprocess.run(args, stdout=stdout, stderr=stderr, env=env, cwd=cwd)
_logger.debug("Command #{} args: {} stdout: {} stderr{}".format(tmp_id, cp.args, out_path, err_path))
- stdout.write("End <<<<<<<<<<<<<<<<\n")
- stdout.close()
-
- stderr.write("End <<<<<<<<<<<<<<<<\n")
- stderr.close()
-
# Add to the global log file. This can help a little. Leave the other
# file available for per-run analysis
with open(self._runtime_log_aggregation, "a") as log:
with open(out_path, "r") as out:
+ log.write("Output for command #{} {}\n".format(tmp_id, command_line))
+ log.write("Start >>>>>>>>>>>>>>>>\n")
log.write(out.read())
+ log.write("End <<<<<<<<<<<<<<<<\n")
with open(err_path, "r") as out:
+ log.write("Error for command #{} {}\n".format(tmp_id, command_line))
+ log.write("Start >>>>>>>>>>>>>>>>\n")
log.write(out.read())
+ log.write("End <<<<<<<<<<<<<<<<\n")
+
+ if check_return:
+ cp.check_returncode()
return (cp, out_path, err_path)
env_fetch = {"CPPFLAGS": (self.get_cppflags(), " "),
"LDFLAGS": (self.get_ldflags(), " "),
- "LD_LIRABRY_PATH": (self.get_ld_library_path(), ":"),
+ "LD_LIBRARY_PATH": (self.get_ld_library_path(), ":"),
"PATH": (self.get_bin_path(), ":"),
}
for key, (value, delimiter) in env_fetch.items():
tmp_var = env[key]
env[key] = delimiter.join([value, tmp_var])
+ for var, value in self.special_env_variables.items():
+ if var in env:
+ # Raise for now since no special cases is known
+ _logger.warning("% Special var % is already defined",
+ self.label, var)
+ raise Exception("Multiple definition of a special environment variable")
+ else:
+ env[var] = value
+
for project in self.__projects:
for var, value in project.special_env_variables.items():
if var in env:
for key, subp in self.__subprocess.items():
subp.terminate()
for key, subp in self.__subprocess.items():
- try:
- # TODO move timeout to settings
- subp.wait(timeout=60)
- except subprocess.TimeoutExpired as e:
- # Force a little bit
- subp.kill()
- subp.wait()
+ # TODO move timeout to settings
+ subp.wait(timeout=60)
for key, (stdout, stderr) in self.__stdout_stderr.items():
stdout.close()
stderr.close()
+
+ # Copy the lttng_home used at runtime using hardlink to prevent useless
+ # data duplication
+ shutil.copytree(self.lttng_home, self.__post_runtime_lttng_home_path, copy_function=os.link)
+