1
0
mirror of https://github.com/facebook/proxygen.git synced 2025-08-05 19:55:47 +03:00
Files
Alex Hornby 18fefedec8 speed up file copy on windows
Summary:
X-link: https://github.com/facebookincubator/fizz/pull/155

X-link: https://github.com/facebookincubator/zstrong/pull/1085

getdeps windows file copy is very slow, speed it up

Reviewed By: bigfootjon

Differential Revision: D66830544

fbshipit-source-id: 43213e258c71ae706bb059600619e276e7491a90
2024-12-06 01:30:06 -08:00

100 lines
3.0 KiB
Python

# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
# pyre-unsafe
import os
import shutil
import subprocess
from .platform import is_windows
from .runcmd import run_cmd
PREFETCHED_DIRS = set()
def containing_repo_type(path):
while True:
if os.path.exists(os.path.join(path, ".git")):
return ("git", path)
if os.path.exists(os.path.join(path, ".hg")):
return ("hg", path)
parent = os.path.dirname(path)
if parent == path:
return None, None
path = parent
def find_eden_root(dirpath):
"""If the specified directory is inside an EdenFS checkout, returns
the canonical absolute path to the root of that checkout.
Returns None if the specified directory is not in an EdenFS checkout.
"""
if is_windows():
repo_type, repo_root = containing_repo_type(dirpath)
if repo_root is not None:
if os.path.exists(os.path.join(repo_root, ".eden", "config")):
return repo_root
return None
try:
return os.readlink(os.path.join(dirpath, ".eden", "root"))
except OSError:
return None
def prefetch_dir_if_eden(dirpath) -> None:
"""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"""
global PREFETCHED_DIRS
if dirpath in PREFETCHED_DIRS:
return
root = find_eden_root(dirpath)
if root is None:
return
glob = f"{os.path.relpath(dirpath, root).replace(os.sep, '/')}/**"
print(f"Prefetching {glob}")
subprocess.call(["edenfsctl", "prefetch", "--repo", root, glob, "--background"])
PREFETCHED_DIRS.add(dirpath)
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)