mirror of
https://github.com/facebook/proxygen.git
synced 2025-08-07 07:02:53 +03:00
Add annotations to opensource/fbcode_builder
Reviewed By: shannonzhu Differential Revision: D34224272 fbshipit-source-id: 52e19886ab3d4fb015a557244660dd4357a35c17
This commit is contained in:

committed by
Facebook GitHub Bot
parent
6c86c07528
commit
e77a9fe43a
@@ -29,7 +29,7 @@ class BuilderBase(object):
|
||||
inst_dir,
|
||||
env=None,
|
||||
final_install_prefix=None,
|
||||
):
|
||||
) -> None:
|
||||
self.env = Env()
|
||||
if env:
|
||||
self.env.update(env)
|
||||
@@ -57,7 +57,14 @@ class BuilderBase(object):
|
||||
return [vcvarsall, "amd64", "&&"]
|
||||
return []
|
||||
|
||||
def _run_cmd(self, cmd, cwd=None, env=None, use_cmd_prefix=True, allow_fail=False):
|
||||
def _run_cmd(
|
||||
self,
|
||||
cmd,
|
||||
cwd=None,
|
||||
env=None,
|
||||
use_cmd_prefix: bool = True,
|
||||
allow_fail: bool = False,
|
||||
):
|
||||
if env:
|
||||
e = self.env.copy()
|
||||
e.update(env)
|
||||
@@ -79,7 +86,7 @@ class BuilderBase(object):
|
||||
allow_fail=allow_fail,
|
||||
)
|
||||
|
||||
def build(self, install_dirs, reconfigure):
|
||||
def build(self, install_dirs, reconfigure: bool) -> None:
|
||||
print("Building %s..." % self.manifest.name)
|
||||
|
||||
if self.build_dir is not None:
|
||||
@@ -97,6 +104,7 @@ class BuilderBase(object):
|
||||
script_path = self.get_dev_run_script_path()
|
||||
dep_munger = create_dyn_dep_munger(self.build_opts, install_dirs)
|
||||
dep_dirs = self.get_dev_run_extra_path_dirs(install_dirs, dep_munger)
|
||||
# pyre-fixme[16]: Optional type has no attribute `emit_dev_run_script`.
|
||||
dep_munger.emit_dev_run_script(script_path, dep_dirs)
|
||||
|
||||
@property
|
||||
@@ -122,12 +130,12 @@ class BuilderBase(object):
|
||||
|
||||
def run_tests(
|
||||
self, install_dirs, schedule_type, owner, test_filter, retry, no_testpilot
|
||||
):
|
||||
) -> None:
|
||||
"""Execute any tests that we know how to run. If they fail,
|
||||
raise an exception."""
|
||||
pass
|
||||
|
||||
def _build(self, install_dirs, reconfigure):
|
||||
def _build(self, install_dirs, reconfigure) -> None:
|
||||
"""Perform the build.
|
||||
install_dirs contains the list of installation directories for
|
||||
the dependencies of this project.
|
||||
@@ -166,7 +174,7 @@ class MakeBuilder(BuilderBase):
|
||||
build_args,
|
||||
install_args,
|
||||
test_args,
|
||||
):
|
||||
) -> None:
|
||||
super(MakeBuilder, self).__init__(
|
||||
build_opts, ctx, manifest, src_dir, build_dir, inst_dir
|
||||
)
|
||||
@@ -181,7 +189,7 @@ class MakeBuilder(BuilderBase):
|
||||
def _get_prefix(self):
|
||||
return ["PREFIX=" + self.inst_dir, "prefix=" + self.inst_dir]
|
||||
|
||||
def _build(self, install_dirs, reconfigure):
|
||||
def _build(self, install_dirs, reconfigure) -> None:
|
||||
|
||||
env = self._compute_env(install_dirs)
|
||||
|
||||
@@ -208,7 +216,7 @@ class MakeBuilder(BuilderBase):
|
||||
|
||||
def run_tests(
|
||||
self, install_dirs, schedule_type, owner, test_filter, retry, no_testpilot
|
||||
):
|
||||
) -> None:
|
||||
if not self.test_args:
|
||||
return
|
||||
|
||||
@@ -219,7 +227,7 @@ class MakeBuilder(BuilderBase):
|
||||
|
||||
|
||||
class CMakeBootStrapBuilder(MakeBuilder):
|
||||
def _build(self, install_dirs, reconfigure):
|
||||
def _build(self, install_dirs, reconfigure) -> None:
|
||||
self._run_cmd(
|
||||
[
|
||||
"./bootstrap",
|
||||
@@ -241,7 +249,7 @@ class AutoconfBuilder(BuilderBase):
|
||||
inst_dir,
|
||||
args,
|
||||
conf_env_args,
|
||||
):
|
||||
) -> None:
|
||||
super(AutoconfBuilder, self).__init__(
|
||||
build_opts, ctx, manifest, src_dir, build_dir, inst_dir
|
||||
)
|
||||
@@ -252,7 +260,7 @@ class AutoconfBuilder(BuilderBase):
|
||||
def _make_binary(self):
|
||||
return self.manifest.get("build", "make_binary", "make", ctx=self.ctx)
|
||||
|
||||
def _build(self, install_dirs, reconfigure):
|
||||
def _build(self, install_dirs, reconfigure) -> None:
|
||||
configure_path = os.path.join(self.src_dir, "configure")
|
||||
autogen_path = os.path.join(self.src_dir, "autogen.sh")
|
||||
|
||||
@@ -295,12 +303,12 @@ class Iproute2Builder(BuilderBase):
|
||||
# Thus, explicitly copy sources from src_dir to build_dir, bulid,
|
||||
# and then install to inst_dir using DESTDIR
|
||||
# lastly, also copy include from build_dir to inst_dir
|
||||
def __init__(self, build_opts, ctx, manifest, src_dir, build_dir, inst_dir):
|
||||
def __init__(self, build_opts, ctx, manifest, src_dir, build_dir, inst_dir) -> None:
|
||||
super(Iproute2Builder, self).__init__(
|
||||
build_opts, ctx, manifest, src_dir, build_dir, inst_dir
|
||||
)
|
||||
|
||||
def _patch(self):
|
||||
def _patch(self) -> None:
|
||||
# FBOSS build currently depends on an old version of iproute2 (commit
|
||||
# 7ca63aef7d1b0c808da0040c6b366ef7a61f38c1). This is missing a commit
|
||||
# (ae717baf15fb4d30749ada3948d9445892bac239) needed to build iproute2
|
||||
@@ -313,7 +321,7 @@ class Iproute2Builder(BuilderBase):
|
||||
f.write("#include <stdint.h>\n")
|
||||
f.write(data)
|
||||
|
||||
def _build(self, install_dirs, reconfigure):
|
||||
def _build(self, install_dirs, reconfigure) -> None:
|
||||
configure_path = os.path.join(self.src_dir, "configure")
|
||||
|
||||
env = self.env.copy()
|
||||
@@ -334,7 +342,7 @@ class Iproute2Builder(BuilderBase):
|
||||
|
||||
|
||||
class BistroBuilder(BuilderBase):
|
||||
def _build(self, install_dirs, reconfigure):
|
||||
def _build(self, install_dirs, reconfigure) -> None:
|
||||
p = os.path.join(self.src_dir, "bistro", "bistro")
|
||||
env = self._compute_env(install_dirs)
|
||||
env["PATH"] = env["PATH"] + ":" + os.path.join(p, "bin")
|
||||
@@ -361,7 +369,7 @@ class BistroBuilder(BuilderBase):
|
||||
|
||||
def run_tests(
|
||||
self, install_dirs, schedule_type, owner, test_filter, retry, no_testpilot
|
||||
):
|
||||
) -> None:
|
||||
env = self._compute_env(install_dirs)
|
||||
build_dir = os.path.join(self.src_dir, "bistro", "bistro", "cmake", "Release")
|
||||
NUM_RETRIES = 5
|
||||
@@ -508,7 +516,7 @@ if __name__ == "__main__":
|
||||
loader=None,
|
||||
final_install_prefix=None,
|
||||
extra_cmake_defines=None,
|
||||
):
|
||||
) -> None:
|
||||
super(CMakeBuilder, self).__init__(
|
||||
build_opts,
|
||||
ctx,
|
||||
@@ -533,7 +541,7 @@ if __name__ == "__main__":
|
||||
if build_opts.shared_libs:
|
||||
self.defines["BUILD_SHARED_LIBS"] = "ON"
|
||||
|
||||
def _invalidate_cache(self):
|
||||
def _invalidate_cache(self) -> None:
|
||||
for name in [
|
||||
"CMakeCache.txt",
|
||||
"CMakeFiles/CMakeError.log",
|
||||
@@ -545,14 +553,14 @@ if __name__ == "__main__":
|
||||
elif os.path.exists(name):
|
||||
os.unlink(name)
|
||||
|
||||
def _needs_reconfigure(self):
|
||||
def _needs_reconfigure(self) -> bool:
|
||||
for name in ["CMakeCache.txt", "build.ninja"]:
|
||||
name = os.path.join(self.build_dir, name)
|
||||
if not os.path.exists(name):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _write_build_script(self, **kwargs):
|
||||
def _write_build_script(self, **kwargs) -> None:
|
||||
env_lines = [" {!r}: {!r},".format(k, v) for k, v in kwargs["env"].items()]
|
||||
kwargs["env_str"] = "\n".join(["{"] + env_lines + ["}"])
|
||||
|
||||
@@ -668,7 +676,7 @@ if __name__ == "__main__":
|
||||
|
||||
return define_args
|
||||
|
||||
def _build(self, install_dirs, reconfigure):
|
||||
def _build(self, install_dirs, reconfigure) -> None:
|
||||
reconfigure = reconfigure or self._needs_reconfigure()
|
||||
|
||||
env = self._compute_env(install_dirs)
|
||||
@@ -713,8 +721,8 @@ if __name__ == "__main__":
|
||||
)
|
||||
|
||||
def run_tests(
|
||||
self, install_dirs, schedule_type, owner, test_filter, retry, no_testpilot
|
||||
):
|
||||
self, install_dirs, schedule_type, owner, test_filter, retry: int, no_testpilot
|
||||
) -> None:
|
||||
env = self._compute_env(install_dirs)
|
||||
ctest = path_search(env, "ctest")
|
||||
cmake = path_search(env, "cmake")
|
||||
@@ -917,19 +925,21 @@ if __name__ == "__main__":
|
||||
# Only add this option in the second run.
|
||||
args += ["--rerun-failed"]
|
||||
count += 1
|
||||
# pyre-fixme[61]: `retcode` is undefined, or not always defined.
|
||||
if retcode != 0:
|
||||
# Allow except clause in getdeps.main to catch and exit gracefully
|
||||
# This allows non-testpilot runs to fail through the same logic as failed testpilot runs, which may become handy in case if post test processing is needed in the future
|
||||
# pyre-fixme[61]: `retcode` is undefined, or not always defined.
|
||||
raise subprocess.CalledProcessError(retcode, args)
|
||||
|
||||
|
||||
class NinjaBootstrap(BuilderBase):
|
||||
def __init__(self, build_opts, ctx, manifest, build_dir, src_dir, inst_dir):
|
||||
def __init__(self, build_opts, ctx, manifest, build_dir, src_dir, inst_dir) -> None:
|
||||
super(NinjaBootstrap, self).__init__(
|
||||
build_opts, ctx, manifest, src_dir, build_dir, inst_dir
|
||||
)
|
||||
|
||||
def _build(self, install_dirs, reconfigure):
|
||||
def _build(self, install_dirs, reconfigure) -> None:
|
||||
self._run_cmd([sys.executable, "configure.py", "--bootstrap"], cwd=self.src_dir)
|
||||
src_ninja = os.path.join(self.src_dir, "ninja")
|
||||
dest_ninja = os.path.join(self.inst_dir, "bin/ninja")
|
||||
@@ -941,12 +951,12 @@ class NinjaBootstrap(BuilderBase):
|
||||
|
||||
|
||||
class OpenSSLBuilder(BuilderBase):
|
||||
def __init__(self, build_opts, ctx, manifest, build_dir, src_dir, inst_dir):
|
||||
def __init__(self, build_opts, ctx, manifest, build_dir, src_dir, inst_dir) -> None:
|
||||
super(OpenSSLBuilder, self).__init__(
|
||||
build_opts, ctx, manifest, src_dir, build_dir, inst_dir
|
||||
)
|
||||
|
||||
def _build(self, install_dirs, reconfigure):
|
||||
def _build(self, install_dirs, reconfigure) -> None:
|
||||
configure = os.path.join(self.src_dir, "Configure")
|
||||
|
||||
# prefer to resolve the perl that we installed from
|
||||
@@ -1001,7 +1011,7 @@ class OpenSSLBuilder(BuilderBase):
|
||||
class Boost(BuilderBase):
|
||||
def __init__(
|
||||
self, build_opts, ctx, manifest, src_dir, build_dir, inst_dir, b2_args
|
||||
):
|
||||
) -> None:
|
||||
children = os.listdir(src_dir)
|
||||
assert len(children) == 1, "expected a single directory entry: %r" % (children,)
|
||||
boost_src = children[0]
|
||||
@@ -1012,7 +1022,7 @@ class Boost(BuilderBase):
|
||||
)
|
||||
self.b2_args = b2_args
|
||||
|
||||
def _build(self, install_dirs, reconfigure):
|
||||
def _build(self, install_dirs, reconfigure) -> None:
|
||||
env = self._compute_env(install_dirs)
|
||||
linkage = ["static"]
|
||||
if self.build_opts.is_windows() or self.build_opts.shared_libs:
|
||||
@@ -1068,12 +1078,12 @@ class Boost(BuilderBase):
|
||||
|
||||
|
||||
class NopBuilder(BuilderBase):
|
||||
def __init__(self, build_opts, ctx, manifest, src_dir, inst_dir):
|
||||
def __init__(self, build_opts, ctx, manifest, src_dir, inst_dir) -> None:
|
||||
super(NopBuilder, self).__init__(
|
||||
build_opts, ctx, manifest, src_dir, None, inst_dir
|
||||
)
|
||||
|
||||
def build(self, install_dirs, reconfigure):
|
||||
def build(self, install_dirs, reconfigure) -> None:
|
||||
print("Installing %s -> %s" % (self.src_dir, self.inst_dir))
|
||||
parent = os.path.dirname(self.inst_dir)
|
||||
if not os.path.exists(parent):
|
||||
@@ -1116,12 +1126,12 @@ class OpenNSABuilder(NopBuilder):
|
||||
# In future, if more builders require git-lfs, we would consider installing
|
||||
# git-lfs as part of the sandcastle infra as against repeating similar
|
||||
# logic for each builder that requires git-lfs.
|
||||
def __init__(self, build_opts, ctx, manifest, src_dir, inst_dir):
|
||||
def __init__(self, build_opts, ctx, manifest, src_dir, inst_dir) -> None:
|
||||
super(OpenNSABuilder, self).__init__(
|
||||
build_opts, ctx, manifest, src_dir, inst_dir
|
||||
)
|
||||
|
||||
def build(self, install_dirs, reconfigure):
|
||||
def build(self, install_dirs, reconfigure) -> None:
|
||||
env = self._compute_env(install_dirs)
|
||||
self._run_cmd(["git", "lfs", "install", "--local"], cwd=self.src_dir, env=env)
|
||||
self._run_cmd(["git", "lfs", "pull"], cwd=self.src_dir, env=env)
|
||||
@@ -1130,12 +1140,12 @@ class OpenNSABuilder(NopBuilder):
|
||||
|
||||
|
||||
class SqliteBuilder(BuilderBase):
|
||||
def __init__(self, build_opts, ctx, manifest, src_dir, build_dir, inst_dir):
|
||||
def __init__(self, build_opts, ctx, manifest, src_dir, build_dir, inst_dir) -> None:
|
||||
super(SqliteBuilder, self).__init__(
|
||||
build_opts, ctx, manifest, src_dir, build_dir, inst_dir
|
||||
)
|
||||
|
||||
def _build(self, install_dirs, reconfigure):
|
||||
def _build(self, install_dirs, reconfigure) -> None:
|
||||
for f in ["sqlite3.c", "sqlite3.h", "sqlite3ext.h"]:
|
||||
src = os.path.join(self.src_dir, f)
|
||||
dest = os.path.join(self.build_dir, f)
|
||||
|
@@ -44,14 +44,14 @@ class BuildOptions(object):
|
||||
scratch_dir,
|
||||
host_type,
|
||||
install_dir=None,
|
||||
num_jobs=0,
|
||||
use_shipit=False,
|
||||
num_jobs: int = 0,
|
||||
use_shipit: bool = False,
|
||||
vcvars_path=None,
|
||||
allow_system_packages=False,
|
||||
allow_system_packages: bool = False,
|
||||
lfs_path=None,
|
||||
shared_libs=False,
|
||||
shared_libs: bool = False,
|
||||
facebook_internal=None,
|
||||
):
|
||||
) -> None:
|
||||
"""fbcode_builder_dir - the path to either the in-fbsource fbcode_builder dir,
|
||||
or for shipit-transformed repos, the build dir that
|
||||
has been mapped into that dir.
|
||||
@@ -176,7 +176,7 @@ class BuildOptions(object):
|
||||
def is_freebsd(self):
|
||||
return self.host_type.is_freebsd()
|
||||
|
||||
def get_num_jobs(self, job_weight):
|
||||
def get_num_jobs(self, job_weight: int):
|
||||
"""Given an estimated job_weight in MiB, compute a reasonable concurrency limit."""
|
||||
if self.specified_num_jobs:
|
||||
return self.specified_num_jobs
|
||||
@@ -324,8 +324,8 @@ class BuildOptions(object):
|
||||
return False
|
||||
|
||||
def add_prefix_to_env(
|
||||
self, d, env, append=True, add_library_path=False
|
||||
): # noqa: C901
|
||||
self, d, env, append: bool = True, add_library_path: bool = False
|
||||
) -> bool: # noqa: C901
|
||||
bindir = os.path.join(d, "bin")
|
||||
found = False
|
||||
pkgconfig = os.path.join(d, "lib", "pkgconfig")
|
||||
@@ -472,7 +472,7 @@ def find_unused_drive_letter():
|
||||
return available[-1]
|
||||
|
||||
|
||||
def create_subst_path(path):
|
||||
def create_subst_path(path) -> str:
|
||||
for _attempt in range(0, 24):
|
||||
drive = find_existing_win32_subst_for_path(
|
||||
path, subst_mapping=list_win32_subst_letters()
|
||||
@@ -512,7 +512,7 @@ def _check_host_type(args, host_type):
|
||||
return host_type
|
||||
|
||||
|
||||
def setup_build_options(args, host_type=None):
|
||||
def setup_build_options(args, host_type=None) -> BuildOptions:
|
||||
"""Create a BuildOptions object based on the arguments"""
|
||||
|
||||
fbcode_builder_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
@@ -10,7 +10,7 @@ class ArtifactCache(object):
|
||||
The primary use case is for storing the build products on CI
|
||||
systems to accelerate the build"""
|
||||
|
||||
def download_to_file(self, name, dest_file_name):
|
||||
def download_to_file(self, name, dest_file_name) -> bool:
|
||||
"""If `name` exists in the cache, download it and place it
|
||||
in the specified `dest_file_name` location on the filesystem.
|
||||
If a transient issue was encountered a TransientFailure shall
|
||||
@@ -21,7 +21,7 @@ class ArtifactCache(object):
|
||||
All other conditions shall raise an appropriate exception."""
|
||||
return False
|
||||
|
||||
def upload_from_file(self, name, source_file_name):
|
||||
def upload_from_file(self, name, source_file_name) -> None:
|
||||
"""Causes `name` to be populated in the cache by uploading
|
||||
the contents of `source_file_name` to the storage system.
|
||||
If a transient issue was encountered a TransientFailure shall
|
||||
@@ -31,7 +31,7 @@ class ArtifactCache(object):
|
||||
pass
|
||||
|
||||
|
||||
def create_cache():
|
||||
def create_cache() -> None:
|
||||
"""This function is monkey patchable to provide an actual
|
||||
implementation"""
|
||||
return None
|
||||
|
@@ -23,7 +23,7 @@ class CargoBuilder(BuilderBase):
|
||||
workspace_dir,
|
||||
manifests_to_build,
|
||||
loader,
|
||||
):
|
||||
) -> None:
|
||||
super(CargoBuilder, self).__init__(
|
||||
build_opts, ctx, manifest, src_dir, build_dir, inst_dir
|
||||
)
|
||||
@@ -32,7 +32,7 @@ class CargoBuilder(BuilderBase):
|
||||
self.manifests_to_build = manifests_to_build and manifests_to_build.split(",")
|
||||
self.loader = loader
|
||||
|
||||
def run_cargo(self, install_dirs, operation, args=None):
|
||||
def run_cargo(self, install_dirs, operation, args=None) -> None:
|
||||
args = args or []
|
||||
env = self._compute_env(install_dirs)
|
||||
# Enable using nightly features with stable compiler
|
||||
@@ -55,12 +55,12 @@ class CargoBuilder(BuilderBase):
|
||||
def manifest_dir(self, manifest):
|
||||
return os.path.join(self.build_source_dir(), manifest)
|
||||
|
||||
def recreate_dir(self, src, dst):
|
||||
def recreate_dir(self, src, dst) -> None:
|
||||
if os.path.isdir(dst):
|
||||
shutil.rmtree(dst)
|
||||
shutil.copytree(src, dst)
|
||||
|
||||
def _build(self, install_dirs, reconfigure):
|
||||
def _build(self, install_dirs, reconfigure) -> None:
|
||||
build_source_dir = self.build_source_dir()
|
||||
self.recreate_dir(self.src_dir, build_source_dir)
|
||||
|
||||
@@ -121,7 +121,7 @@ incremental = false
|
||||
|
||||
def run_tests(
|
||||
self, install_dirs, schedule_type, owner, test_filter, retry, no_testpilot
|
||||
):
|
||||
) -> None:
|
||||
if test_filter:
|
||||
args = ["--", test_filter]
|
||||
else:
|
||||
@@ -138,7 +138,7 @@ incremental = false
|
||||
if self.build_doc:
|
||||
self.run_cargo(install_dirs, "doc", ["--no-deps"] + margs)
|
||||
|
||||
def _patchup_workspace(self):
|
||||
def _patchup_workspace(self) -> None:
|
||||
"""
|
||||
This method makes some assumptions about the state of the project and
|
||||
its cargo dependendies:
|
||||
@@ -184,7 +184,7 @@ incremental = false
|
||||
f.write("\n")
|
||||
f.write(config)
|
||||
|
||||
def _resolve_config(self):
|
||||
def _resolve_config(self) -> str:
|
||||
"""
|
||||
Returns a configuration to be put inside root Cargo.toml file which
|
||||
patches the dependencies git code with local getdeps versions.
|
||||
|
@@ -45,7 +45,7 @@ def find_eden_root(dirpath):
|
||||
return None
|
||||
|
||||
|
||||
def prefetch_dir_if_eden(dirpath):
|
||||
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
|
||||
@@ -65,7 +65,8 @@ def prefetch_dir_if_eden(dirpath):
|
||||
PREFETCHED_DIRS.add(dirpath)
|
||||
|
||||
|
||||
def copytree(src_dir, dest_dir, ignore=None):
|
||||
# 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`.
|
||||
@@ -75,4 +76,7 @@ def copytree(src_dir, dest_dir, ignore=None):
|
||||
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)
|
||||
|
@@ -20,13 +20,13 @@ from .envfuncs import path_search
|
||||
OBJECT_SUBDIRS = ("bin", "lib", "lib64")
|
||||
|
||||
|
||||
def copyfile(src, dest):
|
||||
def copyfile(src, dest) -> None:
|
||||
shutil.copyfile(src, dest)
|
||||
shutil.copymode(src, dest)
|
||||
|
||||
|
||||
class DepBase(object):
|
||||
def __init__(self, buildopts, install_dirs, strip):
|
||||
def __init__(self, buildopts, install_dirs, strip) -> None:
|
||||
self.buildopts = buildopts
|
||||
self.env = buildopts.compute_env_for_install_dirs(install_dirs)
|
||||
self.install_dirs = install_dirs
|
||||
@@ -36,7 +36,7 @@ class DepBase(object):
|
||||
def list_dynamic_deps(self, objfile):
|
||||
raise RuntimeError("list_dynamic_deps not implemented")
|
||||
|
||||
def interesting_dep(self, d):
|
||||
def interesting_dep(self, d) -> bool:
|
||||
return True
|
||||
|
||||
# final_install_prefix must be the equivalent path to `destdir` on the
|
||||
@@ -44,11 +44,12 @@ class DepBase(object):
|
||||
# is intended to map to `/usr/local` in the install image, then
|
||||
# final_install_prefix='/usr/local'.
|
||||
# If left unspecified, destdir will be used.
|
||||
def process_deps(self, destdir, final_install_prefix=None):
|
||||
def process_deps(self, destdir, final_install_prefix=None) -> None:
|
||||
if self.buildopts.is_windows():
|
||||
lib_dir = "bin"
|
||||
else:
|
||||
lib_dir = "lib"
|
||||
# pyre-fixme[16]: `DepBase` has no attribute `munged_lib_dir`.
|
||||
self.munged_lib_dir = os.path.join(destdir, lib_dir)
|
||||
|
||||
final_lib_dir = os.path.join(final_install_prefix or destdir, lib_dir)
|
||||
@@ -92,7 +93,7 @@ class DepBase(object):
|
||||
|
||||
return dep_paths
|
||||
|
||||
def munge_in_place(self, objfile, final_lib_dir):
|
||||
def munge_in_place(self, objfile, final_lib_dir) -> None:
|
||||
print("Munging %s" % objfile)
|
||||
for d in self.list_dynamic_deps(objfile):
|
||||
if not self.interesting_dep(d):
|
||||
@@ -103,6 +104,7 @@ class DepBase(object):
|
||||
dep = self.resolve_loader_path(d)
|
||||
print("dep: %s -> %s" % (d, dep))
|
||||
if dep:
|
||||
# pyre-fixme[16]: `DepBase` has no attribute `munged_lib_dir`.
|
||||
dest_dep = os.path.join(self.munged_lib_dir, os.path.basename(dep))
|
||||
if dep not in self.processed_deps:
|
||||
self.processed_deps.add(dep)
|
||||
@@ -128,7 +130,7 @@ class DepBase(object):
|
||||
return candidate
|
||||
return None
|
||||
|
||||
def list_objs_in_dir(self, dir, recurse=False, output_prefix=""):
|
||||
def list_objs_in_dir(self, dir, recurse: bool = False, output_prefix: str = ""):
|
||||
for entry in os.listdir(dir):
|
||||
entry_path = os.path.join(dir, entry)
|
||||
st = os.lstat(entry_path)
|
||||
@@ -143,21 +145,21 @@ class DepBase(object):
|
||||
):
|
||||
yield result
|
||||
|
||||
def is_objfile(self, objfile):
|
||||
def is_objfile(self, objfile) -> bool:
|
||||
return True
|
||||
|
||||
def strip_debug_info(self, objfile):
|
||||
def strip_debug_info(self, objfile) -> None:
|
||||
"""override this to define how to remove debug information
|
||||
from an object file"""
|
||||
pass
|
||||
|
||||
|
||||
class WinDeps(DepBase):
|
||||
def __init__(self, buildopts, install_dirs, strip):
|
||||
def __init__(self, buildopts, install_dirs, strip) -> None:
|
||||
super(WinDeps, self).__init__(buildopts, install_dirs, strip)
|
||||
self.dumpbin = self.find_dumpbin()
|
||||
|
||||
def find_dumpbin(self):
|
||||
def find_dumpbin(self) -> str:
|
||||
# Looking for dumpbin in the following hardcoded paths.
|
||||
# The registry option to find the install dir doesn't work anymore.
|
||||
globs = [
|
||||
@@ -196,7 +198,7 @@ class WinDeps(DepBase):
|
||||
|
||||
return deps
|
||||
|
||||
def rewrite_dep(self, objfile, depname, old_dep, new_dep, final_lib_dir):
|
||||
def rewrite_dep(self, objfile, depname, old_dep, new_dep, final_lib_dir) -> None:
|
||||
# We can't rewrite on windows, but we will
|
||||
# place the deps alongside the exe so that
|
||||
# they end up in the search path
|
||||
@@ -217,21 +219,21 @@ class WinDeps(DepBase):
|
||||
]
|
||||
)
|
||||
|
||||
def interesting_dep(self, d):
|
||||
def interesting_dep(self, d) -> bool:
|
||||
if "api-ms-win-crt" in d:
|
||||
return False
|
||||
if d in self.SYSTEM_DLLS:
|
||||
return False
|
||||
return True
|
||||
|
||||
def is_objfile(self, objfile):
|
||||
def is_objfile(self, objfile) -> bool:
|
||||
if not os.path.isfile(objfile):
|
||||
return False
|
||||
if objfile.lower().endswith(".exe"):
|
||||
return True
|
||||
return False
|
||||
|
||||
def emit_dev_run_script(self, script_path, dep_dirs):
|
||||
def emit_dev_run_script(self, script_path, dep_dirs) -> None:
|
||||
"""Emit a script that can be used to run build artifacts directly from the
|
||||
build directory, without installing them.
|
||||
|
||||
@@ -297,7 +299,7 @@ class WinDeps(DepBase):
|
||||
|
||||
return dep_dirs
|
||||
|
||||
def _get_dev_run_script_contents(self, path_dirs):
|
||||
def _get_dev_run_script_contents(self, path_dirs) -> str:
|
||||
path_entries = ["$env:PATH"] + path_dirs
|
||||
path_str = ";".join(path_entries)
|
||||
return """\
|
||||
@@ -316,7 +318,7 @@ try {{
|
||||
|
||||
|
||||
class ElfDeps(DepBase):
|
||||
def __init__(self, buildopts, install_dirs, strip):
|
||||
def __init__(self, buildopts, install_dirs, strip) -> None:
|
||||
super(ElfDeps, self).__init__(buildopts, install_dirs, strip)
|
||||
|
||||
# We need patchelf to rewrite deps, so ensure that it is built...
|
||||
@@ -342,15 +344,17 @@ class ElfDeps(DepBase):
|
||||
lines = out.split("\n")
|
||||
return lines
|
||||
|
||||
def rewrite_dep(self, objfile, depname, old_dep, new_dep, final_lib_dir):
|
||||
def rewrite_dep(self, objfile, depname, old_dep, new_dep, final_lib_dir) -> None:
|
||||
final_dep = os.path.join(
|
||||
final_lib_dir, os.path.relpath(new_dep, self.munged_lib_dir)
|
||||
final_lib_dir,
|
||||
# pyre-fixme[16]: `ElfDeps` has no attribute `munged_lib_dir`.
|
||||
os.path.relpath(new_dep, self.munged_lib_dir),
|
||||
)
|
||||
subprocess.check_call(
|
||||
[self.patchelf, "--replace-needed", depname, final_dep, objfile]
|
||||
)
|
||||
|
||||
def is_objfile(self, objfile):
|
||||
def is_objfile(self, objfile) -> bool:
|
||||
if not os.path.isfile(objfile):
|
||||
return False
|
||||
with open(objfile, "rb") as f:
|
||||
@@ -358,7 +362,7 @@ class ElfDeps(DepBase):
|
||||
magic = f.read(4)
|
||||
return magic == b"\x7fELF"
|
||||
|
||||
def strip_debug_info(self, objfile):
|
||||
def strip_debug_info(self, objfile) -> None:
|
||||
subprocess.check_call(["strip", objfile])
|
||||
|
||||
|
||||
@@ -367,7 +371,7 @@ MACH_MAGIC = 0xFEEDFACF
|
||||
|
||||
|
||||
class MachDeps(DepBase):
|
||||
def interesting_dep(self, d):
|
||||
def interesting_dep(self, d) -> bool:
|
||||
if d.startswith("/usr/lib/") or d.startswith("/System/"):
|
||||
return False
|
||||
return True
|
||||
@@ -403,7 +407,7 @@ class MachDeps(DepBase):
|
||||
deps.append(os.path.normcase(m.group(1)))
|
||||
return deps
|
||||
|
||||
def rewrite_dep(self, objfile, depname, old_dep, new_dep, final_lib_dir):
|
||||
def rewrite_dep(self, objfile, depname, old_dep, new_dep, final_lib_dir) -> None:
|
||||
if objfile.endswith(".dylib"):
|
||||
# Erase the original location from the id of the shared
|
||||
# object. It doesn't appear to hurt to retain it, but
|
||||
@@ -412,7 +416,9 @@ class MachDeps(DepBase):
|
||||
["install_name_tool", "-id", os.path.basename(objfile), objfile]
|
||||
)
|
||||
final_dep = os.path.join(
|
||||
final_lib_dir, os.path.relpath(new_dep, self.munged_lib_dir)
|
||||
final_lib_dir,
|
||||
# pyre-fixme[16]: `MachDeps` has no attribute `munged_lib_dir`.
|
||||
os.path.relpath(new_dep, self.munged_lib_dir),
|
||||
)
|
||||
|
||||
subprocess.check_call(
|
||||
@@ -420,7 +426,9 @@ class MachDeps(DepBase):
|
||||
)
|
||||
|
||||
|
||||
def create_dyn_dep_munger(buildopts, install_dirs, strip=False) -> Optional[DepBase]:
|
||||
def create_dyn_dep_munger(
|
||||
buildopts, install_dirs, strip: bool = False
|
||||
) -> Optional[DepBase]:
|
||||
if buildopts.is_linux():
|
||||
return ElfDeps(buildopts, install_dirs, strip)
|
||||
if buildopts.is_darwin():
|
||||
|
@@ -9,18 +9,18 @@ import sys
|
||||
|
||||
|
||||
class Env(object):
|
||||
def __init__(self, src=None):
|
||||
def __init__(self, src=None) -> None:
|
||||
self._dict = {}
|
||||
if src is None:
|
||||
self.update(os.environ)
|
||||
else:
|
||||
self.update(src)
|
||||
|
||||
def update(self, src):
|
||||
def update(self, src) -> None:
|
||||
for k, v in src.items():
|
||||
self.set(k, v)
|
||||
|
||||
def copy(self):
|
||||
def copy(self) -> "Env":
|
||||
return Env(self._dict)
|
||||
|
||||
def _key(self, key):
|
||||
@@ -64,7 +64,7 @@ class Env(object):
|
||||
raise KeyError(key)
|
||||
return val
|
||||
|
||||
def unset(self, key):
|
||||
def unset(self, key) -> None:
|
||||
if key is None:
|
||||
raise KeyError("attempting to unset env[None]")
|
||||
|
||||
@@ -72,13 +72,13 @@ class Env(object):
|
||||
if key:
|
||||
del self._dict[key]
|
||||
|
||||
def __delitem__(self, key):
|
||||
def __delitem__(self, key) -> None:
|
||||
self.unset(key)
|
||||
|
||||
def __repr__(self):
|
||||
return repr(self._dict)
|
||||
|
||||
def set(self, key, value):
|
||||
def set(self, key, value) -> None:
|
||||
if key is None:
|
||||
raise KeyError("attempting to assign env[None] = %r" % value)
|
||||
|
||||
@@ -99,13 +99,13 @@ class Env(object):
|
||||
self.unset(key)
|
||||
self._dict[key] = value
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
def __setitem__(self, key, value) -> None:
|
||||
self.set(key, value)
|
||||
|
||||
def __iter__(self):
|
||||
return self._dict.__iter__()
|
||||
|
||||
def __len__(self):
|
||||
def __len__(self) -> int:
|
||||
return len(self._dict)
|
||||
|
||||
def keys(self):
|
||||
@@ -118,7 +118,9 @@ class Env(object):
|
||||
return self._dict.items()
|
||||
|
||||
|
||||
def add_path_entry(env, name, item, append=True, separator=os.pathsep):
|
||||
def add_path_entry(
|
||||
env, name, item, append: bool = True, separator: str = os.pathsep
|
||||
) -> None:
|
||||
"""Cause `item` to be added to the path style env var named
|
||||
`name` held in the `env` dict. `append` specifies whether
|
||||
the item is added to the end (the default) or should be
|
||||
@@ -135,7 +137,7 @@ def add_path_entry(env, name, item, append=True, separator=os.pathsep):
|
||||
env.set(name, separator.join(val))
|
||||
|
||||
|
||||
def add_flag(env, name, flag, append=True):
|
||||
def add_flag(env, name, flag, append: bool = True) -> None:
|
||||
"""Cause `flag` to be added to the CXXFLAGS-style env var named
|
||||
`name` held in the `env` dict. `append` specifies whether the
|
||||
flag is added to the end (the default) or should be prepended if
|
||||
@@ -152,7 +154,7 @@ _path_search_cache = {}
|
||||
_not_found = object()
|
||||
|
||||
|
||||
def tpx_path():
|
||||
def tpx_path() -> str:
|
||||
return "xplat/testinfra/tpx/ctp.tpx"
|
||||
|
||||
|
||||
|
@@ -13,5 +13,5 @@ class TransientFailure(Exception):
|
||||
|
||||
|
||||
class ManifestNotFound(Exception):
|
||||
def __init__(self, manifest_name):
|
||||
def __init__(self, manifest_name) -> None:
|
||||
super(Exception, self).__init__("Unable to find manifest '%s'" % manifest_name)
|
||||
|
@@ -37,40 +37,40 @@ def parse_expr(expr_text, valid_variables):
|
||||
|
||||
|
||||
class ExprNode(object):
|
||||
def eval(self, ctx):
|
||||
def eval(self, ctx) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
class TrueExpr(ExprNode):
|
||||
def eval(self, ctx):
|
||||
def eval(self, ctx) -> bool:
|
||||
return True
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
return "true"
|
||||
|
||||
|
||||
class NotExpr(ExprNode):
|
||||
def __init__(self, node):
|
||||
def __init__(self, node) -> None:
|
||||
self._node = node
|
||||
|
||||
def eval(self, ctx):
|
||||
def eval(self, ctx) -> bool:
|
||||
return not self._node.eval(ctx)
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
return "not(%s)" % self._node
|
||||
|
||||
|
||||
class AllExpr(ExprNode):
|
||||
def __init__(self, nodes):
|
||||
def __init__(self, nodes) -> None:
|
||||
self._nodes = nodes
|
||||
|
||||
def eval(self, ctx):
|
||||
def eval(self, ctx) -> bool:
|
||||
for node in self._nodes:
|
||||
if not node.eval(ctx):
|
||||
return False
|
||||
return True
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
items = []
|
||||
for node in self._nodes:
|
||||
items.append(str(node))
|
||||
@@ -78,16 +78,16 @@ class AllExpr(ExprNode):
|
||||
|
||||
|
||||
class AnyExpr(ExprNode):
|
||||
def __init__(self, nodes):
|
||||
def __init__(self, nodes) -> None:
|
||||
self._nodes = nodes
|
||||
|
||||
def eval(self, ctx):
|
||||
def eval(self, ctx) -> bool:
|
||||
for node in self._nodes:
|
||||
if node.eval(ctx):
|
||||
return True
|
||||
return False
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
items = []
|
||||
for node in self._nodes:
|
||||
items.append(str(node))
|
||||
@@ -95,19 +95,19 @@ class AnyExpr(ExprNode):
|
||||
|
||||
|
||||
class EqualExpr(ExprNode):
|
||||
def __init__(self, key, value):
|
||||
def __init__(self, key, value) -> None:
|
||||
self._key = key
|
||||
self._value = value
|
||||
|
||||
def eval(self, ctx):
|
||||
return ctx.get(self._key) == self._value
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
return "%s=%s" % (self._key, self._value)
|
||||
|
||||
|
||||
class Parser(object):
|
||||
def __init__(self, text, valid_variables):
|
||||
def __init__(self, text, valid_variables) -> None:
|
||||
self.text = text
|
||||
self.lex = shlex.shlex(text)
|
||||
self.valid_variables = valid_variables
|
||||
@@ -147,13 +147,13 @@ class Parser(object):
|
||||
"Unexpected token sequence '%s %s' in %s" % (name, op, self.text)
|
||||
)
|
||||
|
||||
def ident(self):
|
||||
def ident(self) -> str:
|
||||
ident = self.lex.get_token()
|
||||
if not re.match("[a-zA-Z]+", ident):
|
||||
raise Exception("expected identifier found %s" % ident)
|
||||
return ident
|
||||
|
||||
def parse_not(self):
|
||||
def parse_not(self) -> NotExpr:
|
||||
node = self.top()
|
||||
expr = NotExpr(node)
|
||||
tok = self.lex.get_token()
|
||||
@@ -161,7 +161,7 @@ class Parser(object):
|
||||
raise Exception("expected ')' found %s" % tok)
|
||||
return expr
|
||||
|
||||
def parse_any(self):
|
||||
def parse_any(self) -> AnyExpr:
|
||||
nodes = []
|
||||
while True:
|
||||
nodes.append(self.top())
|
||||
@@ -172,7 +172,7 @@ class Parser(object):
|
||||
raise Exception("expected ',' or ')' but found %s" % tok)
|
||||
return AnyExpr(nodes)
|
||||
|
||||
def parse_all(self):
|
||||
def parse_all(self) -> AllExpr:
|
||||
nodes = []
|
||||
while True:
|
||||
nodes.append(self.top())
|
||||
|
@@ -50,7 +50,7 @@ class ChangeStatus(object):
|
||||
and whether we might need to reconfigure the build system.
|
||||
"""
|
||||
|
||||
def __init__(self, all_changed=False):
|
||||
def __init__(self, all_changed: bool = False) -> None:
|
||||
"""Construct a ChangeStatus object. The default is to create
|
||||
a status that indicates no changes, but passing all_changed=True
|
||||
will create one that indicates that everything changed"""
|
||||
@@ -61,7 +61,7 @@ class ChangeStatus(object):
|
||||
self.source_files = 0
|
||||
self.make_files = 0
|
||||
|
||||
def record_change(self, file_name):
|
||||
def record_change(self, file_name) -> None:
|
||||
"""Used by the shipit fetcher to record changes as it updates
|
||||
files in the destination. If the file name might be one used
|
||||
in the cmake build system that we use for 1st party code, then
|
||||
@@ -81,14 +81,14 @@ class ChangeStatus(object):
|
||||
elif "/fbcode_builder/" not in file_name:
|
||||
self.source_files += 1
|
||||
|
||||
def sources_changed(self):
|
||||
def sources_changed(self) -> bool:
|
||||
"""Returns true if any source files were changed during
|
||||
an update operation. This will typically be used to decide
|
||||
that the build system to be run on the source dir in an
|
||||
incremental mode"""
|
||||
return self.source_files > 0
|
||||
|
||||
def build_changed(self):
|
||||
def build_changed(self) -> bool:
|
||||
"""Returns true if any build files were changed during
|
||||
an update operation. This will typically be used to decidfe
|
||||
that the build system should be reconfigured and re-run
|
||||
@@ -102,7 +102,7 @@ class Fetcher(object):
|
||||
extracted data resides and reports this to the consumer via
|
||||
its `get_src_dir` method."""
|
||||
|
||||
def update(self):
|
||||
def update(self) -> ChangeStatus:
|
||||
"""Brings the src dir up to date, ideally minimizing
|
||||
changes so that a subsequent build doesn't over-build.
|
||||
Returns a ChangeStatus object that helps the caller to
|
||||
@@ -110,12 +110,12 @@ class Fetcher(object):
|
||||
the update."""
|
||||
return ChangeStatus()
|
||||
|
||||
def clean(self):
|
||||
def clean(self) -> None:
|
||||
"""Reverts any changes that might have been made to
|
||||
the src dir"""
|
||||
pass
|
||||
|
||||
def hash(self):
|
||||
def hash(self) -> None:
|
||||
"""Returns a hash that identifies the version of the code in the
|
||||
working copy. For a git repo this is commit hash for the working
|
||||
copy. For other Fetchers this should relate to the version of
|
||||
@@ -128,7 +128,7 @@ class Fetcher(object):
|
||||
"""
|
||||
pass
|
||||
|
||||
def get_src_dir(self):
|
||||
def get_src_dir(self) -> None:
|
||||
"""Returns the source directory that the project was
|
||||
extracted into"""
|
||||
pass
|
||||
@@ -141,13 +141,13 @@ class LocalDirFetcher(object):
|
||||
This fetcher cannot update or track changes. It always reports that the
|
||||
project has changed, forcing it to always be built."""
|
||||
|
||||
def __init__(self, path):
|
||||
def __init__(self, path) -> None:
|
||||
self.path = os.path.realpath(path)
|
||||
|
||||
def update(self):
|
||||
def update(self) -> ChangeStatus:
|
||||
return ChangeStatus(all_changed=True)
|
||||
|
||||
def hash(self):
|
||||
def hash(self) -> str:
|
||||
return "0" * 40
|
||||
|
||||
def get_src_dir(self):
|
||||
@@ -155,7 +155,7 @@ class LocalDirFetcher(object):
|
||||
|
||||
|
||||
class SystemPackageFetcher(object):
|
||||
def __init__(self, build_options, packages):
|
||||
def __init__(self, build_options, packages) -> None:
|
||||
self.manager = build_options.host_type.get_package_manager()
|
||||
self.packages = packages.get(self.manager)
|
||||
self.host_type = build_options.host_type
|
||||
@@ -190,29 +190,29 @@ class SystemPackageFetcher(object):
|
||||
|
||||
return bool(self.installed)
|
||||
|
||||
def update(self):
|
||||
def update(self) -> ChangeStatus:
|
||||
assert self.installed
|
||||
return ChangeStatus(all_changed=False)
|
||||
|
||||
def hash(self):
|
||||
def hash(self) -> str:
|
||||
if self.packages_are_installed():
|
||||
return hashlib.sha256(self.installed).hexdigest()
|
||||
else:
|
||||
return "0" * 40
|
||||
|
||||
def get_src_dir(self):
|
||||
def get_src_dir(self) -> None:
|
||||
return None
|
||||
|
||||
|
||||
class PreinstalledNopFetcher(SystemPackageFetcher):
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
self.installed = True
|
||||
|
||||
|
||||
class GitFetcher(Fetcher):
|
||||
DEFAULT_DEPTH = 1
|
||||
|
||||
def __init__(self, build_options, manifest, repo_url, rev, depth):
|
||||
def __init__(self, build_options, manifest, repo_url, rev, depth) -> None:
|
||||
# Extract the host/path portions of the URL and generate a flattened
|
||||
# directory name. eg:
|
||||
# github.com/facebook/folly.git -> github.com-facebook-folly.git
|
||||
@@ -246,7 +246,7 @@ class GitFetcher(Fetcher):
|
||||
self.manifest = manifest
|
||||
self.depth = depth if depth else GitFetcher.DEFAULT_DEPTH
|
||||
|
||||
def _update(self):
|
||||
def _update(self) -> ChangeStatus:
|
||||
current_hash = (
|
||||
subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=self.repo_dir)
|
||||
.strip()
|
||||
@@ -281,7 +281,7 @@ class GitFetcher(Fetcher):
|
||||
self._clone()
|
||||
return ChangeStatus(True)
|
||||
|
||||
def _clone(self):
|
||||
def _clone(self) -> None:
|
||||
print("Cloning %s..." % self.origin_repo)
|
||||
# The basename/dirname stuff allows us to dance around issues where
|
||||
# eg: this python process is native win32, but the git.exe is cygwin
|
||||
@@ -300,7 +300,7 @@ class GitFetcher(Fetcher):
|
||||
)
|
||||
self._update()
|
||||
|
||||
def clean(self):
|
||||
def clean(self) -> None:
|
||||
if os.path.exists(self.repo_dir):
|
||||
run_cmd(["git", "clean", "-fxd"], cwd=self.repo_dir)
|
||||
|
||||
@@ -343,7 +343,7 @@ def does_file_need_update(src_name, src_st, dest_name):
|
||||
return False
|
||||
|
||||
|
||||
def copy_if_different(src_name, dest_name):
|
||||
def copy_if_different(src_name, dest_name) -> bool:
|
||||
"""Copy src_name -> dest_name, but only touch dest_name
|
||||
if src_name is different from dest_name, making this a
|
||||
more build system friendly way to copy."""
|
||||
@@ -380,22 +380,22 @@ def list_files_under_dir_newer_than_timestamp(dir_to_scan, ts):
|
||||
|
||||
|
||||
class ShipitPathMap(object):
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
self.roots = []
|
||||
self.mapping = []
|
||||
self.exclusion = []
|
||||
|
||||
def add_mapping(self, fbsource_dir, target_dir):
|
||||
def add_mapping(self, fbsource_dir, target_dir) -> None:
|
||||
"""Add a posix path or pattern. We cannot normpath the input
|
||||
here because that would change the paths from posix to windows
|
||||
form and break the logic throughout this class."""
|
||||
self.roots.append(fbsource_dir)
|
||||
self.mapping.append((fbsource_dir, target_dir))
|
||||
|
||||
def add_exclusion(self, pattern):
|
||||
def add_exclusion(self, pattern) -> None:
|
||||
self.exclusion.append(re.compile(pattern))
|
||||
|
||||
def _minimize_roots(self):
|
||||
def _minimize_roots(self) -> None:
|
||||
"""compute the de-duplicated set of roots within fbsource.
|
||||
We take the shortest common directory prefix to make this
|
||||
determination"""
|
||||
@@ -413,7 +413,7 @@ class ShipitPathMap(object):
|
||||
|
||||
self.roots = minimized
|
||||
|
||||
def _sort_mapping(self):
|
||||
def _sort_mapping(self) -> None:
|
||||
self.mapping.sort(reverse=True, key=lambda x: len(x[0]))
|
||||
|
||||
def _map_name(self, norm_name, dest_root):
|
||||
@@ -442,7 +442,7 @@ class ShipitPathMap(object):
|
||||
|
||||
raise Exception("%s did not match any rules" % norm_name)
|
||||
|
||||
def mirror(self, fbsource_root, dest_root):
|
||||
def mirror(self, fbsource_root, dest_root) -> ChangeStatus:
|
||||
self._minimize_roots()
|
||||
self._sort_mapping()
|
||||
|
||||
@@ -516,7 +516,7 @@ class FbsourceRepoData(NamedTuple):
|
||||
FBSOURCE_REPO_DATA: Dict[str, FbsourceRepoData] = {}
|
||||
|
||||
|
||||
def get_fbsource_repo_data(build_options):
|
||||
def get_fbsource_repo_data(build_options) -> FbsourceRepoData:
|
||||
"""Returns the commit metadata for the fbsource repo.
|
||||
Since we may have multiple first party projects to
|
||||
hash, and because we don't mutate the repo, we cache
|
||||
@@ -546,13 +546,13 @@ def get_fbsource_repo_data(build_options):
|
||||
|
||||
|
||||
class SimpleShipitTransformerFetcher(Fetcher):
|
||||
def __init__(self, build_options, manifest, ctx):
|
||||
def __init__(self, build_options, manifest, ctx) -> None:
|
||||
self.build_options = build_options
|
||||
self.manifest = manifest
|
||||
self.repo_dir = os.path.join(build_options.scratch_dir, "shipit", manifest.name)
|
||||
self.ctx = ctx
|
||||
|
||||
def clean(self):
|
||||
def clean(self) -> None:
|
||||
if os.path.exists(self.repo_dir):
|
||||
shutil.rmtree(self.repo_dir)
|
||||
|
||||
@@ -571,7 +571,8 @@ class SimpleShipitTransformerFetcher(Fetcher):
|
||||
|
||||
return mapping.mirror(self.build_options.fbsource_dir, self.repo_dir)
|
||||
|
||||
def hash(self):
|
||||
# pyre-fixme[15]: `hash` overrides method defined in `Fetcher` inconsistently.
|
||||
def hash(self) -> str:
|
||||
# We return a fixed non-hash string for in-fbsource builds.
|
||||
# We're relying on the `update` logic to correctly invalidate
|
||||
# the build in the case that files have changed.
|
||||
@@ -584,18 +585,18 @@ class SimpleShipitTransformerFetcher(Fetcher):
|
||||
class ShipitTransformerFetcher(Fetcher):
|
||||
SHIPIT = "/var/www/scripts/opensource/shipit/run_shipit.php"
|
||||
|
||||
def __init__(self, build_options, project_name):
|
||||
def __init__(self, build_options, project_name) -> None:
|
||||
self.build_options = build_options
|
||||
self.project_name = project_name
|
||||
self.repo_dir = os.path.join(build_options.scratch_dir, "shipit", project_name)
|
||||
|
||||
def update(self):
|
||||
def update(self) -> ChangeStatus:
|
||||
if os.path.exists(self.repo_dir):
|
||||
return ChangeStatus()
|
||||
self.run_shipit()
|
||||
return ChangeStatus(True)
|
||||
|
||||
def clean(self):
|
||||
def clean(self) -> None:
|
||||
if os.path.exists(self.repo_dir):
|
||||
shutil.rmtree(self.repo_dir)
|
||||
|
||||
@@ -603,7 +604,7 @@ class ShipitTransformerFetcher(Fetcher):
|
||||
def available(cls):
|
||||
return os.path.exists(cls.SHIPIT)
|
||||
|
||||
def run_shipit(self):
|
||||
def run_shipit(self) -> None:
|
||||
tmp_path = self.repo_dir + ".new"
|
||||
try:
|
||||
if os.path.exists(tmp_path):
|
||||
@@ -640,7 +641,8 @@ class ShipitTransformerFetcher(Fetcher):
|
||||
self.clean()
|
||||
raise
|
||||
|
||||
def hash(self):
|
||||
# pyre-fixme[15]: `hash` overrides method defined in `Fetcher` inconsistently.
|
||||
def hash(self) -> str:
|
||||
# We return a fixed non-hash string for in-fbsource builds.
|
||||
return "fbsource"
|
||||
|
||||
@@ -648,7 +650,7 @@ class ShipitTransformerFetcher(Fetcher):
|
||||
return self.repo_dir
|
||||
|
||||
|
||||
def download_url_to_file_with_progress(url, file_name):
|
||||
def download_url_to_file_with_progress(url: str, file_name) -> None:
|
||||
print("Download %s -> %s ..." % (url, file_name))
|
||||
|
||||
class Progress(object):
|
||||
@@ -686,7 +688,7 @@ def download_url_to_file_with_progress(url, file_name):
|
||||
|
||||
|
||||
class ArchiveFetcher(Fetcher):
|
||||
def __init__(self, build_options, manifest, url, sha256):
|
||||
def __init__(self, build_options, manifest, url, sha256) -> None:
|
||||
self.manifest = manifest
|
||||
self.url = url
|
||||
self.sha256 = sha256
|
||||
@@ -698,7 +700,7 @@ class ArchiveFetcher(Fetcher):
|
||||
self.src_dir = os.path.join(build_options.scratch_dir, "extracted", basename)
|
||||
self.hash_file = self.src_dir + ".hash"
|
||||
|
||||
def _verify_hash(self):
|
||||
def _verify_hash(self) -> None:
|
||||
h = hashlib.sha256()
|
||||
with open(self.file_name, "rb") as f:
|
||||
while True:
|
||||
@@ -720,16 +722,16 @@ class ArchiveFetcher(Fetcher):
|
||||
os.makedirs(download_dir)
|
||||
return download_dir
|
||||
|
||||
def _download(self):
|
||||
def _download(self) -> None:
|
||||
self._download_dir()
|
||||
download_url_to_file_with_progress(self.url, self.file_name)
|
||||
self._verify_hash()
|
||||
|
||||
def clean(self):
|
||||
def clean(self) -> None:
|
||||
if os.path.exists(self.src_dir):
|
||||
shutil.rmtree(self.src_dir)
|
||||
|
||||
def update(self):
|
||||
def update(self) -> ChangeStatus:
|
||||
try:
|
||||
with open(self.hash_file, "r") as f:
|
||||
saved_hash = f.read().strip()
|
||||
|
@@ -56,7 +56,7 @@ class Loader(object):
|
||||
|
||||
|
||||
class ResourceLoader(Loader):
|
||||
def __init__(self, namespace, manifests_dir):
|
||||
def __init__(self, namespace, manifests_dir) -> None:
|
||||
self.namespace = namespace
|
||||
self.manifests_dir = manifests_dir
|
||||
|
||||
@@ -82,7 +82,7 @@ class ResourceLoader(Loader):
|
||||
|
||||
raise ManifestNotFound(project_name)
|
||||
|
||||
def _load_manifest(self, path):
|
||||
def _load_manifest(self, path: str):
|
||||
import pkg_resources
|
||||
|
||||
contents = pkg_resources.resource_string(self.namespace, path).decode("utf8")
|
||||
@@ -96,7 +96,7 @@ class ResourceLoader(Loader):
|
||||
LOADER = Loader()
|
||||
|
||||
|
||||
def patch_loader(namespace, manifests_dir="manifests"):
|
||||
def patch_loader(namespace, manifests_dir: str = "manifests") -> None:
|
||||
global LOADER
|
||||
LOADER = ResourceLoader(namespace, manifests_dir)
|
||||
|
||||
@@ -119,7 +119,7 @@ class ManifestLoader(object):
|
||||
relationships and project hash values for this build configuration.
|
||||
"""
|
||||
|
||||
def __init__(self, build_opts, ctx_gen=None):
|
||||
def __init__(self, build_opts, ctx_gen=None) -> None:
|
||||
self._loader = LOADER
|
||||
self.build_opts = build_opts
|
||||
if ctx_gen is None:
|
||||
@@ -231,16 +231,16 @@ class ManifestLoader(object):
|
||||
|
||||
return dep_order
|
||||
|
||||
def set_project_src_dir(self, project_name, path):
|
||||
def set_project_src_dir(self, project_name, path) -> None:
|
||||
self._fetcher_overrides[project_name] = fetcher.LocalDirFetcher(path)
|
||||
|
||||
def set_project_build_dir(self, project_name, path):
|
||||
def set_project_build_dir(self, project_name, path) -> None:
|
||||
self._build_dir_overrides[project_name] = path
|
||||
|
||||
def set_project_install_dir(self, project_name, path):
|
||||
def set_project_install_dir(self, project_name, path) -> None:
|
||||
self._install_dir_overrides[project_name] = path
|
||||
|
||||
def set_project_install_prefix(self, project_name, path):
|
||||
def set_project_install_prefix(self, project_name, path) -> None:
|
||||
self._install_prefix_overrides[project_name] = path
|
||||
|
||||
def create_fetcher(self, manifest):
|
||||
@@ -258,7 +258,7 @@ class ManifestLoader(object):
|
||||
self._project_hashes[manifest.name] = h
|
||||
return h
|
||||
|
||||
def _compute_project_hash(self, manifest):
|
||||
def _compute_project_hash(self, manifest) -> str:
|
||||
"""This recursive function computes a hash for a given manifest.
|
||||
The hash takes into account some environmental factors on the
|
||||
host machine and includes the hashes of its dependencies.
|
||||
|
@@ -9,7 +9,7 @@ import shlex
|
||||
import sys
|
||||
|
||||
|
||||
def is_windows():
|
||||
def is_windows() -> bool:
|
||||
"""Returns true if the system we are currently running on
|
||||
is a Windows system"""
|
||||
return sys.platform.startswith("win")
|
||||
@@ -52,7 +52,7 @@ def get_linux_type():
|
||||
# but getdeps can't take third-party dependencies.
|
||||
|
||||
|
||||
def _get_available_ram_linux():
|
||||
def _get_available_ram_linux() -> int:
|
||||
# TODO: Ideally, this function would inspect the current cgroup for any
|
||||
# limits, rather than solely relying on system RAM.
|
||||
with open("/proc/meminfo") as f:
|
||||
@@ -175,7 +175,7 @@ def get_available_ram() -> int:
|
||||
|
||||
|
||||
class HostType(object):
|
||||
def __init__(self, ostype=None, distro=None, distrovers=None):
|
||||
def __init__(self, ostype=None, distro=None, distrovers=None) -> None:
|
||||
if ostype is None:
|
||||
distro = None
|
||||
distrovers = None
|
||||
@@ -185,6 +185,7 @@ class HostType(object):
|
||||
ostype = "darwin"
|
||||
elif is_windows():
|
||||
ostype = "windows"
|
||||
# pyre-fixme[16]: Module `sys` has no attribute `getwindowsversion`.
|
||||
distrovers = str(sys.getwindowsversion().major)
|
||||
elif sys.platform.startswith("freebsd"):
|
||||
ostype = "freebsd"
|
||||
@@ -218,7 +219,7 @@ class HostType(object):
|
||||
def is_freebsd(self):
|
||||
return self.ostype == "freebsd"
|
||||
|
||||
def as_tuple_string(self):
|
||||
def as_tuple_string(self) -> str:
|
||||
return "%s-%s-%s" % (
|
||||
self.ostype,
|
||||
self.distro or "none",
|
||||
@@ -237,7 +238,7 @@ class HostType(object):
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def from_tuple_string(s):
|
||||
def from_tuple_string(s) -> "HostType":
|
||||
ostype, distro, distrovers = s.split("-")
|
||||
return HostType(ostype=ostype, distro=distro, distrovers=distrovers)
|
||||
|
||||
|
@@ -212,7 +212,7 @@ class PythonWheelBuilder(BuilderBase):
|
||||
|
||||
f.write(CMAKE_FOOTER.format(**self.template_format_dict))
|
||||
|
||||
def _write_cmake_config_template(self):
|
||||
def _write_cmake_config_template(self) -> None:
|
||||
config_path_name = self.manifest.name + "-config.cmake.in"
|
||||
output_path = os.path.join(self.build_dir, config_path_name)
|
||||
|
||||
|
@@ -22,7 +22,7 @@ class RunCommandError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def _print_env_diff(env, log_fn):
|
||||
def _print_env_diff(env, log_fn) -> None:
|
||||
current_keys = set(os.environ.keys())
|
||||
wanted_env = set(env.keys())
|
||||
|
||||
@@ -44,7 +44,7 @@ def _print_env_diff(env, log_fn):
|
||||
log_fn("+ %s=%s \\\n" % (k, shellquote(env[k])))
|
||||
|
||||
|
||||
def run_cmd(cmd, env=None, cwd=None, allow_fail=False, log_file=None):
|
||||
def run_cmd(cmd, env=None, cwd=None, allow_fail: bool = False, log_file=None):
|
||||
def log_to_stdout(msg):
|
||||
sys.stdout.buffer.write(msg.encode(errors="surrogateescape"))
|
||||
|
||||
@@ -64,7 +64,7 @@ def run_cmd(cmd, env=None, cwd=None, allow_fail=False, log_file=None):
|
||||
)
|
||||
|
||||
|
||||
def _run_cmd(cmd, env, cwd, allow_fail, log_fn):
|
||||
def _run_cmd(cmd, env, cwd, allow_fail, log_fn) -> int:
|
||||
log_fn("---\n")
|
||||
try:
|
||||
cmd_str = " \\\n+ ".join(shellquote(arg) for arg in cmd)
|
||||
|
@@ -8,11 +8,11 @@ class SubCmd(object):
|
||||
NAME = None
|
||||
HELP = None
|
||||
|
||||
def run(self, args):
|
||||
def run(self, args) -> int:
|
||||
"""perform the command"""
|
||||
return 0
|
||||
|
||||
def setup_parser(self, parser):
|
||||
def setup_parser(self, parser) -> None:
|
||||
# Subclasses should override setup_parser() if they have any
|
||||
# command line options or arguments.
|
||||
pass
|
||||
@@ -21,7 +21,7 @@ class SubCmd(object):
|
||||
CmdTable = []
|
||||
|
||||
|
||||
def add_subcommands(parser, common_args, cmd_table=CmdTable):
|
||||
def add_subcommands(parser, common_args, cmd_table=CmdTable) -> None:
|
||||
"""Register parsers for the defined commands with the provided parser"""
|
||||
for cls in cmd_table:
|
||||
command = cls()
|
||||
|
@@ -10,37 +10,37 @@ from ..expr import parse_expr
|
||||
|
||||
|
||||
class ExprTest(unittest.TestCase):
|
||||
def test_equal(self):
|
||||
def test_equal(self) -> None:
|
||||
valid_variables = {"foo", "some_var", "another_var"}
|
||||
e = parse_expr("foo=bar", valid_variables)
|
||||
self.assertTrue(e.eval({"foo": "bar"}))
|
||||
self.assertFalse(e.eval({"foo": "not-bar"}))
|
||||
self.assertFalse(e.eval({"not-foo": "bar"}))
|
||||
|
||||
def test_not_equal(self):
|
||||
def test_not_equal(self) -> None:
|
||||
valid_variables = {"foo"}
|
||||
e = parse_expr("not(foo=bar)", valid_variables)
|
||||
self.assertFalse(e.eval({"foo": "bar"}))
|
||||
self.assertTrue(e.eval({"foo": "not-bar"}))
|
||||
|
||||
def test_bad_not(self):
|
||||
def test_bad_not(self) -> None:
|
||||
valid_variables = {"foo"}
|
||||
with self.assertRaises(Exception):
|
||||
parse_expr("foo=not(bar)", valid_variables)
|
||||
|
||||
def test_bad_variable(self):
|
||||
def test_bad_variable(self) -> None:
|
||||
valid_variables = {"bar"}
|
||||
with self.assertRaises(Exception):
|
||||
parse_expr("foo=bar", valid_variables)
|
||||
|
||||
def test_all(self):
|
||||
def test_all(self) -> None:
|
||||
valid_variables = {"foo", "baz"}
|
||||
e = parse_expr("all(foo = bar, baz = qux)", valid_variables)
|
||||
self.assertTrue(e.eval({"foo": "bar", "baz": "qux"}))
|
||||
self.assertFalse(e.eval({"foo": "bar", "baz": "nope"}))
|
||||
self.assertFalse(e.eval({"foo": "nope", "baz": "nope"}))
|
||||
|
||||
def test_any(self):
|
||||
def test_any(self) -> None:
|
||||
valid_variables = {"foo", "baz"}
|
||||
e = parse_expr("any(foo = bar, baz = qux)", valid_variables)
|
||||
self.assertTrue(e.eval({"foo": "bar", "baz": "qux"}))
|
||||
|
@@ -12,13 +12,13 @@ from ..manifest import ManifestParser
|
||||
|
||||
|
||||
class ManifestTest(unittest.TestCase):
|
||||
def test_missing_section(self):
|
||||
def test_missing_section(self) -> None:
|
||||
with self.assertRaisesRegex(
|
||||
Exception, "manifest file test is missing required section manifest"
|
||||
):
|
||||
ManifestParser("test", "")
|
||||
|
||||
def test_missing_name(self):
|
||||
def test_missing_name(self) -> None:
|
||||
with self.assertRaisesRegex(
|
||||
Exception,
|
||||
"manifest file test section 'manifest' is missing required field 'name'",
|
||||
@@ -30,7 +30,7 @@ class ManifestTest(unittest.TestCase):
|
||||
""",
|
||||
)
|
||||
|
||||
def test_minimal(self):
|
||||
def test_minimal(self) -> None:
|
||||
p = ManifestParser(
|
||||
"test",
|
||||
"""
|
||||
@@ -41,7 +41,7 @@ name = test
|
||||
self.assertEqual(p.name, "test")
|
||||
self.assertEqual(p.fbsource_path, None)
|
||||
|
||||
def test_minimal_with_fbsource_path(self):
|
||||
def test_minimal_with_fbsource_path(self) -> None:
|
||||
p = ManifestParser(
|
||||
"test",
|
||||
"""
|
||||
@@ -53,7 +53,7 @@ fbsource_path = fbcode/wat
|
||||
self.assertEqual(p.name, "test")
|
||||
self.assertEqual(p.fbsource_path, "fbcode/wat")
|
||||
|
||||
def test_unknown_field(self):
|
||||
def test_unknown_field(self) -> None:
|
||||
with self.assertRaisesRegex(
|
||||
Exception,
|
||||
(
|
||||
@@ -70,7 +70,7 @@ invalid.field = woot
|
||||
""",
|
||||
)
|
||||
|
||||
def test_invalid_section_name(self):
|
||||
def test_invalid_section_name(self) -> None:
|
||||
with self.assertRaisesRegex(
|
||||
Exception, "manifest file test contains unknown section 'invalid.section'"
|
||||
):
|
||||
@@ -85,7 +85,7 @@ foo = bar
|
||||
""",
|
||||
)
|
||||
|
||||
def test_value_in_dependencies_section(self):
|
||||
def test_value_in_dependencies_section(self) -> None:
|
||||
with self.assertRaisesRegex(
|
||||
Exception,
|
||||
(
|
||||
@@ -105,7 +105,7 @@ foo = bar
|
||||
""",
|
||||
)
|
||||
|
||||
def test_invalid_conditional_section_name(self):
|
||||
def test_invalid_conditional_section_name(self) -> None:
|
||||
with self.assertRaisesRegex(
|
||||
Exception,
|
||||
(
|
||||
@@ -124,7 +124,7 @@ name = test
|
||||
""",
|
||||
)
|
||||
|
||||
def test_section_as_args(self):
|
||||
def test_section_as_args(self) -> None:
|
||||
p = ManifestParser(
|
||||
"test",
|
||||
"""
|
||||
@@ -164,7 +164,7 @@ name = test
|
||||
p2.get_section_as_args("autoconf.args"), ["--prefix=/foo", "--with-woot"]
|
||||
)
|
||||
|
||||
def test_section_as_dict(self):
|
||||
def test_section_as_dict(self) -> None:
|
||||
p = ManifestParser(
|
||||
"test",
|
||||
"""
|
||||
@@ -202,12 +202,12 @@ foo = bar
|
||||
msg="sections cascade in the order they appear in the manifest",
|
||||
)
|
||||
|
||||
def test_parse_common_manifests(self):
|
||||
def test_parse_common_manifests(self) -> None:
|
||||
patch_loader(__name__)
|
||||
manifests = load_all_manifests(None)
|
||||
self.assertNotEqual(0, len(manifests), msg="parsed some number of manifests")
|
||||
|
||||
def test_mismatch_name(self):
|
||||
def test_mismatch_name(self) -> None:
|
||||
with self.assertRaisesRegex(
|
||||
Exception,
|
||||
"filename of the manifest 'foo' does not match the manifest name 'bar'",
|
||||
@@ -220,7 +220,7 @@ name = bar
|
||||
""",
|
||||
)
|
||||
|
||||
def test_duplicate_manifest(self):
|
||||
def test_duplicate_manifest(self) -> None:
|
||||
patch_loader(__name__, "fixtures/duplicate")
|
||||
|
||||
with self.assertRaisesRegex(Exception, "found duplicate manifest 'foo'"):
|
||||
|
@@ -10,7 +10,7 @@ from ..platform import HostType
|
||||
|
||||
|
||||
class PlatformTest(unittest.TestCase):
|
||||
def test_create(self):
|
||||
def test_create(self) -> None:
|
||||
p = HostType()
|
||||
self.assertNotEqual(p.ostype, None, msg="probed and returned something")
|
||||
|
||||
@@ -18,11 +18,11 @@ class PlatformTest(unittest.TestCase):
|
||||
round_trip = HostType.from_tuple_string(tuple_string)
|
||||
self.assertEqual(round_trip, p)
|
||||
|
||||
def test_rendering_of_none(self):
|
||||
def test_rendering_of_none(self) -> None:
|
||||
p = HostType(ostype="foo")
|
||||
self.assertEqual(p.as_tuple_string(), "foo-none-none")
|
||||
|
||||
def test_is_methods(self):
|
||||
def test_is_methods(self) -> None:
|
||||
p = HostType(ostype="windows")
|
||||
self.assertTrue(p.is_windows())
|
||||
self.assertFalse(p.is_darwin())
|
||||
|
@@ -10,7 +10,7 @@ from ..buildopts import find_existing_win32_subst_for_path
|
||||
|
||||
|
||||
class Win32SubstTest(unittest.TestCase):
|
||||
def test_no_existing_subst(self):
|
||||
def test_no_existing_subst(self) -> None:
|
||||
self.assertIsNone(
|
||||
find_existing_win32_subst_for_path(
|
||||
r"C:\users\alice\appdata\local\temp\fbcode_builder_getdeps",
|
||||
@@ -24,7 +24,7 @@ class Win32SubstTest(unittest.TestCase):
|
||||
)
|
||||
)
|
||||
|
||||
def test_exact_match_returns_drive_path(self):
|
||||
def test_exact_match_returns_drive_path(self) -> None:
|
||||
self.assertEqual(
|
||||
find_existing_win32_subst_for_path(
|
||||
r"C:\temp\fbcode_builder_getdeps",
|
||||
@@ -40,7 +40,7 @@ class Win32SubstTest(unittest.TestCase):
|
||||
"X:\\",
|
||||
)
|
||||
|
||||
def test_multiple_exact_matches_returns_arbitrary_drive_path(self):
|
||||
def test_multiple_exact_matches_returns_arbitrary_drive_path(self) -> None:
|
||||
self.assertIn(
|
||||
find_existing_win32_subst_for_path(
|
||||
r"C:\temp\fbcode_builder_getdeps",
|
||||
@@ -53,7 +53,7 @@ class Win32SubstTest(unittest.TestCase):
|
||||
("X:\\", "Y:\\", "Z:\\"),
|
||||
)
|
||||
|
||||
def test_drive_letter_is_case_insensitive(self):
|
||||
def test_drive_letter_is_case_insensitive(self) -> None:
|
||||
self.assertEqual(
|
||||
find_existing_win32_subst_for_path(
|
||||
r"C:\temp\fbcode_builder_getdeps",
|
||||
@@ -62,7 +62,7 @@ class Win32SubstTest(unittest.TestCase):
|
||||
"X:\\",
|
||||
)
|
||||
|
||||
def test_path_components_are_case_insensitive(self):
|
||||
def test_path_components_are_case_insensitive(self) -> None:
|
||||
self.assertEqual(
|
||||
find_existing_win32_subst_for_path(
|
||||
r"C:\TEMP\FBCODE_builder_getdeps",
|
||||
|
@@ -43,10 +43,10 @@ class ShellQuoted(namedtuple("ShellQuoted", ("do_not_use_raw_str",))):
|
||||
"or ShellQuoted.format() instead".format(repr(self))
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
def __repr__(self) -> str:
|
||||
return "{0}({1})".format(self.__class__.__name__, repr(self.do_not_use_raw_str))
|
||||
|
||||
def format(self, **kwargs):
|
||||
def format(self, **kwargs) -> "ShellQuoted":
|
||||
"""
|
||||
|
||||
Use instead of str.format() when the arguments are either
|
||||
@@ -65,7 +65,7 @@ class ShellQuoted(namedtuple("ShellQuoted", ("do_not_use_raw_str",))):
|
||||
)
|
||||
|
||||
|
||||
def shell_quote(s):
|
||||
def shell_quote(s) -> ShellQuoted:
|
||||
"Quotes a string if it is not already quoted"
|
||||
return (
|
||||
s
|
||||
@@ -74,19 +74,19 @@ def shell_quote(s):
|
||||
)
|
||||
|
||||
|
||||
def raw_shell(s):
|
||||
def raw_shell(s: ShellQuoted):
|
||||
"Not a member of ShellQuoted so we get a useful error for raw strings"
|
||||
if isinstance(s, ShellQuoted):
|
||||
return s.do_not_use_raw_str
|
||||
raise RuntimeError("{0} should have been ShellQuoted".format(s))
|
||||
|
||||
|
||||
def shell_join(delim, it):
|
||||
def shell_join(delim, it) -> ShellQuoted:
|
||||
"Joins an iterable of ShellQuoted with a delimiter between each two"
|
||||
return ShellQuoted(delim.join(raw_shell(s) for s in it))
|
||||
|
||||
|
||||
def path_join(*args):
|
||||
def path_join(*args) -> ShellQuoted:
|
||||
"Joins ShellQuoted and raw pieces of paths to make a shell-quoted path"
|
||||
return ShellQuoted(os.path.join(*[raw_shell(shell_quote(s)) for s in args]))
|
||||
|
||||
|
Reference in New Issue
Block a user