Skip to content

Commit

Permalink
speed up file copy on windows
Browse files Browse the repository at this point in the history
Summary:
X-link: facebookincubator/fizz#155

X-link: facebookincubator/zstrong#1085

getdeps windows file copy is very slow, speed it up

Reviewed By: bigfootjon

Differential Revision: D66830544

fbshipit-source-id: 43213e258c71ae706bb059600619e276e7491a90
  • Loading branch information
ahornby authored and facebook-github-bot committed Dec 6, 2024
1 parent 4236c2e commit f3a4189
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 18 deletions.
5 changes: 3 additions & 2 deletions build/fbcode_builder/getdeps/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from shlex import quote as shellquote
from typing import Optional

from .copytree import simple_copytree
from .dyndeps import create_dyn_dep_munger
from .envfuncs import add_path_entry, Env, path_search
from .fetcher import copy_if_different
Expand Down Expand Up @@ -1329,7 +1330,7 @@ def build(self, reconfigure: bool) -> None:
os.makedirs(dest_parent)
if os.path.isdir(full_src):
if not os.path.exists(full_dest):
shutil.copytree(full_src, full_dest)
simple_copytree(full_src, full_dest)
else:
shutil.copyfile(full_src, full_dest)
shutil.copymode(full_src, full_dest)
Expand All @@ -1341,7 +1342,7 @@ def build(self, reconfigure: bool) -> None:
os.chmod(full_dest, st.st_mode | stat.S_IXUSR)
else:
if not os.path.exists(self.inst_dir):
shutil.copytree(self.src_dir, self.inst_dir)
simple_copytree(self.src_dir, self.inst_dir)


class SqliteBuilder(BuilderBase):
Expand Down
3 changes: 2 additions & 1 deletion build/fbcode_builder/getdeps/cargo.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import typing

from .builder import BuilderBase
from .copytree import simple_copytree

if typing.TYPE_CHECKING:
from .buildopts import BuildOptions
Expand Down Expand Up @@ -79,7 +80,7 @@ def recreate_dir(self, src, dst) -> None:
os.remove(dst)
else:
shutil.rmtree(dst)
shutil.copytree(src, dst)
simple_copytree(src, dst)

def cargo_config_file(self):
build_source_dir = self.build_dir
Expand Down
47 changes: 32 additions & 15 deletions build/fbcode_builder/getdeps/copytree.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import subprocess

from .platform import is_windows
from .runcmd import run_cmd


PREFETCHED_DIRS = set()
Expand Down Expand Up @@ -65,18 +66,34 @@ def prefetch_dir_if_eden(dirpath) -> None:
PREFETCHED_DIRS.add(dirpath)


# pyre-fixme[9]: ignore has type `bool`; used as `None`.
def copytree(src_dir, dest_dir, ignore: bool = 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)
# pyre-fixme[6]: For 3rd param expected
# `Union[typing.Callable[[Union[PathLike[str], str], List[str]], Iterable[str]],
# typing.Callable[[str, List[str]], Iterable[str]], None]` but got `bool`.
return shutil.copytree(src_dir, dest_dir, ignore=ignore)
def simple_copytree(src_dir, dest_dir, symlinks=False):
"""A simple version of shutil.copytree() that can delegate to native tools if faster"""
if is_windows():
os.makedirs(dest_dir, exist_ok=True)
cmd = [
"robocopy.exe",
src_dir,
dest_dir,
# copy directories, including empty ones
"/E",
# Ignore Extra files in destination
"/XX",
# enable parallel copy
"/MT",
# be quiet
"/NFL",
"/NDL",
"/NJH",
"/NJS",
"/NP",
]
if symlinks:
cmd.append("/SL")
# robocopy exits with code 1 if it copied ok, hence allow_fail
# https://learn.microsoft.com/en-us/troubleshoot/windows-server/backup-and-storage/return-codes-used-robocopy-utility
exit_code = run_cmd(cmd, allow_fail=True)
if exit_code > 1:
raise subprocess.CalledProcessError(exit_code, cmd)
return dest_dir
else:
return shutil.copytree(src_dir, dest_dir, symlinks=symlinks)

0 comments on commit f3a4189

Please sign in to comment.