proxygen
utils.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 'Miscellaneous utility functions.'
8 
9 import itertools
10 import logging
11 import os
12 import shutil
13 import subprocess
14 import sys
15 
16 from contextlib import contextmanager
17 
18 
20  return itertools.chain.from_iterable(
21  (recursively_flatten_list(i) if type(i) is list else (i,))
22  for i in l
23  )
24 
25 
26 def run_command(*cmd, **kwargs):
27  'The stdout of most fbcode_builder utilities is meant to be parsed.'
28  logging.debug('Running: {0} with {1}'.format(cmd, kwargs))
29  kwargs['stdout'] = sys.stderr
30  subprocess.check_call(cmd, **kwargs)
31 
32 
33 @contextmanager
34 def make_temp_dir(d):
35  os.mkdir(d)
36  try:
37  yield d
38  finally:
39  shutil.rmtree(d, ignore_errors=True)
40 
41 
42 def _inner_read_config(path):
43  '''
44  Helper to read a named config file.
45  The grossness with the global is a workaround for this python bug:
46  https://bugs.python.org/issue21591
47  The bug prevents us from defining either a local function or a lambda
48  in the scope of read_fbcode_builder_config below.
49  '''
50  global _project_dir
51  full_path = os.path.join(_project_dir, path)
52  return read_fbcode_builder_config(full_path)
53 
54 
55 def read_fbcode_builder_config(filename):
56  # Allow one spec to read another
57  # When doing so, treat paths as relative to the config's project directory.
58  # _project_dir is a "local" for _inner_read_config; see the comments
59  # in that function for an explanation of the use of global.
60  global _project_dir
61  _project_dir = os.path.dirname(filename)
62 
63  scope = {'read_fbcode_builder_config': _inner_read_config}
64  with open(filename) as config_file:
65  code = compile(config_file.read(), filename, mode='exec')
66  exec(code, scope)
67  return scope['config']
68 
69 
70 def steps_for_spec(builder, spec, processed_modules=None):
71  '''
72  Sets `builder` configuration, and returns all the builder steps
73  necessary to build `spec` and its dependencies.
74 
75  Traverses the dependencies in depth-first order, honoring the sequencing
76  in each 'depends_on' list.
77  '''
78  if processed_modules is None:
79  processed_modules = set()
80  steps = []
81  for module in spec.get('depends_on', []):
82  if module not in processed_modules:
83  processed_modules.add(module)
84  steps.extend(steps_for_spec(
85  builder,
86  module.fbcode_builder_spec(builder),
87  processed_modules
88  ))
89  steps.extend(spec.get('steps', []))
90  return steps
91 
92 
93 def build_fbcode_builder_config(config):
94  return lambda builder: builder.build(
95  steps_for_spec(builder, config['fbcode_builder_spec'](builder))
96  )
PskType type
def recursively_flatten_list(l)
Definition: utils.py:19
def make_temp_dir(d)
Definition: utils.py:34
def _inner_read_config(path)
Definition: utils.py:42
def steps_for_spec(builder, spec, processed_modules=None)
Definition: utils.py:70
def run_command(cmd, kwargs)
Definition: utils.py:26
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
Definition: Traits.h:592