3 from __future__
import absolute_import
4 from __future__
import division
5 from __future__
import print_function
6 from __future__
import unicode_literals
9 This is a small DSL to describe builds of Facebook's open-source projects 10 that are published to Github from a single internal repo, including projects 11 that depend on folly, wangle, proxygen, fbthrift, etc. 13 This file defines the interface of the DSL, and common utilieis, but you 14 will have to instantiate a specific builder, with specific options, in 15 order to get work done -- see e.g. make_docker_context.py. 21 - A simple declarative language for what needs to be checked out & built, 24 - The same specification should work for external continuous integration 25 builds (e.g. Travis + Docker) and for internal VM-based continuous 28 - One should be able to build without root, and to install to a prefix. 32 - General usefulness. The only point of this is to make it easier to build 33 and test Facebook's open-source services. 35 Ideas for the future -- these may not be very good :) 37 - Especially on Ubuntu 14.04 the current initial setup is inefficient: 38 we add PPAs after having installed a bunch of packages -- this prompts 39 reinstalls of large amounts of code. We also `apt-get update` a few 42 - A "shell script" builder. Like DockerFBCodeBuilder, but outputs a 43 shell script that runs outside of a container. Or maybe even 44 synchronously executes the shell commands, `make`-style. 46 - A "Makefile" generator. That might make iterating on builds even quicker 47 than what you can currently get with Docker build caching. 49 - Generate a rebuild script that can be run e.g. inside the built Docker 50 container by tagging certain steps with list-inheriting Python objects: 51 * do change directories 52 * do NOT `git clone` -- if we want to update code this should be a 53 separate script that e.g. runs rebase on top of specific targets 55 * do NOT install software (most / all setup can be skipped) 56 * do NOT `autoreconf` or `configure` 57 * do `make` and `cmake` 59 - If we get non-Debian OSes, part of ccache setup should be factored out. 65 from shell_quoting
import path_join, shell_join, ShellQuoted
69 base_dir =
'deps/github_hashes/' 70 for dirname, _, files
in os.walk(base_dir):
71 for filename
in files:
72 path = os.path.join(dirname, filename)
74 m_proj = re.match(
'^' + base_dir +
'(.*)-rev\.txt$', path)
76 raise RuntimeError(
'Not a hash file? {0}'.
format(path))
77 m_hash = re.match(
'^Subproject commit ([0-9a-f]+)\n$', f.read())
79 raise RuntimeError(
'No hash in {0}'.
format(path))
80 yield m_proj.group(1), m_hash.group(1)
83 class FBCodeBuilder(
object):
94 self.__class__.__name__,
96 '{0}={1}'.
format(k, repr(v))
97 for k, v
in self._options_do_not_access.items()
102 value = self._options_do_not_access.get(name, default)
104 raise RuntimeError(
'Option {0} is required'.
format(name))
105 self.options_used.add(name)
113 raise RuntimeError(
'Option {0} already set'.
format(name))
123 Converts nested actions to your builder's expected output format. 124 Typically takes the output of build(). 127 res = self._render_impl(steps)
134 'Unused options: {0} -- please check if you made a typo ' 135 'in any of them. Those that are truly not useful should ' 136 'be not be set so that this typo detection can be useful.' 143 raise RuntimeError(
'Please ensure that the config you are passing ' 148 'Your builder may want to install packages here.' 149 raise NotImplementedError
152 'Log some system diagnostics before/after setup for ease of debugging' 155 return self.
step(
'Diagnostics', [
156 self.comment(
'Builder {0}'.
format(repr(self))),
160 self.
run(
ShellQuoted(
'cmake --version || echo cmake not installed')),
164 'A labeled collection of actions or other steps' 165 raise NotImplementedError
168 'Run this bash command' 169 raise NotImplementedError
172 'Create this directory if it does not exist, and change into it' 173 raise NotImplementedError
177 Copy the local repo at `dir` into this step's `workdir()`, analog of: 178 cp -r /path/to/folly folly 180 raise NotImplementedError
195 'libdouble-conversion-dev',
198 'libgoogle-glog-dev',
201 'libpthread-stubs0-dev',
227 gcc_version = self.
option(
'gcc_version')
236 'update-alternatives --install /usr/bin/gcc gcc {c} 40 ' 237 '--slave /usr/bin/g++ g++ {cpp}' 247 return self.
step(
'Install packages for Debian-based OS', actions)
256 '{0}:git_hash'.
format(project),
259 self._github_hashes.get(project,
'')
261 maybe_change_branch = [
263 ]
if git_hash
else []
265 base_dir = self.
option(
'projects_dir')
267 local_repo_dir = self.
option(
'{0}:local_repo_dir'.
format(project),
'')
268 return self.
step(
'Check out {0}, workdir {1}'.
format(project, path), [
273 local_repo_dir, os.path.basename(project)
276 ] + maybe_change_branch)
279 'This helper lets Facebook-internal CI special-cases FB projects' 280 project, path = project_and_path.split(
'/', 1)
286 for k, v
in ({}
if make_vars
is None else make_vars).items()
291 n=self.
option(
'make_parallelism'),
304 autoconf_options = {}
306 autoconf_options.update(
311 'LDFLAGS="$LDFLAGS -L"{p}"/lib -Wl,-rpath="{p}"/lib" ' 312 'CFLAGS="$CFLAGS -I"{p}"/include" ' 313 'CPPFLAGS="$CPPFLAGS -I"{p}"/include" ' 315 './configure --prefix={p} {args}' 320 for k, v
in autoconf_options.items()
326 return self.
step(
'Build and install {0}'.
format(name), [
332 'BUILD_SHARED_LIBS':
'ON',
333 'CMAKE_INSTALL_PREFIX': self.
option(
'prefix'),
335 cmake_defines.update(
340 'CXXFLAGS="$CXXFLAGS -fPIC -isystem "{p}"/include" ' 341 'CFLAGS="$CFLAGS -fPIC -isystem "{p}"/include" ' 342 'cmake {args} {cmake_path}' 347 for k, v
in cmake_defines.items()
349 cmake_path=cmake_path,
355 'Build and install {0}'.
format(name),
def fb_github_project_workdir(self, project_and_path, github_org='facebook')
def debian_ccache_setup_steps(self)
def __init__(self, kwargs)
def add_option(self, name, value)
def fb_github_cmake_install(self, project_and_path, cmake_path='..', github_org='facebook')
def has_option(self, name)
def configure(self, name=None)
def copy_local_repo(self, dir, dest_name)
def github_project_workdir(self, project, path)
def cmake_install(self, name, cmake_path='..')
def _make_vars(self, make_vars)
def install_debian_deps(self)
def step(self, name, actions)
Formatter< false, Args... > format(StringPiece fmt, Args &&...args)
def fb_github_autoconf_install(self, project_and_path, github_org='facebook')
def _read_project_github_hashes()
def autoconf_install(self, name)
def option(self, name, default=None)
def make_and_install(self, make_vars=None)
def cmake_configure(self, name, cmake_path='..')
def parallel_make(self, make_vars=None)
def shell_join(delim, it)