From ade91cbac96c1b3db0a190827dae70a330b0a5e5 Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Fri, 3 May 2019 15:52:39 -0700 Subject: [PATCH] fbcode_builder: getdeps: add copytree helper Summary: this module adds some functions that help with copying directory trees. The copytree function is aware of eden and will issue a prefetch prior to walking the directory. Reviewed By: simpkins Differential Revision: D14691006 fbshipit-source-id: 079bf850756f61aca17978453d07bc73b2f91788 --- build/fbcode_builder/getdeps/copytree.py | 54 ++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 build/fbcode_builder/getdeps/copytree.py diff --git a/build/fbcode_builder/getdeps/copytree.py b/build/fbcode_builder/getdeps/copytree.py new file mode 100644 index 000000000..b5f23bee0 --- /dev/null +++ b/build/fbcode_builder/getdeps/copytree.py @@ -0,0 +1,54 @@ +# Copyright (c) 2019-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. An additional grant +# of patent rights can be found in the PATENTS file in the same directory. + +from __future__ import absolute_import, division, print_function, unicode_literals + +import os +import shutil +import subprocess + + +def is_eden(dirpath): + """Returns True if the specified directory is the root directory of, + or is a sub-directory of an Eden mount.""" + return os.path.islink(os.path.join(dirpath, ".eden", "root")) + + +def find_eden_root(dirpath): + """If the specified directory is the root directory of, or is a + sub-directory of an Eden mount, returns the canonical absolute path + to the root of that Eden mount.""" + return os.readlink(os.path.join(dirpath, ".eden", "root")) + + +def prefetch_dir_if_eden(dirpath): + """ After an amend/rebase, Eden may need to fetch a large number + of trees from the servers. The simplistic single threaded walk + performed by copytree makes this more expensive than is desirable + so we help accelerate things by performing a prefetch on the + source directory """ + if not is_eden(dirpath): + return + root = find_eden_root(dirpath) + rel = os.path.relpath(dirpath, root) + print("Prefetching %s..." % rel) + # TODO: this should be edenfsctl but until I swing through a new + # package deploy, I only have `eden` on my mac to test this + subprocess.call(["eden", "prefetch", "--repo", root, "--silent", "%s/**" % rel]) + + +def copytree(src_dir, dest_dir, ignore=None): + """ Recursively copy the src_dir to the dest_dir, filtering + out entries using the ignore lambda. The behavior of the + ignore lambda must match that described by `shutil.copytree`. + This `copytree` function knows how to prefetch data when + running in an eden repo. + TODO: I'd like to either extend this or add a variant that + uses watchman to mirror src_dir into dest_dir. + """ + prefetch_dir_if_eden(src_dir) + return shutil.copytree(src_dir, dest_dir, ignore=ignore)