proxygen
make_docker_context.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 Reads `fbcode_builder_config.py` from the current directory, and prepares a
9 Docker context directory to build this project. Prints to stdout the path
10 to the context directory.
11 
12 Try `.../make_docker_context.py --help` from a project's `build/` directory.
13 
14 By default, the Docker context directory will be in /tmp. It will always
15 contain a Dockerfile, and might also contain copies of your local repos, and
16 other data needed for the build container.
17 '''
18 
19 import os
20 import tempfile
21 import textwrap
22 
23 from docker_builder import DockerFBCodeBuilder
24 from parse_args import parse_args_to_fbcode_builder_opts
25 
26 
28  get_steps_fn, github_project, opts=None, default_context_dir=None
29 ):
30  '''
31  Returns a path to the Docker context directory. See parse_args.py.
32 
33  Helper for making a command-line utility that writes your project's
34  Dockerfile and associated data into a (temporary) directory. Your main
35  program might look something like this:
36 
37  print(make_docker_context(
38  lambda builder: [builder.step(...), ...],
39  'facebook/your_project',
40  ))
41  '''
42 
43  if opts is None:
44  opts = {}
45 
46  valid_versions = (
47  ('ubuntu:16.04', '5'),
48  )
49 
50  def add_args(parser):
51  parser.add_argument(
52  '--docker-context-dir', metavar='DIR',
53  default=default_context_dir,
54  help='Write the Dockerfile and its context into this directory. '
55  'If empty, make a temporary directory. Default: %(default)s.',
56  )
57  parser.add_argument(
58  '--user', metavar='NAME', default=opts.get('user', 'nobody'),
59  help='Build and install as this user. Default: %(default)s.',
60  )
61  parser.add_argument(
62  '--prefix', metavar='DIR',
63  default=opts.get('prefix', '/home/install'),
64  help='Install all libraries in this prefix. Default: %(default)s.',
65  )
66  parser.add_argument(
67  '--projects-dir', metavar='DIR',
68  default=opts.get('projects_dir', '/home'),
69  help='Place project code directories here. Default: %(default)s.',
70  )
71  parser.add_argument(
72  '--os-image', metavar='IMG', choices=zip(*valid_versions)[0],
73  default=opts.get('os_image', valid_versions[0][0]),
74  help='Docker OS image -- be sure to use only ones you trust (See '
75  'README.docker). Choices: %(choices)s. Default: %(default)s.',
76  )
77  parser.add_argument(
78  '--gcc-version', metavar='VER',
79  choices=set(zip(*valid_versions)[1]),
80  default=opts.get('gcc_version', valid_versions[0][1]),
81  help='Choices: %(choices)s. Default: %(default)s.',
82  )
83  parser.add_argument(
84  '--make-parallelism', metavar='NUM', type=int,
85  default=opts.get('make_parallelism', 1),
86  help='Use `make -j` on multi-CPU systems with lots of RAM. '
87  'Default: %(default)s.',
88  )
89  parser.add_argument(
90  '--local-repo-dir', metavar='DIR',
91  help='If set, build {0} from a local directory instead of Github.'
92  .format(github_project),
93  )
94  parser.add_argument(
95  '--ccache-tgz', metavar='PATH',
96  help='If set, enable ccache for the build. To initialize the '
97  'cache, first try to hardlink, then to copy --cache-tgz '
98  'as ccache.tgz into the --docker-context-dir.'
99  )
100 
102  add_args,
103  # These have add_argument() calls, others are set via --option.
104  (
105  'docker_context_dir',
106  'user',
107  'prefix',
108  'projects_dir',
109  'os_image',
110  'gcc_version',
111  'make_parallelism',
112  'local_repo_dir',
113  'ccache_tgz',
114  ),
115  opts,
116  help=textwrap.dedent('''
117 
118  Reads `fbcode_builder_config.py` from the current directory, and
119  prepares a Docker context directory to build {github_project} and
120  its dependencies. Prints to stdout the path to the context
121  directory.
122 
123  Pass --option {github_project}:git_hash SHA1 to build something
124  other than the master branch from Github.
125 
126  Or, pass --option {github_project}:local_repo_dir LOCAL_PATH to
127  build from a local repo instead of cloning from Github.
128 
129  Usage:
130  (cd $(./make_docker_context.py) && docker build . 2>&1 | tee log)
131 
132  '''.format(github_project=github_project)),
133  )
134 
135  # This allows travis_docker_build.sh not to know the main Github project.
136  local_repo_dir = opts.pop('local_repo_dir', None)
137  if local_repo_dir is not None:
138  opts['{0}:local_repo_dir'.format(github_project)] = local_repo_dir
139 
140  if (opts.get('os_image'), opts.get('gcc_version')) not in valid_versions:
141  raise Exception(
142  'Due to 4/5 ABI changes (std::string), we can only use {0}'.format(
143  ' / '.join('GCC {1} on {0}'.format(*p) for p in valid_versions)
144  )
145  )
146 
147  if opts.get('docker_context_dir') is None:
148  opts['docker_context_dir'] = tempfile.mkdtemp(prefix='docker-context-')
149  elif not os.path.exists(opts.get('docker_context_dir')):
150  os.makedirs(opts.get('docker_context_dir'))
151 
152  builder = DockerFBCodeBuilder(**opts)
153  context_dir = builder.option('docker_context_dir') # Mark option "in-use"
154  # The renderer may also populate some files into the context_dir.
155  dockerfile = builder.render(get_steps_fn(builder))
156 
157  with os.fdopen(os.open(
158  os.path.join(context_dir, 'Dockerfile'),
159  os.O_RDWR | os.O_CREAT | os.O_EXCL, # Do not overwrite existing files
160  0o644,
161  ), 'w') as f:
162  f.write(dockerfile)
163 
164  return context_dir
165 
166 
167 if __name__ == '__main__':
168  from utils import read_fbcode_builder_config, build_fbcode_builder_config
169 
170  # Load a spec from the current directory
171  config = read_fbcode_builder_config('fbcode_builder_config.py')
172  print(make_docker_context(
174  config['github_project'],
175  ))
Zip zip(Source &&source)
Definition: Combine-inl.h:202
def make_docker_context(get_steps_fn, github_project, opts=None, default_context_dir=None)
#define join
def build_fbcode_builder_config(config)
Definition: utils.py:93
def read_fbcode_builder_config(filename)
Definition: utils.py:55
def parse_args_to_fbcode_builder_opts(add_args_fn, top_level_opts, opts, help)
Definition: parse_args.py:15
Formatter< false, Args... > format(StringPiece fmt, Args &&...args)
Definition: Format.h:271
Definition: Traits.h:592