Commit 571f3268 authored by Adam Simpkins's avatar Adam Simpkins Committed by Facebook Github Bot

fbcode_builder: implement automatic project detection from the current repo

Summary:
This updates fbcode_builder to try and automatically detect the current
repository's project name by looking for a `.projectid` file in the repository
root.  If the project name can be detected:
- The current repository will automatically be used as the source directory
  for this project (instead of fetching the sources into the scratch
  directory).
- If an explicit project name was not specified on the command line, the
  current project will be built by default.

This also changes the repository detection logic to use the current working
directory, rather than the directory where the fbcode_builder code lives.
This will allow this logic to work even if we move fbcode_builder into its own
repository in the future, and have projects depend on it using git submodules.
This does mean that callers need to invoke fbcode_builder.py from inside the
repository.

Reviewed By: wez

Differential Revision: D17088938

fbshipit-source-id: f14d28fdcfaa330ff837ea52b8bdd4e358b81c61
parent 233f10ae
...@@ -71,6 +71,23 @@ class ShowHostType(SubCmd): ...@@ -71,6 +71,23 @@ class ShowHostType(SubCmd):
class ProjectCmdBase(SubCmd): class ProjectCmdBase(SubCmd):
def run(self, args): def run(self, args):
opts = setup_build_options(args) opts = setup_build_options(args)
if args.current_project is not None:
opts.repo_project = args.current_project
if args.project is None:
if opts.repo_project is None:
raise UsageError(
"no project name specified, and no .projectid file found"
)
if opts.repo_project == "fbsource":
# The fbsource repository is a little special. There is no project
# manifest file for it. A specific project must always be explicitly
# specified when building from fbsource.
raise UsageError(
"no project name specified (required when building in fbsource)"
)
args.project = opts.repo_project
ctx_gen = opts.get_context_generator(facebook_internal=args.facebook_internal) ctx_gen = opts.get_context_generator(facebook_internal=args.facebook_internal)
if args.test_dependencies: if args.test_dependencies:
ctx_gen.set_value_for_all_projects("test", "on") ctx_gen.set_value_for_all_projects("test", "on")
...@@ -101,6 +118,12 @@ class ProjectCmdBase(SubCmd): ...@@ -101,6 +118,12 @@ class ProjectCmdBase(SubCmd):
return project, os.path.abspath(path) return project, os.path.abspath(path)
# If we are currently running from a project repository,
# use the current repository for the project sources.
build_opts = loader.build_opts
if build_opts.repo_project is not None and build_opts.repo_root is not None:
loader.set_project_src_dir(build_opts.repo_project, build_opts.repo_root)
for arg in args.src_dir: for arg in args.src_dir:
project, path = parse_project_arg(arg, "--src-dir") project, path = parse_project_arg(arg, "--src-dir")
loader.set_project_src_dir(project, path) loader.set_project_src_dir(project, path)
...@@ -116,6 +139,7 @@ class ProjectCmdBase(SubCmd): ...@@ -116,6 +139,7 @@ class ProjectCmdBase(SubCmd):
def setup_parser(self, parser): def setup_parser(self, parser):
parser.add_argument( parser.add_argument(
"project", "project",
nargs="?",
help=( help=(
"name of the project or path to a manifest " "name of the project or path to a manifest "
"file describing the project" "file describing the project"
...@@ -133,6 +157,12 @@ class ProjectCmdBase(SubCmd): ...@@ -133,6 +157,12 @@ class ProjectCmdBase(SubCmd):
action="store_true", action="store_true",
help="Enable building tests for dependencies as well.", help="Enable building tests for dependencies as well.",
) )
parser.add_argument(
"--current-project",
help="Specify the name of the fbcode_builder manifest file for the "
"current repository. If not specified, the code will attempt to find "
"this in a .projectid file in the repository root.",
)
parser.add_argument( parser.add_argument(
"--src-dir", "--src-dir",
default=[], default=[],
......
...@@ -35,10 +35,28 @@ def containing_repo_type(path): ...@@ -35,10 +35,28 @@ def containing_repo_type(path):
parent = os.path.dirname(path) parent = os.path.dirname(path)
if parent == path: if parent == path:
return None return None, None
path = parent path = parent
def detect_project(path):
repo_type, repo_root = containing_repo_type(path)
if repo_type is None:
return None, None
# Look for a .projectid file. If it exists, read the project name from it.
project_id_path = os.path.join(repo_root, ".projectid")
try:
with open(project_id_path, "r") as f:
project_name = f.read().strip()
return repo_root, project_name
except EnvironmentError as ex:
if ex.errno != errno.ENOENT:
raise
return repo_root, None
class BuildOptions(object): class BuildOptions(object):
def __init__( def __init__(
self, self,
...@@ -78,11 +96,13 @@ class BuildOptions(object): ...@@ -78,11 +96,13 @@ class BuildOptions(object):
self.project_hashes = hashes self.project_hashes = hashes
break break
# Use a simplistic heuristic to figure out if we're in fbsource # Detect what repository and project we are being run from.
# and where the root of fbsource can be found self.repo_root, self.repo_project = detect_project(os.getcwd())
repo_type, repo_root = containing_repo_type(fbcode_builder_dir)
if repo_type == "hg": # If we are running from an fbsource repository, set self.fbsource_dir
self.fbsource_dir = repo_root # to allow the ShipIt-based fetchers to use it.
if self.repo_project == "fbsource":
self.fbsource_dir = self.repo_root
else: else:
self.fbsource_dir = None self.fbsource_dir = None
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment