build/fbcode_builder/shell_builder.py (73 lines of code) (raw):
#!/usr/bin/env python
# Copyright (c) Facebook, Inc. and its affiliates.
"""
shell_builder.py allows running the fbcode_builder logic
on the host rather than in a container.
It emits a bash script with set -exo pipefail configured such that
any failing step will cause the script to exit with failure.
== How to run it? ==
cd build
python fbcode_builder/shell_builder.py > ~/run.sh
bash ~/run.sh
"""
import distutils.spawn
import os
from fbcode_builder import FBCodeBuilder
from shell_quoting import raw_shell, shell_comment, shell_join, ShellQuoted
from utils import recursively_flatten_list
class ShellFBCodeBuilder(FBCodeBuilder):
def _render_impl(self, steps):
return raw_shell(shell_join("\n", recursively_flatten_list(steps)))
def set_env(self, key, value):
return ShellQuoted("export {key}={val}").format(key=key, val=value)
def workdir(self, dir):
return [
ShellQuoted("mkdir -p {d} && cd {d}").format(d=dir),
]
def run(self, shell_cmd):
return ShellQuoted("{cmd}").format(cmd=shell_cmd)
def step(self, name, actions):
assert "\n" not in name, "Name {0} would span > 1 line".format(name)
b = ShellQuoted("")
return [ShellQuoted("### {0} ###".format(name)), b] + actions + [b]
def setup(self):
steps = (
[
ShellQuoted("set -exo pipefail"),
]
+ self.create_python_venv()
+ self.python_venv()
)
if self.has_option("ccache_dir"):
ccache_dir = self.option("ccache_dir")
steps += [
ShellQuoted(
# Set CCACHE_DIR before the `ccache` invocations below.
"export CCACHE_DIR={ccache_dir} "
'CC="ccache ${{CC:-gcc}}" CXX="ccache ${{CXX:-g++}}"'
).format(ccache_dir=ccache_dir)
]
return steps
def comment(self, comment):
return shell_comment(comment)
def copy_local_repo(self, dir, dest_name):
return [
ShellQuoted("cp -r {dir} {dest_name}").format(dir=dir, dest_name=dest_name),
]
def find_project_root():
here = os.path.dirname(os.path.realpath(__file__))
maybe_root = os.path.dirname(os.path.dirname(here))
if os.path.isdir(os.path.join(maybe_root, ".git")):
return maybe_root
raise RuntimeError(
"I expected shell_builder.py to be in the "
"build/fbcode_builder subdir of a git repo"
)
def persistent_temp_dir(repo_root):
escaped = repo_root.replace("/", "sZs").replace("\\", "sZs").replace(":", "")
return os.path.join(os.path.expandvars("$HOME"), ".fbcode_builder-" + escaped)
if __name__ == "__main__":
from utils import read_fbcode_builder_config, build_fbcode_builder_config
repo_root = find_project_root()
temp = persistent_temp_dir(repo_root)
config = read_fbcode_builder_config("fbcode_builder_config.py")
builder = ShellFBCodeBuilder(projects_dir=temp)
if distutils.spawn.find_executable("ccache"):
builder.add_option(
"ccache_dir", os.environ.get("CCACHE_DIR", os.path.join(temp, ".ccache"))
)
builder.add_option("prefix", os.path.join(temp, "installed"))
builder.add_option("make_parallelism", 4)
builder.add_option(
"{project}:local_repo_dir".format(project=config["github_project"]), repo_root
)
make_steps = build_fbcode_builder_config(config)
steps = make_steps(builder)
print(builder.render(steps))