Browse Source

Fix get_shallowest_files_sub: Return "" (not None) if file found in root. Modify it to replace _find_sub_with_known_files.

master
poikilos 7 months ago
parent
commit
d379767a1e
  1. 144
      pyenliven/mtpatches.py
  2. 2
      tests/test_mtpatches.py

144
pyenliven/mtpatches.py

@ -196,35 +196,58 @@ def diff_only_head(base, head, rel=None, more_1char_args=None, depth=0):
return diffs # folder, so return every sub's diff(s) ([] if None) return diffs # folder, so return every sub's diff(s) ([] if None)
def get_shallowest_files_sub(root, log_level=0, filter=None): def get_shallowest_files_sub(root, log_level=0, mask=None, name=None):
"""Get the shallowest folder relative to root that contains file(s). """Get the shallowest folder relative to root that contains file(s).
Args: Args:
root (str): The folder to check for files recursively. root (str): The folder to check for files recursively.
rel (str, optional): Leave blank (set automatically during NOTE: "" or paths ending with "." will be converted to a
recursion). real path (following symlinks if any).
depth (int, optional): Leave as 0 (set automatically during log_level (int, optional): 0 for only errors. 1 for info.
recursion). mask (Union[str,list[str]], optional): Filename or list of
filter (Union[str,list[str]], optional): Filename or list of
filenames to find (None/0/""/False/"*"/[] will match any filenames to find (None/0/""/False/"*"/[] will match any
file). file). If a folder contains the files, the folder path
relative to root will be returned.
name (str, optional): What parent folder name to return, or None
for any with files (see mask). Defaults to None.
Returns: Returns:
Union(str, None): Get the relative dir that contains file(s). str: Get the relative dir that contains file(s) ("" for root,
None if not found).
""" """
if (root == "") or root.endswith("."):
root = os.path.realpath(root)
return _get_shallowest_files_sub( return _get_shallowest_files_sub(
root, root,
log_level=log_level, log_level=log_level,
filter=filter, mask=mask,
name=name,
) )
def _get_shallowest_files_sub(root, rel=None, depth=0, log_level=0, def _get_shallowest_files_sub(root, rel=None, depth=0, log_level=0,
filter=None): mask=None, name=None):
if isinstance(filter, str): """Get the shallowest folder relative to root that contains file(s).
if filter == "*": See get_shallowest_files_sub for other arguments.
filter = None
filter = [filter] Args:
rel (str, optional): Leave blank (set automatically during
recursion).
depth (int, optional): Leave as 0 (set automatically during
recursion).
Raises:
ValueError: root is None
ValueError: _description_
Returns:
str: Get the relative dir that contains file(s) ("" for root,
None if not found).
"""
if isinstance(mask, str):
if mask == "*":
mask = None
mask = [mask]
if root is None: if root is None:
raise ValueError("root is {}".format(root)) raise ValueError("root is {}".format(root))
if rel and rel.startswith(os.path.sep): if rel and rel.startswith(os.path.sep):
@ -235,10 +258,17 @@ def _get_shallowest_files_sub(root, rel=None, depth=0, log_level=0,
) )
parent = os.path.join(root, rel) if rel else root parent = os.path.join(root, rel) if rel else root
_, parent_name = os.path.split(parent)
# ^ Ok even if rel is used, since split name results in ('', name)
for sub in os.listdir(parent): for sub in os.listdir(parent):
if name and (parent_name != name):
# Match against the name if name is set by caller.
continue
sub_path = os.path.join(parent, sub) sub_path = os.path.join(parent, sub)
if os.path.isfile(sub_path): if os.path.isfile(sub_path):
if (not filter) or (sub in filter): if (not mask) or (sub in mask):
if rel is None:
rel = "" # found in root, so rel is ""
return rel return rel
# ^ Check *all* subs first, in case dir is listed before file. # ^ Check *all* subs first, in case dir is listed before file.
# The *parent* has file(s), so return parent # The *parent* has file(s), so return parent
@ -262,10 +292,11 @@ def _get_shallowest_files_sub(root, rel=None, depth=0, log_level=0,
rel=sub_rel, rel=sub_rel,
depth=depth+1, depth=depth+1,
log_level=log_level, log_level=log_level,
filter=filter, mask=mask,
name=name,
) )
if found_path: if found_path is not None:
return found_path return found_path
continue continue
@ -273,72 +304,33 @@ def _get_shallowest_files_sub(root, rel=None, depth=0, log_level=0,
def find_mod(parent, name): def find_mod(parent, name):
return _find_sub_with_known_files( mask = ["init.lua", "mod.conf", "depends.txt", "description.txt"]
# return _find_sub_with_known_files(
# parent,
# name,
# mask=mask,
# )
return get_shallowest_files_sub(
parent, parent,
name, mask=mask,
filter=["init.lua", "mod.conf", "depends.txt", "description.txt"], name=name,
) )
def find_modpack(parent, name): def find_modpack(parent, name):
return _find_sub_with_known_files( mask = ["modpack.txt", "modpack.conf"]
# return _find_sub_with_known_files(
# parent,
# name,
# mask=mask,
# )
return get_shallowest_files_sub(
parent, parent,
name, mask=mask,
filter=["modpack.txt", "modpack.conf"], name=name,
) )
def _find_sub_with_known_files(parent, name, root_slash=None, filter=None):
"""Get relative path to Minetest mod (or "" if parent is it).
Args:
parent (str): Folder to search for Minetest mod files.
name (str): Name of the mod to find. It can still be found if it
is the same name as the parent, so if parent is "mods",
then "3d_armor/3d_armor" would be the result rather than
"3d_armor".
root_slash (str, optional): Leave as None. Recursion sets it
automatically. Defaults to None.
filter (list[str]): Defaults to files found in a mod,
but can be changed to find a modpack or anything else.
Returns:
str: relative path to Minetest mod (or "" if parent is it),
or None if not Found.
"""
if not root_slash:
root_slash = parent + os.path.sep
_, parent_name = os.path.split(parent)
if parent_name == name:
for sub in os.listdir(parent):
sub_path = os.path.join(parent, sub)
if not os.path.isfile(sub_path):
continue
if sub in filter:
# Then parent is the mod. End the search
# and return *relative* path to mod
# (with root_slash removed, so
# "" if parent matches before recursion)
return parent[len(root_slash):]
# ^ must iterate files *before* recursion to avoid deeper false
# positive suchas backup folder inside of a mod that has a
# file in filter.
for sub in os.listdir(parent):
sub_path = os.path.join(parent, sub)
if os.path.isfile(sub_path):
continue
found = _find_sub_with_known_files(
sub_path,
name,
root_slash=root_slash,
filter=filter,
)
if found:
return found
return None
def main(): def main():
bases = ( bases = (
"/opt/minebest/assemble/bucket_game", "/opt/minebest/assemble/bucket_game",
@ -365,12 +357,12 @@ def main():
continue continue
mod_rel = get_shallowest_files_sub( mod_rel = get_shallowest_files_sub(
head_sub_path, head_sub_path,
filter=["init.lua", "mod.conf", "depends.txt", mask=["init.lua", "mod.conf", "depends.txt",
"description.txt"], "description.txt"],
) )
modpack_rel = get_shallowest_files_sub( modpack_rel = get_shallowest_files_sub(
head_sub_path, head_sub_path,
filter=["modpack.txt"], mask=["modpack.txt"],
) )
if mod_rel and not modpack_rel: if mod_rel and not modpack_rel:
mod_parent = os.path.dirname(os.path.join(head_sub_path, mod_parent = os.path.dirname(os.path.join(head_sub_path,

2
tests/test_mtpatches.py

@ -31,7 +31,7 @@ class TestMTPatches(unittest.TestCase):
os.path.join(TESTS_DATA_DIR, "base", "unused", "sub", "has_file"), os.path.join(TESTS_DATA_DIR, "base", "unused", "sub", "has_file"),
log_level=1, log_level=1,
) )
self.assertEqual(sub, None) self.assertEqual(sub, "")
# ^ should be "has_file" dir, since that contains # ^ should be "has_file" dir, since that contains
# "shallowest_in_base.txt" # "shallowest_in_base.txt"

Loading…
Cancel
Save