From d379767a1ea65739229dd75c9f7afd1e4f224561 Mon Sep 17 00:00:00 2001 From: poikilos <7557867+poikilos@users.noreply.github.com> Date: Sun, 25 Feb 2024 14:29:20 -0500 Subject: [PATCH] Fix get_shallowest_files_sub: Return "" (not None) if file found in root. Modify it to replace _find_sub_with_known_files. --- pyenliven/mtpatches.py | 144 +++++++++++++++++++--------------------- tests/test_mtpatches.py | 2 +- 2 files changed, 69 insertions(+), 77 deletions(-) diff --git a/pyenliven/mtpatches.py b/pyenliven/mtpatches.py index f91732e..faa212b 100644 --- a/pyenliven/mtpatches.py +++ b/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) -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). Args: root (str): The folder to check for files recursively. - rel (str, optional): Leave blank (set automatically during - recursion). - depth (int, optional): Leave as 0 (set automatically during - recursion). - filter (Union[str,list[str]], optional): Filename or list of + NOTE: "" or paths ending with "." will be converted to a + real path (following symlinks if any). + log_level (int, optional): 0 for only errors. 1 for info. + mask (Union[str,list[str]], optional): Filename or list of 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: - 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( root, log_level=log_level, - filter=filter, + mask=mask, + name=name, ) def _get_shallowest_files_sub(root, rel=None, depth=0, log_level=0, - filter=None): - if isinstance(filter, str): - if filter == "*": - filter = None - filter = [filter] + mask=None, name=None): + """Get the shallowest folder relative to root that contains file(s). + See get_shallowest_files_sub for other arguments. + + 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: raise ValueError("root is {}".format(root)) 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_name = os.path.split(parent) + # ^ Ok even if rel is used, since split name results in ('', name) 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) 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 # ^ Check *all* subs first, in case dir is listed before file. # 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, depth=depth+1, log_level=log_level, - filter=filter, + mask=mask, + name=name, ) - if found_path: + if found_path is not None: return found_path continue @@ -273,72 +304,33 @@ def _get_shallowest_files_sub(root, rel=None, depth=0, log_level=0, 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, - name, - filter=["init.lua", "mod.conf", "depends.txt", "description.txt"], + mask=mask, + name=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, - name, - filter=["modpack.txt", "modpack.conf"], + mask=mask, + 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(): bases = ( "/opt/minebest/assemble/bucket_game", @@ -365,12 +357,12 @@ def main(): continue mod_rel = get_shallowest_files_sub( head_sub_path, - filter=["init.lua", "mod.conf", "depends.txt", + mask=["init.lua", "mod.conf", "depends.txt", "description.txt"], ) modpack_rel = get_shallowest_files_sub( head_sub_path, - filter=["modpack.txt"], + mask=["modpack.txt"], ) if mod_rel and not modpack_rel: mod_parent = os.path.dirname(os.path.join(head_sub_path, diff --git a/tests/test_mtpatches.py b/tests/test_mtpatches.py index c117de6..06067f6 100644 --- a/tests/test_mtpatches.py +++ b/tests/test_mtpatches.py @@ -31,7 +31,7 @@ class TestMTPatches(unittest.TestCase): os.path.join(TESTS_DATA_DIR, "base", "unused", "sub", "has_file"), log_level=1, ) - self.assertEqual(sub, None) + self.assertEqual(sub, "") # ^ should be "has_file" dir, since that contains # "shallowest_in_base.txt"