proxygen
shell_builder.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 # Copyright (c) Facebook, Inc. and its affiliates.
3 from __future__ import absolute_import
4 from __future__ import division
5 from __future__ import print_function
6 from __future__ import unicode_literals
7 
8 '''
9 shell_builder.py allows running the fbcode_builder logic
10 on the host rather than in a container.
11 
12 It emits a bash script with set -exo pipefail configured such that
13 any failing step will cause the script to exit with failure.
14 
15 == How to run it? ==
16 
17 cd build
18 python fbcode_builder/shell_builder.py > ~/run.sh
19 bash ~/run.sh
20 '''
21 
22 import os
23 import distutils.spawn
24 
25 from fbcode_builder import FBCodeBuilder
26 from shell_quoting import (
27  raw_shell, shell_comment, shell_join, ShellQuoted
28 )
29 from utils import recursively_flatten_list
30 
31 
32 class ShellFBCodeBuilder(FBCodeBuilder):
33  def _render_impl(self, steps):
34  return raw_shell(shell_join('\n', recursively_flatten_list(steps)))
35 
36  def workdir(self, dir):
37  return [
38  ShellQuoted('mkdir -p {d} && cd {d}').format(
39  d=dir
40  ),
41  ]
42 
43  def run(self, shell_cmd):
44  return ShellQuoted('{cmd}').format(cmd=shell_cmd)
45 
46  def step(self, name, actions):
47  assert '\n' not in name, 'Name {0} would span > 1 line'.format(name)
48  b = ShellQuoted('')
49  return [ShellQuoted('### {0} ###'.format(name)), b] + actions + [b]
50 
51  def setup(self):
52  steps = [
53  ShellQuoted('set -exo pipefail'),
54  ]
55  if self.has_option('ccache_dir'):
56  ccache_dir = self.option('ccache_dir')
57  steps += [
58  ShellQuoted(
59  # Set CCACHE_DIR before the `ccache` invocations below.
60  'export CCACHE_DIR={ccache_dir} '
61  'CC="ccache ${{CC:-gcc}}" CXX="ccache ${{CXX:-g++}}"'
62  ).format(ccache_dir=ccache_dir)
63  ]
64  return steps
65 
66  def comment(self, comment):
67  return shell_comment(comment)
68 
69  def copy_local_repo(self, dir, dest_name):
70  return [
71  ShellQuoted('cp -r {dir} {dest_name}').format(
72  dir=dir,
73  dest_name=dest_name
74  ),
75  ]
76 
77 
78 def find_project_root():
79  here = os.path.dirname(os.path.realpath(__file__))
80  maybe_root = os.path.dirname(os.path.dirname(here))
81  if os.path.isdir(os.path.join(maybe_root, '.git')):
82  return maybe_root
83  raise RuntimeError(
84  "I expected shell_builder.py to be in the "
85  "build/fbcode_builder subdir of a git repo")
86 
87 
88 def persistent_temp_dir(repo_root):
89  escaped = repo_root.replace('/', 'sZs').replace('\\', 'sZs').replace(':', '')
90  return os.path.join(os.path.expandvars("$HOME"), '.fbcode_builder-' + escaped)
91 
92 
93 if __name__ == '__main__':
94  from utils import read_fbcode_builder_config, build_fbcode_builder_config
95  repo_root = find_project_root()
96  temp = persistent_temp_dir(repo_root)
97 
98  config = read_fbcode_builder_config('fbcode_builder_config.py')
99  builder = ShellFBCodeBuilder()
100 
101  builder.add_option('projects_dir', temp)
102  if distutils.spawn.find_executable('ccache'):
103  builder.add_option('ccache_dir',
104  os.environ.get('CCACHE_DIR', os.path.join(temp, '.ccache')))
105  builder.add_option('prefix', os.path.join(temp, 'installed'))
106  builder.add_option('make_parallelism', 4)
107  builder.add_option(
108  '{project}:local_repo_dir'.format(project=config['github_project']),
109  repo_root)
110  make_steps = build_fbcode_builder_config(config)
111  steps = make_steps(builder)
112  print(builder.render(steps))
def raw_shell(s)
def step(self, name, actions)
void BENCHFUN() replace(size_t iters, size_t arg)
def recursively_flatten_list(l)
Definition: utils.py:19
def persistent_temp_dir(repo_root)
def find_project_root()
def shell_comment(c)
def build_fbcode_builder_config(config)
Definition: utils.py:93
def read_fbcode_builder_config(filename)
Definition: utils.py:55
Formatter< false, Args... > format(StringPiece fmt, Args &&...args)
Definition: Format.h:271
def option(self, name, default=None)
def copy_local_repo(self, dir, dest_name)
def shell_join(delim, it)