Extensions: ensure paths are always included for the "build" command
Scanning the file-system for paths to include didn't detect cases when explicitly included paths (such as wheels) were missing. Change the logic to build a list of paths which is merged with pattern matched paths (de-duplicating), then add all files into the ZIP. Any missing paths will raise an error.
This commit is contained in:
@@ -2717,13 +2717,19 @@ class subcmd_author:
|
||||
message_error(msg_fn, "Error parsing TOML \"{:s}\" {:s}".format(pkg_manifest_filepath, error_msg))
|
||||
return False
|
||||
|
||||
# Always include wheels & manifest.
|
||||
build_paths_extra = (
|
||||
# Inclusion of the manifest is implicit.
|
||||
# No need to require the manifest to include itself.
|
||||
PKG_MANIFEST_FILENAME_TOML,
|
||||
*(manifest.wheels or ()),
|
||||
)
|
||||
|
||||
if (manifest_build_data := manifest_data.get("build")) is not None:
|
||||
manifest_build_test = PkgManifest_Build.from_dict_all_errors(manifest_build_data, extra_paths=[
|
||||
# Inclusion of the manifest is implicit.
|
||||
# No need to require the manifest to include itself.
|
||||
PKG_MANIFEST_FILENAME_TOML,
|
||||
*(manifest.wheels or ()),
|
||||
])
|
||||
manifest_build_test = PkgManifest_Build.from_dict_all_errors(
|
||||
manifest_build_data,
|
||||
extra_paths=build_paths_extra,
|
||||
)
|
||||
if isinstance(manifest_build_test, list):
|
||||
for error_msg in manifest_build_test:
|
||||
message_error(msg_fn, "Error parsing TOML \"{:s}\" {:s}".format(pkg_manifest_filepath, error_msg))
|
||||
@@ -2746,23 +2752,73 @@ class subcmd_author:
|
||||
if manifest_build.paths_exclude_pattern is not None:
|
||||
build_paths_exclude_pattern = PathPatternMatch(manifest_build.paths_exclude_pattern)
|
||||
|
||||
build_paths: Optional[List[str]] = None
|
||||
build_paths: List[Tuple[str, str]] = []
|
||||
|
||||
# Manifest & wheels.
|
||||
if build_paths_extra:
|
||||
build_paths.extend(build_paths_expand_iter(pkg_source_dir, build_paths_extra))
|
||||
|
||||
if manifest_build.paths is not None:
|
||||
build_paths = manifest_build.paths
|
||||
build_paths.extend(build_paths_expand_iter(pkg_source_dir, manifest_build.paths))
|
||||
else:
|
||||
# Mixing literal and pattern matched lists of files is a hassle.
|
||||
# De-duplicate canonical root-relative path names.
|
||||
def filepath_canonical_from_relative(filepath_rel: str):
|
||||
filepath_rel = os.path.normpath(filepath_rel)
|
||||
if os.sep == "\\":
|
||||
filepath_rel = filepath_rel.replace("\\", "/")
|
||||
return filepath_rel
|
||||
|
||||
def scandir_filter_with_paths_exclude_pattern(filepath: str, is_dir: bool) -> bool:
|
||||
assert build_paths_exclude_pattern is not None
|
||||
if os.sep == "\\":
|
||||
filepath = filepath.replace("\\", "/")
|
||||
if is_dir:
|
||||
assert not filepath.endswith("/")
|
||||
filepath = filepath + "/"
|
||||
assert not filepath.startswith(("/", "./", "../"))
|
||||
return not build_paths_exclude_pattern.test_path(filepath)
|
||||
# Use lowercase to prevent duplicates on MS-Windows.
|
||||
build_paths_extra_canonical: Set[int] = set(
|
||||
filepath_canonical_from_relative(f).lower()
|
||||
for f in build_paths_extra
|
||||
)
|
||||
|
||||
def scandir_filter_fallback(filepath: str, is_dir: bool) -> bool:
|
||||
_ = is_dir
|
||||
return not os.path.basename(filepath).startswith(".")
|
||||
# Scanning the file-system may fail, surround by try/except.
|
||||
try:
|
||||
if build_paths_exclude_pattern:
|
||||
def scandir_filter_with_paths_exclude_pattern(filepath: str, is_dir: bool) -> bool:
|
||||
# Returning true includes the file.
|
||||
assert build_paths_exclude_pattern is not None
|
||||
if os.sep == "\\":
|
||||
filepath = filepath.replace("\\", "/")
|
||||
filepath_canonical = filepath
|
||||
if is_dir:
|
||||
assert not filepath.endswith("/")
|
||||
filepath = filepath + "/"
|
||||
assert not filepath.startswith(("/", "./", "../"))
|
||||
result = not build_paths_exclude_pattern.test_path(filepath)
|
||||
if result and (not is_dir):
|
||||
# Finally check the path isn't one of the known paths.
|
||||
if filepath_canonical.lower() in build_paths_extra_canonical:
|
||||
result = False
|
||||
return result
|
||||
|
||||
build_paths.extend(
|
||||
scandir_recursive(
|
||||
pkg_source_dir,
|
||||
filter_fn=scandir_filter_with_paths_exclude_pattern,
|
||||
),
|
||||
)
|
||||
else:
|
||||
# In this case there isn't really a good option, just ignore all dot-files.
|
||||
def scandir_filter_fallback(filepath: str, is_dir: bool) -> bool:
|
||||
# Returning true includes the file.
|
||||
result = not os.path.basename(filepath).startswith(".")
|
||||
if result and (not is_dir):
|
||||
# Finally check the path isn't
|
||||
if filepath_canonical.lower() in build_paths_extra_canonical:
|
||||
result = False
|
||||
return result
|
||||
|
||||
build_paths.extend(scandir_recursive(pkg_source_dir, filter_fn=scandir_filter_fallback))
|
||||
|
||||
del build_paths_extra_canonical
|
||||
|
||||
except Exception as ex:
|
||||
message_status(msg_fn, "Error building path list \"{:s}\"".format(str(ex)))
|
||||
return False
|
||||
|
||||
pkg_filename = manifest.id + PKG_EXT
|
||||
|
||||
@@ -2797,20 +2853,7 @@ class subcmd_author:
|
||||
return False
|
||||
|
||||
with contextlib.closing(zip_fh_context) as zip_fh:
|
||||
|
||||
if build_paths is not None:
|
||||
filepath_iterator = build_paths_expand_iter(pkg_source_dir, build_paths)
|
||||
else:
|
||||
filepath_iterator = scandir_recursive(
|
||||
pkg_source_dir,
|
||||
filter_fn=(
|
||||
scandir_filter_with_paths_exclude_pattern if build_paths_exclude_pattern else
|
||||
# In this case there isn't really a good option, just ignore all dot-files.
|
||||
scandir_filter_fallback
|
||||
),
|
||||
)
|
||||
|
||||
for filepath_abs, filepath_rel in filepath_iterator:
|
||||
for filepath_abs, filepath_rel in build_paths:
|
||||
if filepath_rel in filenames_root_exclude:
|
||||
continue
|
||||
|
||||
|
||||
Reference in New Issue
Block a user