Browse Source

Show all differences of all heads (folders to overlay into a base as a way of patching).

master
poikilos 10 months ago
parent
commit
5e205c562d
  1. 176
      pyenliven/mtpatches.py

176
pyenliven/mtpatches.py

@ -1,6 +1,7 @@
#!/usr/bin/env python3
import os import os
import platform import platform
# import shlex import shlex
import shutil import shutil
import sys import sys
import subprocess import subprocess
@ -31,7 +32,7 @@ else:
DIFF_CMD_PARTS = ["diff"] DIFF_CMD_PARTS = ["diff"]
def diff_only_head(base, head, rel=None, more_1char_args=None, depth=0): def diff_only_head(base, head, more_1char_args=None, log_level=0):
"""Compare two directories or files. """Compare two directories or files.
Files not in head will not be checked! Files not in head will not be checked!
@ -48,10 +49,8 @@ def diff_only_head(base, head, rel=None, more_1char_args=None, depth=0):
more_1char_args (Union[str,list[str]], optional): args. Defaults more_1char_args (Union[str,list[str]], optional): args. Defaults
to "-wb", or if using Windows, then "/W" if diff is not to "-wb", or if using Windows, then "/W" if diff is not
present in PATH (in that case, fc is used). present in PATH (in that case, fc is used).
rel (str, optional): Leave as None. This will be set log_level (int): How much info to show (-1 to hide output of
automatically for recursion. diff command).
depth (int, optional): Leave as 0. This will be set
automatically for recursion.
Raises: Raises:
FileNotFoundError: If base does not exist (and depth is 0). FileNotFoundError: If base does not exist (and depth is 0).
@ -65,6 +64,28 @@ def diff_only_head(base, head, rel=None, more_1char_args=None, depth=0):
- 'rel': The path relative to head. - 'rel': The path relative to head.
- 'new': True if not in base, otherwise False or not present. - 'new': True if not in base, otherwise False or not present.
- 'code': Return code (1 if file in head&base differ) - 'code': Return code (1 if file in head&base differ)
"""
return _diff_only_head(
base,
head,
more_1char_args=more_1char_args,
log_level=log_level,
)
def _diff_only_head(base, head, rel=None, more_1char_args=None, depth=0,
log_level=0):
"""Compare two directories or files.
For other documentation see diff_only_head.
Args:
rel (str, optional): Leave as None. This will be set
automatically for recursion.
depth (int, optional): Leave as 0. This will be set
automatically for recursion.
""" """
diffs = [] diffs = []
if not DIFF_CMD_PARTS: if not DIFF_CMD_PARTS:
@ -147,12 +168,13 @@ def diff_only_head(base, head, rel=None, more_1char_args=None, depth=0):
# (See docstring). # (See docstring).
for sub in os.listdir(head_path): for sub in os.listdir(head_path):
sub_rel = os.path.join(rel, sub) if rel else sub sub_rel = os.path.join(rel, sub) if rel else sub
diffs += diff_only_head( diffs += _diff_only_head(
base, base,
head, head,
rel=sub_rel, rel=sub_rel,
more_1char_args=more_1char_args, more_1char_args=more_1char_args,
depth=depth+1, depth=depth+1,
log_level=log_level,
) )
else: else:
# echo0('base={}:"{}"'.format(whats[0], paths[0])) # echo0('base={}:"{}"'.format(whats[0], paths[0]))
@ -178,6 +200,8 @@ def diff_only_head(base, head, rel=None, more_1char_args=None, depth=0):
# echo0("\n\n{}".format(shlex.join(cmd_parts))) # echo0("\n\n{}".format(shlex.join(cmd_parts)))
child = subprocess.Popen(cmd_parts, stdout=subprocess.PIPE) child = subprocess.Popen(cmd_parts, stdout=subprocess.PIPE)
streamdata = child.communicate()[0] streamdata = child.communicate()[0]
if log_level >= 0:
# ^ Only -1 should hide diff output itself.
data = streamdata data = streamdata
if sys.version_info.major >= 3: if sys.version_info.major >= 3:
data = streamdata.decode(sys.stdout.encoding) data = streamdata.decode(sys.stdout.encoding)
@ -334,27 +358,61 @@ def find_modpack(parent, name):
def main(): def main():
bases = ( bases = (
"/opt/minebest/assemble/bucket_game", "/opt/minebest/assemble/bucket_game",
"/opt/minebest/mtkit/minetest/src" # "/opt/minebest/mtkit/minetest/src",
) )
heads = ( head_parents = (
os.path.join(REPO_DIR, "Bucket_Game-branches"), os.path.join(REPO_DIR, "Bucket_Game-branches"),
os.path.join(HOME, "metaprojects", "pull-requests", "OldCoder") os.path.join(HOME, "metaprojects", "pull-requests", "OldCoder"),
os.path.join(HOME, "metaprojects", "pull-requests",
"Bucket_Game-branches"),
) )
return check_if_head_files_applied(bases, head_parents)
def check_if_head_files_applied(bases, head_parents):
"""Check if head files are applied.
Args:
bases (list[str]): Directories where heads should have been
applied.
head_parents (list[str]): Folders containing various patches,
where each sub of each parent is in the form of files to
overlay onto base.
Returns:
int: 0 on success.
"""
for base in bases: for base in bases:
if not os.path.isdir(base): if not os.path.isdir(base):
echo0('Warning: There is no base "{}".'.format(base)) echo0('Warning: There is no base "{}".'.format(base))
continue continue
for head in heads: for head in head_parents:
echo0("\n# {}".format(head))
for head_sub in os.listdir(head): for head_sub in os.listdir(head):
# Identify each head folder as an overlay to "patch" a base.
head_sub_path = os.path.join(head, head_sub) head_sub_path = os.path.join(head, head_sub)
# region skip non-patch subs
if os.path.isfile(head_sub_path): if os.path.isfile(head_sub_path):
# echo0('Warning: Only folders, skipped "{}"' # echo0('Warning: Only folders, skipped "{}"'
# ''.format(head_sub)) # ''.format(head_sub))
continue continue
if "original" in head_sub: if "original" in head_sub:
echo0('INFO: skipped original: "{}"' # echo0('INFO: skipped original: "{}"'
''.format(head_sub)) # ''.format(head_sub))
continue
elif "-BASE" in head_sub:
# echo0('INFO: skipped BASE: "{}"'
# ''.format(head_sub))
continue
elif head_sub in ("1.Tasks", "1.old", "1.wontfix",
"1.website"):
# echo0('INFO: skipped Tasks folder: "{}"'
# ''.format(head_sub))
continue continue
# endregion skip non-patch subs
# region identify patch structure
mod_rel = get_shallowest_files_sub( mod_rel = get_shallowest_files_sub(
head_sub_path, head_sub_path,
mask=["init.lua", "mod.conf", "depends.txt", mask=["init.lua", "mod.conf", "depends.txt",
@ -362,24 +420,106 @@ def main():
) )
modpack_rel = get_shallowest_files_sub( modpack_rel = get_shallowest_files_sub(
head_sub_path, head_sub_path,
mask=["modpack.txt"], mask=["modpack.txt", "modpack.conf"],
) )
if mod_rel and not modpack_rel: game_patch_root = None
mod_patch_root = None
modpack_patch_root = None
if head_sub.endswith("_game"):
game_patch_root = head_sub_path
elif os.path.isdir(os.path.join(head_sub_path, "mods")):
game_patch_root = head_sub_path
echo0('game_patch_root="{}"'.format(head_sub))
elif (mod_rel is not None) and (modpack_rel is None):
mod_parent = os.path.dirname(os.path.join(head_sub_path, mod_parent = os.path.dirname(os.path.join(head_sub_path,
mod_rel)) mod_rel))
mod_parent_rel = mod_parent[len(head_sub_path)+1:] mod_parent_rel = mod_parent[len(head_sub_path)+1:]
# ^ +1 no os.path.sep # ^ +1 no os.path.sep
_, mod_parent_name = os.path.split(mod_parent) _, mod_parent_name = os.path.split(mod_parent)
if mod_parent_rel and (mod_parent_name not in ["mods"]): if mod_parent_rel and (mod_parent_name not in ["mods"]):
echo0('Warning: No modpack.txt,' echo0('Warning: No modpack.txt nor modpack.conf,'
' so assuming modpack={} ("{}")' ' so assuming modpack={} ("{}")'
''.format(mod_parent_name, mod_parent)) ''.format(mod_parent_name, mod_parent))
modpack_patch_root = mod_parent
if game_patch_root:
pass # Already set above.
elif modpack_patch_root:
pass # Already set above.
elif mod_rel is not None:
if mod_rel: if mod_rel:
echo0('mod="{}"'.format(mod_rel)) mod_patch_root = os.path.join(head_sub_path, mod_rel)
else:
# Must be "", so don't do join or will add os.path.sep
mod_patch_root = head_sub_path
_, got_mod_name = os.path.split(mod_patch_root)
echo0('mod_patch="{}" root="{}"'
''.format(got_mod_name, mod_patch_root))
else:
pass
# echo0('Warning: mod not identified in "{}"'
# ''.format(head_sub))
# See output in "else" below instead.
# endregion identify patch structure
# region check whether base has it installed
patch_root = None
if game_patch_root is not None:
patch_root = game_patch_root
_, game_name = os.path.split(base)
base_sub_path = base
echo0("* Checking whether {} was applied to {} game"
"".format(head_sub, game_name))
elif modpack_patch_root is not None:
patch_root = modpack_patch_root
_, modpack_name = os.path.split(modpack_patch_root)
modpack_rel = find_modpack(base, modpack_name)
if modpack_rel is None:
echo0("Error: {} was not found in {}"
"".format(modpack_name, base))
continue
if modpack_rel:
base_sub_path = os.path.join(base, modpack_rel)
else:
# Must be "", so avoid join to avoid adding os.path.sep
base_sub_path = base
echo0("* Checking whether {} was applied to"
" {} modpack in {} game"
"".format(head_sub, modpack_name, game_name))
elif mod_patch_root is not None:
patch_root = mod_patch_root
_, mod_name = os.path.split(mod_patch_root)
mod_rel = find_mod(base, mod_name)
if mod_rel is None:
echo0("Error: {} was not found in {}"
"".format(mod_name, base))
continue
if modpack_rel:
base_sub_path = os.path.join(base, modpack_rel)
else:
# Must be "", so avoid join to avoid adding os.path.sep
base_sub_path = base
echo0("* Checking whether {} was applied to"
" {} mod in {} game"
"".format(head_sub, mod_name, game_name))
else: else:
echo0('Warning: mod not identified in "{}"' echo0('Warning: Skipping unknown patch structure: "{}"'
''.format(head_sub)) ''.format(head_sub))
diffs = diff_only_head(base_sub_path, patch_root, log_level=-1)
for diff in diffs:
missing = bool(diff.get("new"))
adjective = "missing" if missing else "differs"
# TODO: echo0(" * {}: {}".format(adjective, diff))
# if not missing:
echo0(" "+shlex.join([
"meld",
os.path.join(base, diff['rel']),
os.path.join(head, diff['rel']),
])+" # base (original) vs head (patch)")
# endregion check whether base has it installed
return 0 return 0

Loading…
Cancel
Save