From e170a2b1236203c7fd88025db2d84c606e96d339 Mon Sep 17 00:00:00 2001 From: poikilos <7557867+poikilos@users.noreply.github.com> Date: Sat, 30 Jul 2022 13:38:49 -0400 Subject: [PATCH] Rename error to echo0 and debug to echo1. Add and use main's return in many cases. Remove lint. Move TRY_SHARE_MT_DIRS from deprecated. --- .gitignore | 1 + Bucket_Game-base/trimpatchstats.py | 52 ++-- Bucket_Game-branches/remove_not_in.py | 27 +- basecompare.py | 32 ++- buildenliven.py | 53 ++-- deploy.py | 257 ++++++++++--------- filever.py | 28 ++- forwardfilesync.py | 22 +- generate-mt5-share-fix.py | 276 ++++++++++---------- headcompare.py | 48 ++-- install-subgametest.py | 349 ++++++++++++++------------ install.py | 31 ++- mtsenliven.py | 200 ++++++++------- notes/continuify.py | 13 +- pyenliven/__init__.py | 103 ++++++++ pyenliven/compatiblizemod.py | 30 ++- pyenliven/deprecated.py | 5 +- setup.py | 77 ++++++ uninstall-minetestserver-git.py | 347 ++++++++++++------------- utilities/compatiblizemod.py | 8 +- utilities/enissue.py | 97 +++---- utilities/enlynx.py | 43 ++-- utilities/extra/uninstall.py | 213 ++++++++-------- utilities/generatemod.py | 311 ++++++++++++----------- utilities/mtcompile-program-local.py | 13 +- utilities/mtoldtonew.py | 10 +- utilities/showmissing.py | 35 +-- 27 files changed, 1522 insertions(+), 1159 deletions(-) mode change 100644 => 100755 mtsenliven.py create mode 100644 pyenliven/__init__.py create mode 100644 setup.py diff --git a/.gitignore b/.gitignore index ede47d3..eedc7f0 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ linux-minetest-kit.zip /docker/lmk-libraries.devuan-chimera/install-minetest-build-deps.sh /docker/libraries-devuan-chimera/install-minetest-build-deps.sh /docker/libraries-devuan-chimaera/install-minetest-build-deps.sh +/debug.txt diff --git a/Bucket_Game-base/trimpatchstats.py b/Bucket_Game-base/trimpatchstats.py index 2ff0e38..c8ffba2 100755 --- a/Bucket_Game-base/trimpatchstats.py +++ b/Bucket_Game-base/trimpatchstats.py @@ -1,13 +1,15 @@ #!/usr/bin/env python3 ''' -Remove the lines from the from the input file in Bucket_Game-base that are not in the matching list file in Bucket_Game-branches. +Remove the lines from the from the input file in Bucket_Game-base that +are not in the matching list file in Bucket_Game-branches. The resulting modified list is written to standard output. -The provided filename must exist in both the Bucket_Game-base directory and the parallel Bucket_Game-branches directory. +The provided filename must exist in both the Bucket_Game-base directory +and the parallel Bucket_Game-branches directory. The file must contain output such as from ls or find executing ls. Examples: - find -type f -name "*.ogg" -exec ls -lh {} \; - find -type f -exec ls -lh {} \; + find -type f -name "*.ogg" -exec ls -lh {} \\; + find -type f -exec ls -lh {} \\; Usage: ./trimpatchstats.py @@ -16,15 +18,16 @@ import sys import os import json -def error(msg): - sys.stderr.write("{}\n".format(msg)) - sys.stderr.flush() + +def echo0(*args, **kwargs): + print(*args, file=sys.stderr, **kwargs) + def usage(): - error("") - error("trimpatchstats.py") - error("-----------------") - error(__doc__) + echo0("") + echo0("trimpatchstats.py") + echo0("-----------------") + echo0(__doc__) def splitFirst(line, delimiter): @@ -196,6 +199,7 @@ class LSFileInfo: def __str__(self): return json.dumps(self.to_dict()) + def getFileNumber(path, num): ''' Get a file from a listfile that contains ls -l or ls -n output. @@ -251,7 +255,7 @@ def printOnlyPatched(baseListPath): if fid is None: print("Error: \"{}\" contained no filenames." "".format(patchedListPath)) - exit(1) + return 1 tryFilePath = os.path.join(targetDirPath, fid['name']) if not os.path.isfile(tryFilePath): print("Error: \"{}\" doesn't exist. Run again from the" @@ -260,9 +264,9 @@ def printOnlyPatched(baseListPath): " directory name in the \"{}\" directory and run in a" " directory parallel to that." "".format(tryFilePath, fid['name'], patchedPath)) - exit(1) + return 2 - error("* analyzing \"{}\"".format(patchedListPath)) + echo0("* analyzing \"{}\"".format(patchedListPath)) patchedFIs = [] rawNames = [] with open(patchedListPath, 'r') as ins: @@ -279,9 +283,9 @@ def printOnlyPatched(baseListPath): fid = parse_ls(line) rawNames.append(fid['name']) # fill_file_dict_path(fid, targetDirPath) - # error(fid) + # echo0(fid) - error("* analyzing \"{}\"".format(baseListPath)) + echo0("* analyzing \"{}\"".format(baseListPath)) allCount = 0 matchCount = 0 with open(baseListPath, 'r') as ins: @@ -300,13 +304,19 @@ def printOnlyPatched(baseListPath): if fid['name'] in rawNames: print(line) matchCount += 1 - error("{} of {} in {} were also in {}" + echo0("{} of {} in {} were also in {}" "".format(matchCount, allCount, baseListPath, patchedListPath)) + return 0 -if __name__ == "__main__": + +def main(): if len(sys.argv) < 2: usage() - error("Error: You are missing the required list filename argument.\n") - exit(1) - printOnlyPatched(sys.argv[1]) + echo0("Error: You are missing the required list filename argument.\n") + return 1 + return printOnlyPatched(sys.argv[1]) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/Bucket_Game-branches/remove_not_in.py b/Bucket_Game-branches/remove_not_in.py index 096987a..62483eb 100755 --- a/Bucket_Game-branches/remove_not_in.py +++ b/Bucket_Game-branches/remove_not_in.py @@ -11,9 +11,8 @@ else: profile = os.environ['HOME'] -def error(msg): - sys.stderr.write("{}\n".format(msg)) - sys.stderr.flush() +def echo0(*args, **kwargs): + print(*args, file=sys.stderr, **kwargs) def showNotInOriginal(patched, original, root=None, ignores=[]): @@ -34,7 +33,8 @@ def showNotInOriginal(patched, original, root=None, ignores=[]): if sub in ignores: continue if os.path.isdir(patchedPath): - showNotInOriginal(patchedPath, originalPath, root=root, ignores=ignores) + showNotInOriginal(patchedPath, originalPath, root=root, + ignores=ignores) continue if not os.path.isfile(originalPath): relPath = patchedPath[len(root):] @@ -47,17 +47,24 @@ def showNotInOriginal(patched, original, root=None, ignores=[]): print("rm {}".format(dotPathShell)) -if __name__ == "__main__": +def main(): original = os.path.join(profile, "minetest", "games", "Bucket_Game") patched = os.path.abspath(".") originalMods = os.path.join(original, "mods") patchedMods = os.path.join(patched, "mods") if not os.path.isdir(originalMods): - error("Error: \"{}\" doesn't seem to be a game since it doesn't have a \"mods\" directory.".format(original)) - exit(1) + echo0("Error: \"{}\" doesn't seem to be a game since it doesn't" + " have a \"mods\" directory.".format(original)) + return 1 if not os.path.isdir(patchedMods): - error("Error: \"{}\" doesn't seem to be a game since it doesn't have a \"mods\" directory.".format(patched)) - exit(1) + echo0("Error: \"{}\" doesn't seem to be a game since it doesn't" + " have a \"mods\" directory.".format(patched)) + return 2 myName = os.path.split(sys.argv[0])[1] - # error("myName:{}".format(myName)) + # echo0("myName:{}".format(myName)) showNotInOriginal(patched, original, None, ignores=[myName]) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/basecompare.py b/basecompare.py index 0617316..9e95548 100755 --- a/basecompare.py +++ b/basecompare.py @@ -3,8 +3,11 @@ from __future__ import print_function import sys import os +from pyenliven import ( + echo0, +) + from headcompare import ( - error, compareBranch, defaultVirtualReposDir, minetestPath, @@ -15,45 +18,48 @@ from headcompare import ( me = os.path.basename(__file__) + def usage(): - error("Usage:") + echo0("Usage:") sys.stderr.write("Specify a branch") parent = "Bucket_Game-base" if os.path.isdir(parent): - error(" from Bucket_Game-base:") + echo0(" from Bucket_Game-base:") for sub in os.listdir(parent): subPath = os.path.join(parent, sub) if sub.startswith("."): continue if os.path.isdir(subPath): - error(subPath) + echo0(subPath) else: - error(" from Bucket_Game-base.") + echo0(" from Bucket_Game-base.") + + echo0("{} []".format(me)) + echo0("") - error("{} []".format(me)) - error("") def main(): global defaultGamePath defaultGamePath = None if len(sys.argv) < 2: usage() - error("Error: You must provide a branch name.\n") - exit(1) + echo0("Error: You must provide a branch name.\n") + return 1 if len(sys.argv) > 3: usage() - error("Error: There are too many arguments: {}.\n" + echo0("Error: There are too many arguments: {}.\n" "".format(sys.argv)) - exit(1) + return 1 if len(sys.argv) > 2: defaultGamePath = sys.argv[2] results = compareBranch(sys.argv[1], gamePath=defaultGamePath, compareOld=True) - error("# ^ Do that to verify: they MUST match, and the first" + echo0("# ^ Do that to verify: they MUST match, and the first" " directory must be unmodified from the original" " release package.") + return 0 if __name__ == "__main__": - main() + sys.exit(main()) diff --git a/buildenliven.py b/buildenliven.py index 0fa3b77..796eb15 100755 --- a/buildenliven.py +++ b/buildenliven.py @@ -9,46 +9,48 @@ import os import configparser from pyenliven import ( - error, + echo0, getSGPath, profile, + MODS_STOPGAP_DIR, ) gamespec = {} gamespec['remove_mods'] = [ "coderblocks", # includes lmb blocks; no recipes - "facade", # no recipes - "placecraft", # interferes with eating - "more_chests", # See https://github.com/poikilos/EnlivenMinetest/issues/446 - "emeralds", # See https://github.com/poikilos/EnlivenMinetest/issues/497 + "facade", # no recipes + "placecraft", # interferes with eating + "more_chests", # See https://github.com/poikilos/EnlivenMinetest/issues/446 + "emeralds", # See https://github.com/poikilos/EnlivenMinetest/issues/497 "give_initial_stuff", # or make it configurable (It only uses a give_initial_stuff boolean, no configurable item list) # TODO: more are at https://github.com/poikilos/EnlivenMinetest/issues/310 ] gamespec['local_mods_paths'] = [] gamespec['local_mods_paths'].append("mods_stopgap") +# ^ See also MODS_STOPGAP_DIR (full path) in pyenliven gamespec['add_mods'] = [ - # {'repo':"https://github.com/poikilos/homedecor_ua"}, + # {'repo': "https://github.com/poikilos/homedecor_ua"}, {'name': "animal_materials_legacy"}, - {'repo':"https://github.com/minetest-mods/ccompass.git"}, - {'repo':"https://github.com/octacian/chat3.git"}, - {'repo':"https://github.com/poikilos/compassgps.git"}, + {'repo': "https://github.com/minetest-mods/ccompass.git"}, + {'repo': "https://github.com/octacian/chat3.git"}, + {'repo': "https://github.com/poikilos/compassgps.git"}, {'name': "elk_legacy"}, - {'repo':"https://github.com/MinetestForFun/fishing.git"}, + {'repo': "https://github.com/MinetestForFun/fishing.git"}, {'name': "glooptest_missing"}, - {'repo':"https://github.com/minetest-mods/item_drop.git"}, - {'repo':"https://github.com/poikilos/metatools.git"}, + {'repo': "https://github.com/minetest-mods/item_drop.git"}, + {'repo': "https://github.com/poikilos/metatools.git"}, {'name': "nftools_legacy"}, {'name': "glooptest_missing"}, - {'repo':"https://github.com/poikilos/slimenodes.git"}, - {'repo':"https://github.com/BenjieFiftysix/sponge.git"}, - {'repo':"https://github.com/poikilos/throwing.git"}, # Can utilize toolranks, toolranks_extras, wielded_light - {'repo':"https://github.com/poikilos/throwing_arrows.git"}, # Can utilize mesecons, mesecons_button - {'repo':"https://github.com/mt-mods/biome_lib.git"}, + {'repo': "https://github.com/poikilos/slimenodes.git"}, + {'repo': "https://github.com/BenjieFiftysix/sponge.git"}, + {'repo': "https://github.com/poikilos/throwing.git"}, # Can utilize toolranks, toolranks_extras, wielded_light + {'repo': "https://github.com/poikilos/throwing_arrows.git"}, # Can utilize mesecons, mesecons_button + {'repo': "https://github.com/mt-mods/biome_lib.git"}, { 'repo': "https://github.com/Poikilos/vines.git", - 'branch': "Bucket_Game", # git clone --branch + 'branch': "Bucket_Game", # git clone --branch }, {"https://github.com/MinetestForFun/unified_inventory"}, ] @@ -164,14 +166,15 @@ WARNINGS: ''' """ warnings = [] -valid_bases = ['Bucket_Game', "bucket_ game"] +valid_bases = ['Bucket_Game', "bucket_game"] + def main(): for warning in warnings: - error(warning) + echo0(warning) tryGameDir = os.getcwd() - error('* examining "{}"'.format(tryGameDir)) + echo0('* examining "{}"'.format(tryGameDir)) gameConfName = "game.conf" gameConfPath = os.path.join(tryGameDir, gameConfName) if not os.path.isfile(gameConfPath): @@ -185,7 +188,7 @@ def main(): config.read_string('[top]\n' + ins.read()) # ^ insert a section since ConfigParser requires sections. gameName = config['top'].get("name") - error(' * detected {} from {}' + echo0(' * detected "{}" from "{}"' ''.format(gameName, gameConfName)) if gameName not in valid_bases: raise ValueError( @@ -200,8 +203,10 @@ def main(): # ^ TODO: Get this from mtanalyze? targetGames = os.path.join(targetMT, "games") target = os.path.join(targetGames, "ENLIVEN") - centerOfTheSunTarget = + centerOfTheSunTarget = None raise NotImplementedError("pyenliven build") + return 0 + if __name__ == "__main__": - main() + sys.exit(main()) diff --git a/deploy.py b/deploy.py index 8e32909..076a658 100644 --- a/deploy.py +++ b/deploy.py @@ -1,117 +1,16 @@ #!/usr/bin/env python import os +import sys import shutil from forwardfilesync import * # import filever -try: - input = raw_input -except NameError: - pass - -warnings = list() - -print("") -print("This script is NOT YET IMPLEMENTED") - - -# TODO: Scrape https://minetest.kitsunemimi.pw/builds/ (NOTE: stable is -# always "https://minetest.kitsunemimi.pw/builds/win64/" -# "minetest-0.4.15-win64.7z") - - -print("This script patches minetest and minetest_game with ENLIVEN\n" + - "(such as launcher and subgame) and creates a Windows installer.") - -script_dir_path = os.path.dirname(os.path.abspath(__file__)) -enliven_project_path = os.path.dirname(script_dir_path) - -profile_path = None -if "HOME" in os.environ: - profile_path = os.environ["HOME"] -elif "USERPROFILE" in os.environ: - profile_path = os.environ["USERPROFILE"] -else: - try_path = "C:\\Users\\jgustafson" - if not os.path.isdir(try_path): - try_path = "C:\\Users\\Owner" - - print("WARNING: no HOME or USERPROFILE found, reverting to '" + - try_path + "'") - profile_path = try_path -# TODO: Make a settings file for values in the next region. -# region user settings -deploy_path = "C:\\Games\\ENLIVEN-deploy" -try_path = "C:\\Games\\Minetest" -if (not os.path.isdir(deploy_path)) and os.path.isdir(try_path): - deploy_path = try_path -installer_deploy_path = path_join_all([profile_path, "ownCloud", "www", - "expertmultimedia", "downloads"]) -installer_name = "install-ENLIVEN.exe" -# endregion user settings - -installer_path = os.path.join(installer_deploy_path, installer_name) - -if not os.path.isdir(installer_deploy_path): - print("#WARNING: does not exist:") -print("installer_deploy_path: " + installer_deploy_path) - -# this is a waste--it just shows 0.0.0.0 though iss file has version -# if os.path.isfile(installer_path): -# numbers=filever.get_version_number(installer_path) -# major,minor,subminor,revision = numbers -# print(".".join([str (i) for i in numbers])) - -if not os.path.isdir(deploy_path): - os.makedirs(deploy_path) -games_path = os.path.join(deploy_path, "games") -minetest_game_path = os.path.join(games_path, "minetest_game") -minetest_game_mods_path = os.path.join(minetest_game_path, "mods") -if not os.path.isdir(minetest_game_path): - print("This deploy script requires an unmodified build of minetest and\n" + - " minetest_game. Please place an unmodified build of minetest in\n" + - " " + deploy_path + " so that minetest_game is at: \n\n" + - " " + minetest_game_path + "\n\n") - exit(1) - -game_path = os.path.join(games_path, "ENLIVEN") - -# NOTE: remove this case, and instead: copy minetest_game, download ENLIVEN -# automatically -if not os.path.isdir(game_path): - print("") - print("ERROR: ENLIVEN must first be installed from web sources" + - " using the provided 'install' script in the etc/change*" + - " folder (run on linux then copy to a Windows machine" + - " in " + game_path) - # exit(2) -else: - print("game_path: " + game_path) -mods_path = os.path.join(game_path, "mods") -if not os.path.isdir(mods_path): - os.makedirs(mods_path) -mtg_list_path = os.path.join(game_path, "minetest_game-mod-list.txt") -mtg_list_out = open(mtg_list_path, 'w') -folder_path = minetest_game_mods_path -if os.path.isdir(folder_path): - for sub_name in os.listdir(folder_path): - sub_path = os.path.join(folder_path, sub_name) - if sub_name[:1] != "." and os.path.isdir(sub_path): - mtg_list_out.write(sub_name + "\n") -mtg_list_out.close() - -# TODO: uncomment this: update_tree(minetest_game_path, game_path) - -server_devel_minetest_conf_path = os.path.join( - game_path, - "minetest.conf.ENLIVEN-server" +from pyenliven import ( + echo0, ) -server_minetest_conf_path = os.path.join(game_path, "minetest.conf") - -if not os.path.isfile(server_devel_minetest_conf_path): - warnings.append(server_devel_minetest_conf_path + " was not found") +if sys.version_info.major >= 3: + pass else: - shutil.copyfile(server_devel_minetest_conf_path, - server_minetest_conf_path) + input = raw_input def rm_sub(bad_sub): @@ -120,22 +19,132 @@ def rm_sub(bad_sub): os.remove(bad_path) -rm_sub(["CC-BY-SA 3.0 Unported (fallback license for ENLIVEN assets)" - ".txt"]) -rm_sub(["MIT LICENSE (fallback license for ENLIVEN code).txt"]) +def main(): + warnings = list() -# NOTE: At this point, the following LICENSE and README files are -# minetest_game's and the following are intentionally looking in -# C:\games\ENLIVEN\games\ENLIVEN: -# rm_sub(["games", "ENLIVEN", "LICENSE.txt"]) -# rm_sub(["games", "ENLIVEN", "README.txt"]) + echo0("") + echo0("This script is NOT YET IMPLEMENTED") -print("") -if len(warnings) > 0: - print(str(len(warnings)) + " warning(s):") - for warning in warnings: - print(warning) -else: - print("0 warnings.") -print("\n") -input("press enter to exit...") + + # TODO: Scrape https://minetest.kitsunemimi.pw/builds/ (NOTE: stable is + # always "https://minetest.kitsunemimi.pw/builds/win64/" + # "minetest-0.4.15-win64.7z") + + + echo0("This script patches minetest and minetest_game with ENLIVEN\n" + + "(such as launcher and subgame) and creates a Windows installer.") + + script_dir_path = os.path.dirname(os.path.abspath(__file__)) + enliven_project_path = os.path.dirname(script_dir_path) + + profile_path = None + if "HOME" in os.environ: + profile_path = os.environ["HOME"] + elif "USERPROFILE" in os.environ: + profile_path = os.environ["USERPROFILE"] + else: + try_path = "C:\\Users\\jgustafson" + if not os.path.isdir(try_path): + try_path = "C:\\Users\\Owner" + + echo0("WARNING: no HOME or USERPROFILE found, reverting to '" + + try_path + "'") + profile_path = try_path + # TODO: Make a settings file for values in the next region. + # region user settings + deploy_path = "C:\\Games\\ENLIVEN-deploy" + try_path = "C:\\Games\\Minetest" + if (not os.path.isdir(deploy_path)) and os.path.isdir(try_path): + deploy_path = try_path + installer_deploy_path = path_join_all([profile_path, "ownCloud", "www", + "expertmultimedia", "downloads"]) + installer_name = "install-ENLIVEN.exe" + # endregion user settings + + installer_path = os.path.join(installer_deploy_path, installer_name) + + if not os.path.isdir(installer_deploy_path): + echo0("#WARNING: does not exist:") + print("installer_deploy_path: " + installer_deploy_path) + + # this is a waste--it just shows 0.0.0.0 though iss file has version + # if os.path.isfile(installer_path): + # numbers=filever.get_version_number(installer_path) + # major,minor,subminor,revision = numbers + # print(".".join([str (i) for i in numbers])) + + if not os.path.isdir(deploy_path): + os.makedirs(deploy_path) + games_path = os.path.join(deploy_path, "games") + minetest_game_path = os.path.join(games_path, "minetest_game") + minetest_game_mods_path = os.path.join(minetest_game_path, "mods") + if not os.path.isdir(minetest_game_path): + echo0("This deploy script requires an unmodified build of minetest and\n" + + " minetest_game. Please place an unmodified build of minetest in\n" + + " " + deploy_path + " so that minetest_game is at: \n\n" + + " " + minetest_game_path + "\n\n") + return 1 + + game_path = os.path.join(games_path, "ENLIVEN") + + # NOTE: remove this case, and instead: copy minetest_game, download ENLIVEN + # automatically + if not os.path.isdir(game_path): + echo0("") + echo0("ERROR: ENLIVEN must first be installed from web sources" + + " using the provided 'install' script in the etc/change*" + + " folder (run on linux then copy to a Windows machine" + + " in " + game_path) + # return 2 + else: + print("game_path: " + game_path) + mods_path = os.path.join(game_path, "mods") + if not os.path.isdir(mods_path): + os.makedirs(mods_path) + mtg_list_path = os.path.join(game_path, "minetest_game-mod-list.txt") + mtg_list_out = open(mtg_list_path, 'w') + folder_path = minetest_game_mods_path + if os.path.isdir(folder_path): + for sub_name in os.listdir(folder_path): + sub_path = os.path.join(folder_path, sub_name) + if sub_name[:1] != "." and os.path.isdir(sub_path): + mtg_list_out.write(sub_name + "\n") + mtg_list_out.close() + + # TODO: uncomment this: update_tree(minetest_game_path, game_path) + + server_devel_minetest_conf_path = os.path.join( + game_path, + "minetest.conf.ENLIVEN-server" + ) + server_minetest_conf_path = os.path.join(game_path, "minetest.conf") + + if not os.path.isfile(server_devel_minetest_conf_path): + warnings.append(server_devel_minetest_conf_path + " was not found") + else: + shutil.copyfile(server_devel_minetest_conf_path, + server_minetest_conf_path) + + rm_sub(["CC-BY-SA 3.0 Unported (fallback license for ENLIVEN assets)" + ".txt"]) + rm_sub(["MIT LICENSE (fallback license for ENLIVEN code).txt"]) + + # NOTE: At this point, the following LICENSE and README files are + # minetest_game's and the following are intentionally looking in + # C:\games\ENLIVEN\games\ENLIVEN: + # rm_sub(["games", "ENLIVEN", "LICENSE.txt"]) + # rm_sub(["games", "ENLIVEN", "README.txt"]) + + echo0("") + if len(warnings) > 0: + echo0(str(len(warnings)) + " warning(s):") + for warning in warnings: + echo0(warning) + else: + echo0("0 warnings.") + echo0() + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/filever.py b/filever.py index d710a8c..a1e8aa6 100644 --- a/filever.py +++ b/filever.py @@ -1,5 +1,7 @@ #!/usr/bin/env python -# by Jamie at try: from win32api import GetFileVersionInfo, LOWORD, HIWORD @@ -7,7 +9,7 @@ except ImportError: print("you need to install win32api such as with the command:") print("sudo python2 -m pip install --upgrade pip") print("sudo python -m pip install pypiwin32") - exit(1) + sys.exit(1) from win32api import GetFileVersionInfo, LOWORD, HIWORD @@ -23,15 +25,25 @@ def get_version_number(filename): return 0, 0, 0, 0 -if __name__ == '__main__': +API_USAGE = ''' +# API Usage: +import filever +parts = filever.get_version_number(filename) +major,minor,subminor,revision = parts +print(".".join([str (i) for i in parts])) +''' + + +def main(): import os if "COMSPEC" in os.environ: filename = os.environ["COMSPEC"] this_delimiter = "." print(str(filename) + " version:") print(".".join([str(i) for i in get_version_number(filename)])) - print("Running filever directly doesn't do much.\n\n#Usage:\n" + - "import filever\n" + - "parts = filever.get_version_number(filename)\n" + - "major,minor,subminor,revision = parts\n" + - "print(\".\".join([str (i) for i in parts]))\n\n") + print("Running filever directly doesn't do much\n\n"+API_USAGE) + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/forwardfilesync.py b/forwardfilesync.py index dfd06d1..db656ff 100644 --- a/forwardfilesync.py +++ b/forwardfilesync.py @@ -24,6 +24,7 @@ if platform.system() == "Windows": CMD_CP = "COPY" CMD_MKDIR = "MD" + def path_join_all(names): result = names[0] for i in range(1, len(names)): @@ -35,7 +36,7 @@ def trim_branch(src, dst, dot_hidden=True, verbose=True): ''' Explore dst non-recursively and delete files and subdirectories recursively that are not present on src. - + Keyword arguments: dot_hidden -- Operate on files and directories even if they are hidden by starting with '.'. @@ -60,7 +61,7 @@ def update_tree(src, dst, level=0, do_trim=False, dot_hidden=False, ''' Creates dst if not present, then copies everything from src to dst recursively. - + Keyword arguments: do_trim -- Delete files and directories from dst that are not on src. @@ -122,6 +123,7 @@ def update_tree(src, dst, level=0, do_trim=False, dot_hidden=False, "".format(CMD_CP, sub_path, dst_sub_path)) pass + USAGE = ''' Syntax: forwardfilesync.py [options] @@ -131,18 +133,20 @@ forwardfilesync.py [options] ''' + def usage(): print(USAGE) + def main(): flags = {} flags["hidden"] = False flags["delete"] = False - + if len(sys.argv) < 3: usage() print("Error: You must provide at least a source and destination.") - exit(1) + return 1 src = sys.argv[1] dst = sys.argv[2] @@ -155,17 +159,17 @@ def main(): " since it doesn't start with \"--\". If it is part" " of a path with spaces, put the path in quotes." "".format(sys.argv[argI])) - exit(1) + return 1 name = arg[2:] if name not in flags: usage() print("Error: There is no option \"{}\". If it is part of a" " path with spaces, put the path in quotes." "".format(sys.argv[argI])) - exit(1) + return 1 flags[name] = True print(CMD_COMMENT + "Using options:") - for k,v in flags.items(): + for k, v in flags.items(): print(CMD_COMMENT + "{}: {}".format(k, v)) update_tree( @@ -175,8 +179,8 @@ def main(): dot_hidden=flags["hidden"] is True, ) print(CMD_COMMENT + "Done.") - + return 0 if __name__ == "__main__": - main() + sys.exit(main()) diff --git a/generate-mt5-share-fix.py b/generate-mt5-share-fix.py index 636e0af..2f4d108 100755 --- a/generate-mt5-share-fix.py +++ b/generate-mt5-share-fix.py @@ -1,144 +1,154 @@ #!/usr/bin/env python3 import os import shutil +import sys actions = {"-- Up-to-date: ": "move", "-- Installing: ": "move"} changes = { "/usr/local/./": "/usr/local/share/minetest/" } -count = 0 -command_count = 0 -in_path = "bad_mt5_make_install_output.txt" -outs_path = os.path.dirname(os.path.realpath(__file__)) -out_path = os.path.join(outs_path, "install-fix-minetest5-share.sh") -file_commands = [] -rmd_cmds = [] -mkdir_commands = [] -made_dirs = [] -mtg_mod_dirs = ["games//minetest_game/mods", "games/minetest_game/mods"] -with open(in_path) as ins: - with open(out_path, 'w') as outs: - outs.write("#!/bin/sh\n") - count += 1 - for line_orig in ins: - line = line_orig.strip() - action = None - old_path = None - for k, try_action in actions.items(): - if line.startswith(k): - action = try_action - old_path = line[len(k):].strip() - break - if action == "move": - found = None - for old, new in changes.items(): - if old_path.startswith(old): - found = old - new_path = new + old_path[len(old):] - if not os.path.exists(old_path): - if not os.path.exists(new_path): - # raise ValueError( - # "The program is not installed" - # " (missing '{}')".format(old_path) - # ) - outs.write( - '# WARNING: expected "{}" (there is' - ' no destination "{}" either)' - ''.format(old_path, new_path) - ) - else: - outs.write( - '# Already moved (no source "{}"' - ' for destination "{}")' - ''.format(old_path, new_path) - ) - else: - if os.path.isfile(old_path): - parent = os.path.split(new_path)[0] - if parent not in made_dirs: - made_dirs.append(parent) - cmd = 'mkdir -p "{}"'.format( - parent.replace("//", "/") - ) - mkdir_commands.append(cmd) - # AFTER all directories BEFORE all files - options = "" - if os.path.isfile(new_path): - options = "-f" - if len(options) > 0: - options = " " + options.strip() - cmd = ( - 'mv' + options - + ' "{}" "{}"'.format( - old_path.replace("//", "/"), - new_path.replace("//", "/") - ) - ) - # outs.write(cmd + "\n") - # AFTER all directories - file_commands.append(cmd) - else: - # old_path == old_path.replace("//","/") - # Manually fix: - # rmdir: failed to remove '/usr/local/ - # ./games//minetest_game/mods': - # Directory not empty - # rmdir: failed to remove '/usr/local/ - # ./games//minetest_game': - # Directory not empty - - # due to /usr/local/./games// - # minetest_game/mods/game_commands: - orphan_mods = ["game_commands"] - removed_orphan_mods = [] - - for mod_rel in orphan_mods: - for mtg_rel in mtg_mod_dirs: - f_rel = found + mtg_rel - # such as ("/usr/local/./" - # + "games//minetest_game/mods") - if old_path.startswith(f_rel): - # if mod_rel not in - # removed_orphan_mods: - try_path = (found + mtg_rel - + "/" + mod_rel) - if os.path.isdir(try_path): - cmd = ( - 'rmdir "{}"'.format( - try_path - ) - ) - # queue for last stage: - if cmd not in rmd_cmds: - rmd_cmds.append(cmd) - # removed_orphan_mods. - # append(mod_rel) - break - - cmd = 'rmdir "{}"'.format(old_path) - rmd_cmds.append(cmd) # AFTER everything +def main(): + count = 0 + command_count = 0 + in_path = "bad_mt5_make_install_output.txt" + outs_path = os.path.dirname(os.path.realpath(__file__)) + out_path = os.path.join(outs_path, "install-fix-minetest5-share.sh") + file_commands = [] + rmd_cmds = [] + mkdir_commands = [] + made_dirs = [] + mtg_mod_dirs = ["games//minetest_game/mods", "games/minetest_game/mods"] + with open(in_path) as ins: + with open(out_path, 'w') as outs: + outs.write("#!/bin/sh\n") + count += 1 + for line_orig in ins: + line = line_orig.strip() + action = None + old_path = None + for k, try_action in actions.items(): + if line.startswith(k): + action = try_action + old_path = line[len(k):].strip() break - if found is None: - outs.write("# WARNING: The destination path is" - " unknown: ") - outs.write('# mv "{}" "{}"'.format(old_path, - old_path)) - else: - outs.write("# " + line + "\n") - count += 1 - for cmd in sorted(mkdir_commands, key=len): - outs.write(cmd + "\n") - count += 1 - command_count += 1 - for cmd in file_commands: - outs.write(cmd + "\n") - count += 1 - command_count += 1 - for cmd in sorted(rmd_cmds, key=len, reverse=True): - outs.write(cmd + "\n") - count += 1 - command_count += 1 + if action == "move": + found = None + for old, new in changes.items(): + if old_path.startswith(old): + found = old + new_path = new + old_path[len(old):] + if not os.path.exists(old_path): + if not os.path.exists(new_path): + # raise ValueError( + # "The program is not installed" + # " (missing '{}')".format(old_path) + # ) + outs.write( + '# WARNING: expected "{}" (there is' + ' no destination "{}" either)' + ''.format(old_path, new_path) + ) + else: + outs.write( + '# Already moved (no source "{}"' + ' for destination "{}")' + ''.format(old_path, new_path) + ) + else: + if os.path.isfile(old_path): + parent = os.path.split(new_path)[0] + if parent not in made_dirs: + made_dirs.append(parent) + cmd = 'mkdir -p "{}"'.format( + parent.replace("//", "/") + ) + mkdir_commands.append(cmd) + # AFTER all directories BEFORE all files + options = "" + if os.path.isfile(new_path): + options = "-f" + if len(options) > 0: + options = " " + options.strip() + cmd = ( + 'mv' + options + + ' "{}" "{}"'.format( + old_path.replace("//", "/"), + new_path.replace("//", "/") + ) + ) + # outs.write(cmd + "\n") + # AFTER all directories + file_commands.append(cmd) + else: + # old_path == old_path.replace("//","/") + # Manually fix: -print('Added {} line(s) to "{}" (including {} command(s))' - ''.format(count, out_path, command_count)) + # rmdir: failed to remove '/usr/local/ + # ./games//minetest_game/mods': + # Directory not empty + + # rmdir: failed to remove '/usr/local/ + # ./games//minetest_game': + # Directory not empty + + # due to /usr/local/./games// + # minetest_game/mods/game_commands: + orphan_mods = ["game_commands"] + removed_orphan_mods = [] + + for mod_rel in orphan_mods: + for mtg_rel in mtg_mod_dirs: + f_rel = found + mtg_rel + # such as ("/usr/local/./" + # + "games//minetest_game/mods") + if old_path.startswith(f_rel): + # if mod_rel not in + # removed_orphan_mods: + try_path = (found + mtg_rel + + "/" + mod_rel) + if os.path.isdir(try_path): + cmd = ( + 'rmdir "{}"'.format( + try_path + ) + ) + # queue for last stage: + if cmd not in rmd_cmds: + rmd_cmds.append(cmd) + # removed_orphan_mods. + # append(mod_rel) + break + + cmd = 'rmdir "{}"'.format(old_path) + rmd_cmds.append(cmd) # AFTER everything + break + if found is None: + outs.write("# WARNING: The destination path is" + " unknown: ") + outs.write('# mv "{}" "{}"'.format(old_path, + old_path)) + else: + outs.write("# " + line + "\n") + count += 1 + for cmd in sorted(mkdir_commands, key=len): + outs.write(cmd + "\n") + count += 1 + command_count += 1 + for cmd in file_commands: + outs.write(cmd + "\n") + count += 1 + command_count += 1 + for cmd in sorted(rmd_cmds, key=len, reverse=True): + outs.write(cmd + "\n") + count += 1 + command_count += 1 + + print('Added {} line(s) to "{}" (including {} command(s))' + ''.format(count, out_path, command_count)) + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/headcompare.py b/headcompare.py index e0be74e..664c9fe 100755 --- a/headcompare.py +++ b/headcompare.py @@ -4,45 +4,46 @@ import sys import os import platform +from pyenliven import ( + echo0, +) + + me = os.path.basename(__file__) myDir = os.path.dirname(os.path.abspath(__file__)) defaultVirtualReposDir = myDir -def error(msg): - sys.stderr.write("{}\n".format(msg)) - sys.stderr.flush() - def usage(): - error("Usage:") + echo0("Usage:") sys.stderr.write("Specify a branch") parent = "Bucket_Game-branches" if os.path.isdir(parent): - error(" from Bucket_Game-branches:") + echo0(" from Bucket_Game-branches:") for sub in os.listdir(parent): subPath = os.path.join(parent, sub) if sub.startswith("."): continue if os.path.isdir(subPath): - error(subPath) + echo0(subPath) else: - error(" from Bucket_Game-branches.") + echo0(" from Bucket_Game-branches.") - error("{} []".format(me)) - error("") + echo0("{} []".format(me)) + echo0("") profile = None if platform.system() == "Windows": profile = os.environ.get('USERPROFILE') if profile is None: - error("Error: USERPROFILE is not set.") - exit(1) + echo0("Error: USERPROFILE is not set.") + sys.exit(1) else: profile = os.environ.get('HOME') if profile is None: - error("Error: HOME is not set.") - exit(1) + echo0("Error: HOME is not set.") + sys.exit(1) minetestPath = os.path.join(profile, "minetest") gamesPath = os.path.join(minetestPath, "games") @@ -153,7 +154,6 @@ def compareBranch(branchName, gamePath=None, bgVersion=None, if branchPathRel.startswith(myDirSlash): branchPathRel = branchPathRel[len(myDirSlash):] - print("meld \"{}\" \"{}\"".format(gamePath, branchPath)) patchFilePath = branchPath+".patch" print("diff -ru \"{}\" \"{}\" > \"{}\"" @@ -166,26 +166,28 @@ def compareBranch(branchName, gamePath=None, bgVersion=None, } return results + def main(): global defaultGamePath defaultGamePath = None if len(sys.argv) < 2: usage() - error("Error: You must provide a branch name.\n") - exit(1) + echo0("Error: You must provide a branch name.\n") + return 1 if len(sys.argv) > 3: usage() - error("Error: There are too many arguments: {}.\n" + echo0("Error: There are too many arguments: {}.\n" "".format(sys.argv)) - exit(1) + return 1 if len(sys.argv) > 2: defaultGamePath = sys.argv[2] results = compareBranch(sys.argv[1], gamePath=defaultGamePath) - error("# ^ Do that to see the difference or generate a patch," - " but the first directory must be unmodified from the" - " original release package.") + echo0("# ^ Do that to see the difference or generate a patch," + " but the first directory must be unmodified from the" + " original release package.") + return 0 if __name__ == "__main__": - main() + sys.exit(main()) diff --git a/install-subgametest.py b/install-subgametest.py index beebe41..4943574 100755 --- a/install-subgametest.py +++ b/install-subgametest.py @@ -9,10 +9,12 @@ from forwardfilesync import * force_update_mtg_enable = False # first delete subgametest then remake # endregion options -try: - input = raw_input -except NameError: +''' +if sys.version_info.major >= 3: pass +else: + input = raw_input +''' gitpython_msg = """ You do not have gitpython installed. @@ -42,181 +44,200 @@ try: except ImportError: print(gitpython_msg) print("") - input("press enter to close...") - exit(1) + sys.exit(1) + +from pyenliven import ( + echo0, +) +from mtanalyze import( + TRY_SHARE_MT_DIRS, + get_var_and_check, +) + profile_path = None -if 'HOME' in os.environ: # if os.name=="windows": +if 'HOME' in os.environ: profile_path = os.environ['HOME'] -else: +else: # if platform.system() == "Windows" profile_path = os.environ['USERPROFILE'] -if not os.path.isdir(profile_path): - print("") - print("Failed to get existing home path--tried HOME & USERPROFILE") - print("") - input("press enter to close") - exit(2) +def main(): + if not os.path.isdir(profile_path): + echo0("") + echo0("Failed to get existing home path--tried HOME & USERPROFILE") + echo0("") + return 2 -configs_path = os.path.join(profile_path, ".config") -if os.name == "windows": - base_path = os.path.join(profile_path, "AppData") - configs_path = os.path.join(base_path, "Local") + configs_path = os.path.join(profile_path, ".config") + if os.name == "windows": + base_path = os.path.join(profile_path, "AppData") + configs_path = os.path.join(base_path, "Local") -CONFIG_PATH = os.path.join(configs_path, "EnlivenMinetest") -if not os.path.isdir(CONFIG_PATH): - os.makedirs(CONFIG_PATH) + CONFIG_PATH = os.path.join(configs_path, "EnlivenMinetest") + if not os.path.isdir(CONFIG_PATH): + os.makedirs(CONFIG_PATH) -# NOTE: not using /var/cache -caches_path = os.path.join(CONFIG_PATH, "cache") -RELEASES_PATH = os.path.join(caches_path, "releases") -GIT_REPOS_PATH = os.path.join(caches_path, "git") -GIT_BRANCHES_PATH = os.path.join(caches_path, "git-branches") + # NOTE: not using /var/cache + caches_path = os.path.join(CONFIG_PATH, "cache") + RELEASES_PATH = os.path.join(caches_path, "releases") + GIT_REPOS_PATH = os.path.join(caches_path, "git") + GIT_BRANCHES_PATH = os.path.join(caches_path, "git-branches") -if not os.path.isdir(RELEASES_PATH): - os.makedirs(RELEASES_PATH) + if not os.path.isdir(RELEASES_PATH): + os.makedirs(RELEASES_PATH) -if not os.path.isdir(GIT_REPOS_PATH): - os.makedirs(GIT_REPOS_PATH) + if not os.path.isdir(GIT_REPOS_PATH): + os.makedirs(GIT_REPOS_PATH) -if not os.path.isdir(GIT_BRANCHES_PATH): - os.makedirs(GIT_BRANCHES_PATH) + if not os.path.isdir(GIT_BRANCHES_PATH): + os.makedirs(GIT_BRANCHES_PATH) -USR_SHARE_MINETEST = "/usr/share/games/minetest" -if not os.path.isdir(USR_SHARE_MINETEST): - if os.path.isdir("/usr/local/share/minetest"): - # IF git version is installed: - USR_SHARE_MINETEST = "/usr/local/share/minetest" - if os.path.isdir("/usr/share/minetest"): - USR_SHARE_MINETEST = "/usr/share/minetest" - - if not os.path.isdir(USR_SHARE_MINETEST): - print("Minetest could not be found in any known location." + ''' + USR_SHARE_MINETEST = None + for try_share_mt in TRY_SHARE_MT_DIRS: + if os.path.isdir(try_share_mt): + USR_SHARE_MINETEST = try_share_mt + break + if USR_SHARE_MINETEST is None: + echo0("Minetest could not be found in any known location ({})." " Try installing minetest or compiling from source or" " editing value of USR_SHARE_MINETEST in this script." - " The script ended early.") - input("press enter to close...") - exit(3) + " The script ended early.".format(TRY_SHARE_MT_DIRS)) + return 3 + ''' + USR_SHARE_MINETEST, code = get_var_and_check('shared_minetest_path', 3) + if code != 0: + return code + + MT_GAMES_DIR = os.path.join(USR_SHARE_MINETEST, "games") + MT_MYGAME_NAME = "subgametest" + MT_MYGAME_DIR = os.path.join(MT_GAMES_DIR, MT_MYGAME_NAME) + + MTG_PATH = None + mtg_game_name = None + base_game_path = None + base_games = ["amhi_game", "minetest_game"] + for try_game_name in base_games: + MTG_PATH = os.path.join(MT_GAMES_DIR, try_game_name) + base_game_path = MTG_PATH + if os.path.isdir(base_game_path): + mtg_game_name = try_game_name + + if mtg_game_name is None: + echo0("Could not find \"" + base_game_path + "\". Script ended early.") + echo0("Set shared_minetest_path to the path containing a") + echo0(" games folder with one of the following: {}".format(base_games)) + return 4 + + MTG_MODS_PATH = os.path.join(MTG_PATH, "mods") + + if force_update_mtg_enable: + shutil.rmtree(MT_MYGAME_DIR) + + # yes | cp -rf $MT_GAMES_DIR/minetest_game/* MT_MYGAME_DIR" + # sudo rsync -a $MT_GAMES_DIR/minetest_game/* MT_MYGAME_DIR" + + try: + # DOES update minetest_game, but does NOT delete extra mods: + update_tree(base_game_path, MT_MYGAME_DIR) + echo0("Updated \"" + MT_MYGAME_DIR + "\"...") + except PermissionError: + echo0(str(sys.exc_info())) + echo0("") + echo0("You must run " + __file__ + " as a user that can write to " + "\"" + MT_MYGAME_DIR + "\"") + echo0("") + return 5 + + try: + # cd $HOME + # tmp_game_conf_path = os.path.join(profile_path, "game.conf") + outs = open(os.path.join(MT_MYGAME_DIR, "game.conf"), 'w') + outs.write("name = subgametest") + outs.close() + except PermissionError: + echo0(str(sys.exc_info())) + echo0("") + echo0("You must run " + __file__ + " as a user that can write to " + "\"" + MT_MYGAME_DIR + "\"") + echo0("") + return 6 + # cmd_string = "sudo mv -f game.conf \MT_MYGAME_DIR\"" + # shutil.move(tmp_game_conf_path, os.path.join(MT_MYGAME_DIR, "game.conf")) + + good_dir = os.path.join(MT_MYGAME_DIR, "mods") + if os.path.isdir(good_dir): + echo0("Copied subgame to " + MT_MYGAME_DIR) + else: + echo0('FAILED to copy subgame to "{}" ("{}" is missing)' + ''.format(MT_MYGAME_DIR, good_dir)) + return 7 + + MT_MYGAME_MODS_PATH = os.path.join(MT_MYGAME_DIR, "mods") + MTMOD_DEST_NAME = "minigamer" + MTMOD_DEST_PATH = os.path.join(MT_MYGAME_MODS_PATH, MTMOD_DEST_NAME) + + # if force_update_mtg_mods_enable: + # for sub_name in os.listdir(base_game_path): + # sub_path = os.path.join(base_game_path, sub_name) + # dst_path = os.path.join(MT_MYGAME_DIR, sub_name) + # if sub_name[:1]!="." and os.path.isdir(sub_path): + # if os.path.isdir(dst_path): + # shutil.rmtree(dst_path) + + if not os.path.isdir(GIT_REPOS_PATH): + echo0("Cannot create " + GIT_REPOS_PATH + " so cannot continue.") + return 8 + + # TODO: actually install something (from spreadsheet maybe) + + mtg_mods_list = list() + src_mods_path = MTG_MODS_PATH + if os.path.isdir(src_mods_path): + for sub_name in os.listdir(src_mods_path): + sub_path = os.path.join(src_mods_path, sub_name) + if sub_name[:1] != "." and os.path.isdir(sub_path): + mtg_mods_list.append(sub_name) + + mods_installed_list = list() + mods_added_list = list() + + dst_mods_path = MT_MYGAME_MODS_PATH + if os.path.isdir(dst_mods_path): + for sub_name in os.listdir(dst_mods_path): + sub_path = os.path.join(dst_mods_path, sub_name) + if sub_name[:1] != "." and os.path.isdir(sub_path): + mods_installed_list.append(sub_name) + if sub_name not in mtg_mods_list: + mods_added_list.append(sub_name) + else: + echo0("Missing '" + dst_mods_path + "'") + + echo0("") + echo0("") + echo0("Installed " + str(len(mods_installed_list)) + " mod(s)" + + " (" + str(len(mtg_mods_list)) + " from " + mtg_game_name + ").") + if len(mods_added_list) > 0: + print("Added:") + for mod_name in mods_added_list: + print(" - " + mod_name) + echo0("") + # cd $TMP_DIR + # git clone https://github.com/tenplus1/mobs_redo.git + # git clone https://github.com/tenplus1/mobs_animal.git + # git clone https://github.com/tenplus1/mobs_monster.git + # git clone https://github.com/tenplus1/mobs_npc.git + # but not: + # git clone https://github.com/poikilos/minetest-minigamer.git + # git clone https://github.com/poikilos/birthstones.git + + # Repo.clone_from(git_url, repo_dir) + return 0 -MT_GAMES_DIR = os.path.join(USR_SHARE_MINETEST, "games") -MT_MYGAME_NAME = "subgametest" -MT_MYGAME_DIR = os.path.join(MT_GAMES_DIR, MT_MYGAME_NAME) - -mtg_game_name = "minetest_game" -MTG_PATH = os.path.join(MT_GAMES_DIR, mtg_game_name) -folder_path = MTG_PATH -MTG_MODS_PATH = os.path.join(MTG_PATH, "mods") - -if not os.path.isdir(folder_path): - print("Could not find \"" + folder_path + "\". Script ended early.") - input("press enter to close...") - exit(4) - -if force_update_mtg_enable: - shutil.rmtree(MT_MYGAME_DIR) - -# yes | cp -rf $MT_GAMES_DIR/minetest_game/* MT_MYGAME_DIR" -# sudo rsync -a $MT_GAMES_DIR/minetest_game/* MT_MYGAME_DIR" - -try: - # DOES update minetest_game, but does NOT delete extra mods: - update_tree(folder_path, MT_MYGAME_DIR) - print("Updated \"" + MT_MYGAME_DIR + "\"...") -except PermissionError: - print(str(sys.exc_info())) - print("") - print("You must run " + __file__ + " as a user that can write to " - "\"" + MT_MYGAME_DIR + "\"") - print("") - input("press enter to close...") - exit(5) - -try: - # cd $HOME - # tmp_game_conf_path = os.path.join(profile_path, "game.conf") - outs = open(os.path.join(MT_MYGAME_DIR, "game.conf"), 'w') - outs.write("name = subgametest") - outs.close() -except PermissionError: - print(str(sys.exc_info())) - print("") - print("You must run " + __file__ + " as a user that can write to " - "\"" + MT_MYGAME_DIR + "\"") - print("") - input("press enter to close...") - exit(6) -# cmd_string = "sudo mv -f game.conf \MT_MYGAME_DIR\"" -# shutil.move(tmp_game_conf_path, os.path.join(MT_MYGAME_DIR, "game.conf")) - -if os.path.isdir(os.path.join(MT_MYGAME_DIR, "mods")): - print("Copied subgame to " + MT_MYGAME_DIR) -else: - print("FAILED to copy subgame to " + MT_MYGAME_DIR) - input("press enter to close...") - exit(7) - - -MT_MYGAME_MODS_PATH = os.path.join(MT_MYGAME_DIR, "mods") -MTMOD_DEST_NAME = "minigamer" -MTMOD_DEST_PATH = os.path.join(MT_MYGAME_MODS_PATH, MTMOD_DEST_NAME) - -# if force_update_mtg_mods_enable: -# for sub_name in os.listdir(folder_path): -# sub_path = os.path.join(folder_path, sub_name) -# dst_path = os.path.join(MT_MYGAME_DIR, sub_name) -# if sub_name[:1]!="." and os.path.isdir(sub_path): -# if os.path.isdir(dst_path): -# shutil.rmtree(dst_path) - - -if not os.path.isdir(GIT_REPOS_PATH): - print("Cannot create " + GIT_REPOS_PATH + " so cannot continue.") - input("press enter to close...") - exit(8) - -# TODO: actually install something (from spreadsheet maybe) - -mtg_mods_list = list() -folder_path = MTG_MODS_PATH -if os.path.isdir(folder_path): - for sub_name in os.listdir(folder_path): - sub_path = os.path.join(folder_path, sub_name) - if sub_name[:1] != "." and os.path.isdir(sub_path): - mtg_mods_list.append(sub_name) - -mods_installed_list = list() -mods_added_list = list() - -folder_path = MT_MYGAME_MODS_PATH -if os.path.isdir(folder_path): - for sub_name in os.listdir(folder_path): - sub_path = os.path.join(folder_path, sub_name) - if sub_name[:1] != "." and os.path.isdir(sub_path): - mods_installed_list.append(sub_name) - if sub_name not in mtg_mods_list: - mods_added_list.append(sub_name) -else: - print("Missing '" + folder_path + "'") - -print("") -print("") -print("Installed " + str(len(mods_installed_list)) + " mod(s)" + - " (" + str(len(mtg_mods_list)) + " from " + mtg_game_name + ").") -if len(mods_added_list) > 0: - print("Added:") - for mod_name in mods_added_list: - print(" - " + mod_name) -print("") -input("press enter to close...") -# cd $TMP_DIR -# git clone https://github.com/tenplus1/mobs_redo.git -# git clone https://github.com/tenplus1/mobs_animal.git -# git clone https://github.com/tenplus1/mobs_monster.git -# git clone https://github.com/tenplus1/mobs_npc.git -# but not: -# git clone https://github.com/poikilos/minetest-minigamer.git -# git clone https://github.com/poikilos/birthstones.git - -# Repo.clone_from(git_url, repo_dir) +if __name__ == "__main__": + code = main() + # if code != 0: + # input("press enter to close...") + sys.exit(code) diff --git a/install.py b/install.py index 40bc36f..3ab2d04 100644 --- a/install.py +++ b/install.py @@ -11,9 +11,10 @@ if platform.system() == "Windows": else: profile = os.environ.get('HOME') -def error(msg): - sys.stderr.write("{}\n".format(msg)) - sys.stderr.flush() + +def echo0(*args, **kwargs): + print(*args, file=sys.stderr, **kwargs) + try: import mtanalyze @@ -23,12 +24,20 @@ except ModuleNotFoundError as ex: sys.path.append(tryMTA) import mtanalyze else: - error("") - error("You must install mtanalyze in the directory alongside") - error("EnlivenMinetest or as ~/git/mtanalize") - error("such as via:") - error("git clone https://github.com/poikilos/mtanalyze ~/git/mtanalize") - error("") + echo0("") + echo0("You must install mtanalyze in the directory alongside") + echo0("EnlivenMinetest or as ~/git/mtanalize") + echo0("such as via:") + echo0("git clone https://github.com/poikilos/mtanalyze ~/git/mtanalize") + echo0("") # raise tryMTA - exit(1) -print("This doesn't work (not yet implemented). See build.py.") + sys.exit(1) + + +def main(): + echo0("This doesn't work (not yet implemented). See build.py.") + return 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/mtsenliven.py b/mtsenliven.py old mode 100644 new mode 100755 index 830fc58..02ff62b --- a/mtsenliven.py +++ b/mtsenliven.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 from __future__ import print_function # runs minetestserver using the paths defined by minetestinfo @@ -7,7 +7,7 @@ from __future__ import print_function # dr4Ke on # https://forum.minetest.net/viewtopic.php?f=11&t=13138&start=50 import os -from mtanalyze.minetestinfo import * +import sys import subprocess import signal try: @@ -20,55 +20,26 @@ try: except ImportError: from queue import Queue # Python 3 -key_exit_msg = "SIGINT should shut down server safely...\n" -game_id = "ENLIVEN" -# screen -S MinetestServer $mts --gameid ENLIVEN --worldname ... -print() -print() -print() +REPO_PATH = os.path.dirname(os.path.realpath(__file__)) +# ^ realpath follows symlinks +REPOS_PATH = os.path.dirname(REPO_PATH) +TRY_REPO_PATH = os.path.join(REPOS_PATH, "mtanalyze") +if os.path.isfile(os.path.join(TRY_REPO_PATH, "mtanalyze", "__init__.py")): + # ^ Yes, it is 2 mtanalyze deep, + # such as "$HOME/git/mtanalyze/mtanalyze/__init__.py" + sys.path.insert(0, TRY_REPO_PATH) -if not minetestinfo.contains("minetestserver_path"): - print("[ mtsenliven.py ] ERROR: minetestserver_path" - " was not found in your version of minetestinfo.py") - exit(1) +from pyenliven import ( + echo0, + echo1, +) -mts = minetestinfo.get_var("minetestserver_path") -if not minetestinfo.contains("primary_world_path"): - print("[ mtsenliven.py ] ERROR: primary_world_path" - "was selected by minetestinfo.py") - exit(2) -wp = minetestinfo.get_var("primary_world_path") -wn = os.path.basename(wp) -print("Using minetestserver: " + mts) -print("Using primary_world_path: " + wp) -print("Using world_name: " + wn) -print() -process = None -try: - # get both stdout and stderr (see - # https://www.saltycrane.com/blog/2008/09/how-get-stdout-and- - # stderr-using-python-subprocess-module/) - process = subprocess.Popen( - [mts, '--gameid', game_id, '--worldname', wn], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - bufsize=1 - ) - # bufsize=1 as per jfs on -except Exception as e: - print(mts + " could not be executed. Try installing the " - " minetest-server package or compiling from git instructions" - " on minetest.net") - print(e) - exit(1) -msgprefix_flags = ["WARNING[Server]: ", "ACTION[Server]: "] -msgprefix_lists = {} # where flag is key -for flag in msgprefix_flags: - msgprefix_lists[flag] = [] -# see https://www.endpoint.com/blog/2015/01/28/getting-realtime-output- -# using-python + +# from mtanalyze.minetestinfo import * +from mtanalyze import ( + mti, + get_var_and_check, +) non_unique_wraps = [] non_unique_wraps.append( @@ -83,6 +54,11 @@ unique_flags = [ "joins game" ] +msgprefix_flags = ["WARNING[Server]: ", "ACTION[Server]: "] +msgprefix_lists = {} # where flag is key +for flag in msgprefix_flags: + msgprefix_lists[flag] = [] + def print_unique_only(output, err_flag=False): output_strip = output.strip() @@ -124,7 +100,7 @@ def print_unique_only(output, err_flag=False): if show_enable: print(output_strip) if found_flag is not None: - print(" [ mtsenliven.py ] " + msg_msg + echo0(" [ mtsenliven.py ] " + msg_msg + " will be suppressed") @@ -158,7 +134,7 @@ def reader(pipe, q): finally: q.put(None) except KeyboardInterrupt: - print("[ mtsenliven.py ] " + key_exit_msg) + echo0("[ mtsenliven.py ] " + key_exit_msg) pass @@ -167,44 +143,100 @@ def decode_safe(b): s = b.decode() except UnicodeDecodeError: s = b.decode('utf-8') + ''' + except AttributeError as ex: + if "'str' object has no attribute" in str(ex): + return b + raise ex + ''' return s -q = Queue() -Thread(target=reader, args=[process.stdout, q]).start() -Thread(target=reader, args=[process.stderr, q]).start() -try: - for _ in range(2): - for source, line in iter(q.get, None): - # print "%s: %s" % (source, line), - s = source - l_s = line - # NOTE: source is a string such as - # "<_io.BufferedReader name=5>" - l_s = decode_safe("utf-8") - process_msg("%s: %s" % (s, l_s)) -except KeyboardInterrupt: - print("[ mtsenliven.py ] " + key_exit_msg) - pass +def main(): + key_exit_msg = "SIGINT should shut down server safely...\n" + game_id = "ENLIVEN" + # screen -S MinetestServer $mts --gameid ENLIVEN --worldname ... + echo0() + echo0() + echo0() -exit(0) + mts, code = get_var_and_check("minetestserver_path", code=1) + if code != 0: + return code -while True: + wp, code = get_var_and_check("primary_world_path", code=1) + if code != 0: + return code + + wn = os.path.basename(wp) + echo0("Using minetestserver: " + mts) + echo0("Using primary_world_path: " + wp) + echo0("Using world_name: " + wn) + echo0() + process = None try: - # can deadlock on high volume--use communicate instead - # as per https://docs.python.org/2/library/subprocess.html - out_bytes = process.stdout.readline() - # err_bytes = process.stderr.readline() - # (err_bytes == '') and \ - if (out_bytes == '') and \ - (process.poll() is not None): - break - if out_bytes: - process_msg(out_bytes) - # if err_bytes: - # process_msg(err_bytes) - rc = process.poll() + # get both stdout and stderr (see + # https://www.saltycrane.com/blog/2008/09/how-get-stdout-and- + # stderr-using-python-subprocess-module/) + process = subprocess.Popen( + [mts, '--gameid', game_id, '--worldname', wn], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + bufsize=1 + ) + # bufsize=1 as per jfs on + except Exception as e: + echo0(mts + " could not be executed. Try installing the " + " minetest-server package or compiling from git instructions" + " on minetest.net") + echo0(e) + return 2 + # see https://www.endpoint.com/blog/2015/01/28/getting-realtime-output- + # using-python + + q = Queue() + Thread(target=reader, args=[process.stdout, q]).start() + Thread(target=reader, args=[process.stderr, q]).start() + try: + for _ in range(2): + for source, line in iter(q.get, None): + # print "%s: %s" % (source, line), + s = source + l_s = line + # NOTE: source is a string such as + # "<_io.BufferedReader name=5>" + l_s = decode_safe(line) # line.decode("utf-8") + process_msg("%s: %s" % (s, l_s)) except KeyboardInterrupt: print("[ mtsenliven.py ] " + key_exit_msg) - break -# process.kill() + pass + + return 0 + ''' + while True: + try: + # can deadlock on high volume--use communicate instead + # as per https://docs.python.org/2/library/subprocess.html + out_bytes = process.stdout.readline() + # err_bytes = process.stderr.readline() + # (err_bytes == '') and \ + if (out_bytes == '') and \ + (process.poll() is not None): + break + if out_bytes: + process_msg(out_bytes) + # if err_bytes: + # process_msg(err_bytes) + rc = process.poll() + except KeyboardInterrupt: + echo0("[ mtsenliven.py ] " + key_exit_msg) + break + # process.kill() + return 0 + ''' + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/notes/continuify.py b/notes/continuify.py index 6046f55..c380a37 100755 --- a/notes/continuify.py +++ b/notes/continuify.py @@ -9,8 +9,9 @@ comparison purposes and link.txt files). import sys import os + def continuify(inPath, outPath, continueStr=" \\", indent=" ", - sep=" "): + sep=" "): with open(outPath, 'w') as outs: with open(inPath) as ins: rawLine = True @@ -28,21 +29,23 @@ def continuify(inPath, outPath, continueStr=" \\", indent=" ", if i >= 0: starter = indent + def main(): if len(sys.argv) < 2: print("You must specify file(s).") - exit(1) + return 1 for i in range(1, len(sys.argv)): arg = sys.argv[i] if not os.path.isfile(arg): print("ERROR: {} is not a file.".format(arg)) - exit(1) + return 2 # parts = os.path.splitext(arg) # outPath = parts[0] + ".tmp" + parts[1] outPath = arg + ".continuified.tmp" continuify(arg, outPath) print("* wrote \"{}\"".format(outPath)) - pass + return 0 + if __name__ == "__main__": - main() + sys.exit(main()) diff --git a/pyenliven/__init__.py b/pyenliven/__init__.py new file mode 100644 index 0000000..7bdf9aa --- /dev/null +++ b/pyenliven/__init__.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python +''' +This module assists with building games from other games, mods, and +patches. +''' +from __future__ import print_function + +import sys +import platform +import os + +profile = None +if platform.system() == "Windows": + profile = os.environ.get('USERPROFILE') +else: + profile = os.environ.get('HOME') + +verbosity = 0 +max_verbosity = 2 + + +def echo0(*args, **kwargs): + print(*args, file=sys.stderr, **kwargs) + + +def echo1(*args, **kwargs): + if verbosity < 1: + return False + print(*args, file=sys.stderr, **kwargs) + return True + + +def echo2(*args, **kwargs): + if verbosity < 2: + return False + print(*args, file=sys.stderr, **kwargs) + return True + + +def get_verbosity(): + return verbosity + + +def set_verbosity(level): + if level is True: + verbosity = 1 + elif level is False: + verbosity = 0 + elif level in range(max_verbosity+1): + verbosity = level + raise ValueError( + "verbosity must be {} at maximum.".format(max_verbosity) + ) + + +try: + import mtanalyze +except ModuleNotFoundError as ex: + # tryMTA = os.path.join(profile, "git", "mtanalyze") + moduleDir = os.path.dirname(os.path.realpath(__file__)) + REPO_DIR = os.path.dirname(moduleDir) + modulesDir = os.path.dirname(REPO_DIR) + echo0("* looking for mtanalyze in modulesDir \"{}\"" + "".format(modulesDir)) + tryMTA = os.path.abspath(os.path.join(modulesDir, "mtanalyze")) + if os.path.isdir(tryMTA): + sys.path.append(tryMTA) + import mtanalyze + # ^ import mtanalyze/mtanalyze purposely since the main + # mtanalyze/ directory is a setuptools package not a module. + else: + echo0("") + echo0("You must install mtanalyze alongside") + echo0("EnlivenMinetest such that ../mtanalize/mtanalize exists") + echo0("such as via:") + echo0(" git clone https://github.com/poikilos/mtanalyze {}" + "".format(tryMTA)) + echo0("") + # raise tryMTA + exit(1) + +# from mtanalyze import profile_path +MY_MODULE_DIR = os.path.dirname(os.path.realpath(__file__)) +# ^ realpath follows symlinks +REPO_DIR = os.path.dirname(MY_MODULE_DIR) +MODS_STOPGAP_DIR = os.path.join(REPO_DIR, "patches", "mods-stopgap") +if not os.path.isdir(MODS_STOPGAP_DIR): + echo0("Error: \"{}\" is missing.".format(MODS_STOPGAP_DIR)) + exit(1) +BASE_DIR = os.path.join(REPO_DIR, "Bucket_Game-base") +if not os.path.isdir(BASE_DIR): + echo0("Error: \"{}\" is missing.".format(BASE_DIR)) + exit(1) +BRANCHES_DIR = os.path.join(REPO_DIR, "Bucket_Game-branches") +if not os.path.isdir(BRANCHES_DIR): + echo0("Error: \"{}\" is missing.".format(BRANCHES_DIR)) + exit(1) + +# NOTE: get a git repo's origin via: git remote show origin + + +def getSGPath(stopgap_mod_name): + return os.path.join(MODS_STOPGAP_DIR, stopgap_mod_name) diff --git a/pyenliven/compatiblizemod.py b/pyenliven/compatiblizemod.py index cbc5102..37d4eff 100755 --- a/pyenliven/compatiblizemod.py +++ b/pyenliven/compatiblizemod.py @@ -4,9 +4,10 @@ import sys import os import shutil -def error(msg): - sys.stderr.write("{}\n".format(msg)) - sys.stderr.flush() + +def echo0(*args, **kwargs): + print(*args, file=sys.stderr, **kwargs) + def add_depends(mod_path): mod_dir_name = os.path.basename(mod_path) @@ -41,10 +42,10 @@ def add_depends(mod_path): print("* created {}/modpack.txt" "".format(mod_dir_name)) else: - error("{}/modpack.txt already exists for compatibility." + echo0("{}/modpack.txt already exists for compatibility." "".format(mod_dir_name)) if os.path.isfile(modpack_txt): - error("{}/{} indicates it is a modpack." + echo0("{}/{} indicates it is a modpack." "".format(mod_dir_name, found_modpack_file)) for sub in os.listdir(mod_path): if sub.startswith('.'): @@ -52,19 +53,19 @@ def add_depends(mod_path): subPath = os.path.join(mod_path, sub) add_depends(subPath) # It must be a modpack, so return after doing subdirectories. - return + return 1 depends_path = os.path.join(mod_path, "depends.txt") description_path = os.path.join(mod_path, "description.txt") if os.path.isfile(depends_path): - error("WARNING: Writing {} will be skipped since it exists." + echo0("WARNING: Writing {} will be skipped since it exists." "".format(depends_path)) - return + return 0 mod_conf = os.path.join(mod_path, "mod.conf") if not os.path.isfile(mod_conf): - error("WARNING: Writing {} will be skipped since {} does" + echo0("WARNING: Writing {} will be skipped since {} does" " not exist." "".format(depends_path, mod_conf)) - return + return 1 optional_depends = None depends = None description = None @@ -117,14 +118,17 @@ def add_depends(mod_path): if os.path.isfile(description_path): print("* INFO: There is already a description.txt so it" " will be left intact.") - return + return 0 with open(description_path, 'w') as outs: outs.write("{}\n".format(description)) print("* wrote {}/description.txt".format(mod_dir_name)) + return 0 + def main(): parent = os.path.realpath(".") - add_depends(parent) + return add_depends(parent) + if __name__ == "__main__": - main() + sys.exit(main()) diff --git a/pyenliven/deprecated.py b/pyenliven/deprecated.py index 51911d7..7ea3ac4 100644 --- a/pyenliven/deprecated.py +++ b/pyenliven/deprecated.py @@ -1,4 +1,4 @@ -#!/usr/bin/env +#!/usr/bin/env python3 class Repo: ''' WARNING: The real Repo class is in enliven.py @@ -6,6 +6,7 @@ class Repo: print(__doc__) pass + class GiteaRepo(Repo): ''' This class is deprecated since the "options" sequential argument @@ -28,7 +29,7 @@ class GiteaRepo(Repo): # hide_events=['renamed', 'assigned'], caches_path=None, # api_comments_url_fmt="{instance_url}/repos/{ru}/{rn}/issues/comments", - ): + ): print(GiteaRepo.__doc__) if repo_url.endswith(".git"): repo_url = repo_url[:-4] diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..2f991b2 --- /dev/null +++ b/setup.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python +import setuptools +import sys +import os +# - For the example on which this was based, see +# https://github.com/poikilos/linux-preinstall/blob/main/setup.py +# which is based on +# https://github.com/poikilos/world_clock/blob/main/setup.py +# which is based on +# https://github.com/poikilos/nopackage/blob/main/setup.py +# which is based on +# https://github.com/poikilos/pypicolcd/blob/master/setup.py +# - For nose, see https://github.com/poikilos/mgep/blob/master/setup.py + +# python_mr = sys.version_info.major +# versionedModule = {} +# versionedModule['urllib'] = 'urllib' +# if python_mr == 2: +# versionedModule['urllib'] = 'urllib2' + +install_requires = [] + +if os.path.isfile("requirements.txt"): + with open("requirements.txt", "r") as ins: + for rawL in ins: + line = rawL.strip() + if len(line) < 1: + continue + install_requires.append(line) + +description = '''Manage Minetest using Python.''' +long_description = description +if os.path.isfile("readme.md"): + with open("readme.md", "r") as fh: + long_description = fh.read() + +setuptools.setup( + name='pyenliven', + version='0.3.0', + description=description, + long_description=long_description, + long_description_content_type="text/markdown", + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Programming Language :: Python :: 3', + ('License :: OSI Approved ::' + ' GNU General Public License v2 or later (GPLv2+)'), + 'Operating System :: POSIX :: Linux', + 'Topic :: Software Development :: Version Control', + ], + keywords=('minetest repo management commit data analyzer' + ' meld merge compare files diff'), + url="https://github.com/poikilos/EnlivenMinetest", + author="Jake Gustafson", + author_email='7557867+poikilos@users.noreply.github.com', + license='GPLv2.1', + # packages=setuptools.find_packages(), + packages=['pyenliven'], + # include_package_data=True, # look for MANIFEST.in + # scripts=['example'] , + # See + entry_points={ + 'console_scripts': [ + 'compatiblizemod=pyenliven.compatiblizemod:main', + ], + }, + install_requires=install_requires, + # versionedModule['urllib'], + # ^ "ERROR: Could not find a version that satisfies the requirement + # urllib (from nopackage) (from versions: none) + # ERROR: No matching distribution found for urllib" + test_suite='nose.collector', + tests_require=['nose', 'nose-cover3'], + zip_safe=False, # It can't run zipped due to needing data files. + ) diff --git a/uninstall-minetestserver-git.py b/uninstall-minetestserver-git.py index 4197b6f..bb98fdc 100755 --- a/uninstall-minetestserver-git.py +++ b/uninstall-minetestserver-git.py @@ -1,183 +1,194 @@ #!/usr/bin/env python3 import os +import sys import platform -CMD_REM = "#" -CMD_RM = "rm " -CMD_RMDIR = "rmdir " -if platform.system() == "Windows": - CMD_REM = "REM " - CMD_RM = "del " - CMD_RMDIR = "rd " -# profile_path = None -# if 'HOME' in os.environ: -# profile_path = os.environ['HOME'] -# elif 'USERPROFILE' in os.environ: -# profile_path = os.environ['USERPROFILE'] -# downloads_path = os.path.join(profile_path, "Downloads") -# repo_path = os.path.join(downloads_path, "minetest") -# if not os.path.isdir(repo_path): -# repo_path = os.path.join(profile_path, "minetest") -# if not os.path.isdir(repo_path): -# print("ERROR: Nothing done since there is no minetest sourcecode" -# " folder in " + downloads_path -# + " (nor " + profile_path + ")") -# exit(1) -install_manifest_name = "install_manifest.txt" -# install_manifest_path = os.path.join(repo_path, install_manifest_name) -# if not os.path.isfile(install_manifest_path): -# print("ERROR: nothing done since there is no " + -# install_manifest_name + " in '" + repo_path + -# "'. The file would only be present if you " + -# "installed minetest from sourcecode" + -# "(otherwise this uninstaller is not for you).") -# exit(2) -if not os.path.isfile(install_manifest_name): - print("ERROR: nothing done since there is no " + - install_manifest_name + " in the current " + - "directory. You must run: ") - print(" sudo python3 "+os.path.abspath(__file__)) - print("from the minetest sourcecode (repo) directory.") - exit(2) -directories = [] -print("Removing files...") -f_removed_count = 0 -f_skipped_count = 0 -f_failed_count = 0 -retry_lines = [] -with open(install_manifest_name, 'r') as ins: - original_line = True - while original_line: - original_line = ins.readline() - if original_line: - line = original_line.rstrip() # remove trailing newline - if len(line) > 0: - d_path = os.path.dirname(line) - if d_path not in directories: - if "minetest" in d_path: - directories.append(d_path) - # else must be a system directory like - # /usr/local/share/applications - if os.path.isfile(line): - os.remove(line) +def main(): + CMD_REM = "#" + CMD_RM = "rm " + CMD_RMDIR = "rmdir " + if platform.system() == "Windows": + CMD_REM = "REM " + CMD_RM = "del " + CMD_RMDIR = "rd " + + # profile_path = None + # if 'HOME' in os.environ: + # profile_path = os.environ['HOME'] + # elif 'USERPROFILE' in os.environ: + # profile_path = os.environ['USERPROFILE'] + # downloads_path = os.path.join(profile_path, "Downloads") + # repo_path = os.path.join(downloads_path, "minetest") + # if not os.path.isdir(repo_path): + # repo_path = os.path.join(profile_path, "minetest") + # if not os.path.isdir(repo_path): + # print("ERROR: Nothing done since there is no minetest sourcecode" + # " folder in " + downloads_path + # + " (nor " + profile_path + ")") + # return 1 + install_manifest_name = "install_manifest.txt" + # install_manifest_path = os.path.join(repo_path, install_manifest_name) + # if not os.path.isfile(install_manifest_path): + # print("ERROR: nothing done since there is no " + + # install_manifest_name + " in '" + repo_path + + # "'. The file would only be present if you " + + # "installed minetest from sourcecode" + + # "(otherwise this uninstaller is not for you).") + # return 2 + if not os.path.isfile(install_manifest_name): + print("ERROR: nothing done since there is no " + + install_manifest_name + " in the current " + + "directory. You must run: ") + print(" sudo python3 "+os.path.abspath(__file__)) + print("from the minetest sourcecode (repo) directory.") + return 2 + directories = [] + print("Removing files...") + f_removed_count = 0 + f_skipped_count = 0 + f_failed_count = 0 + retry_lines = [] + with open(install_manifest_name, 'r') as ins: + original_line = True + while original_line: + original_line = ins.readline() + if original_line: + line = original_line.rstrip() # remove trailing newline + if len(line) > 0: + d_path = os.path.dirname(line) + if d_path not in directories: + if "minetest" in d_path: + directories.append(d_path) + # else must be a system directory like + # /usr/local/share/applications if os.path.isfile(line): - f_failed_count += 1 - retry_lines.append(CMD_RM+'"'+line+'"') + os.remove(line) + if os.path.isfile(line): + f_failed_count += 1 + retry_lines.append(CMD_RM+'"'+line+'"') + else: + f_removed_count += 1 else: - f_removed_count += 1 - else: - f_skipped_count += 1 + f_skipped_count += 1 -print("Removed " + str(f_removed_count) + " file(s) (skipped not" - " present:" + str(f_skipped_count) + "; failed:" - + str(f_failed_count) + ")") + print("Removed " + str(f_removed_count) + " file(s) (skipped not" + " present:" + str(f_skipped_count) + "; failed:" + + str(f_failed_count) + ")") -# NOTE: the next line makes ASCENDING (by len) list of TUPLES (name,len) -sorted_directories = [ - (x, len(x)) for x in sorted(directories, key=len) -] + # NOTE: the next line makes ASCENDING (by len) list of TUPLES (name,len) + sorted_directories = [ + (x, len(x)) for x in sorted(directories, key=len) + ] -print("Removing folders...") -# NOTE: they are sorted ASCENDING so start at end: -d_removed_count = 0 -d_skipped_count = 0 -d_failed_count = 0 + print("Removing folders...") + # NOTE: they are sorted ASCENDING so start at end: + d_removed_count = 0 + d_skipped_count = 0 + d_failed_count = 0 -# still leaves: -# /usr/local/share/minetest/games/minetest_game/mods -# /usr/local/share/minetest/textures/base/pack/: -# down_arrow.png left_arrow.png right_arrow.png up_arrow.png -# /usr/local/share/minetest/games/minimal/mods -# so: -try_files = ["depends.txt", "down_arrow.png", "left_arrow.png", - "right_arrow.png", "up_arrow.png"] -try_dirs = ["mods"] + # still leaves: + # /usr/local/share/minetest/games/minetest_game/mods + # /usr/local/share/minetest/textures/base/pack/: + # down_arrow.png left_arrow.png right_arrow.png up_arrow.png + # /usr/local/share/minetest/games/minimal/mods + # so: + try_files = ["depends.txt", "down_arrow.png", "left_arrow.png", + "right_arrow.png", "up_arrow.png"] + try_dirs = ["mods"] -extra_dirs = [] -ed_failed_count = 0 -ed_removed_count = 0 -extra_files = [] -e_failed_count = 0 -e_removed_count = 0 -for i in reversed(range(len(sorted_directories))): - d_path = sorted_directories[i][0] -# for d in reversed(sorted_directories): -# d_path = d[0] -# print("checking "+str(d_path)) - if os.path.isdir(d_path): - try: - for try_name in try_files: - try_path = os.path.join(d_path, try_name) - if os.path.isfile(try_path): - extra_files.append(try_path) - print('Removing known extra file: "' + try_path - + '"') - try: - os.remove(try_path) - e_removed_count += 1 - except Exception as e: - e_failed_count += 1 - retry_lines.append(CMD_RM + '"' + try_path - + '"') - print(str(e)) - for try_name in try_dirs: - try_path = os.path.join(d_path, try_name) - if os.path.isdir(try_path): - extra_dirs.append(try_path) - print('Removing known extra folder: "' + try_path - + '"') - try: - os.rmdir(try_path) - ed_removed_count += 1 - except Exception as e: - ed_failed_count += 1 - retry_lines.append(CMD_RMDIR+'"'+try_path+'"') - print(str(e)) - os.rmdir(d_path) - except Exception as e: - print(str(e)) + extra_dirs = [] + ed_failed_count = 0 + ed_removed_count = 0 + extra_files = [] + e_failed_count = 0 + e_removed_count = 0 + for i in reversed(range(len(sorted_directories))): + d_path = sorted_directories[i][0] + # for d in reversed(sorted_directories): + # d_path = d[0] + # print("checking "+str(d_path)) if os.path.isdir(d_path): - d_failed_count += 1 - retry_lines.append(CMD_RMDIR+'"'+d_path+'"') + try: + for try_name in try_files: + try_path = os.path.join(d_path, try_name) + if os.path.isfile(try_path): + extra_files.append(try_path) + print('Removing known extra file: "' + try_path + + '"') + try: + os.remove(try_path) + e_removed_count += 1 + except Exception as e: + e_failed_count += 1 + retry_lines.append(CMD_RM + '"' + try_path + + '"') + print(str(e)) + for try_name in try_dirs: + try_path = os.path.join(d_path, try_name) + if os.path.isdir(try_path): + extra_dirs.append(try_path) + print('Removing known extra folder: "' + try_path + + '"') + try: + os.rmdir(try_path) + ed_removed_count += 1 + except Exception as e: + ed_failed_count += 1 + retry_lines.append(CMD_RMDIR+'"'+try_path+'"') + print(str(e)) + os.rmdir(d_path) + except Exception as e: + print(str(e)) + if os.path.isdir(d_path): + d_failed_count += 1 + retry_lines.append(CMD_RMDIR+'"'+d_path+'"') + else: + d_removed_count += 1 else: - d_removed_count += 1 - else: - d_skipped_count += 1 -print("Removed " + str(d_removed_count) + " folder(s) (skipped not" - " present:" + str(d_skipped_count) + "; failed:" - + str(d_failed_count) + ")") -if e_failed_count > 0: - print("(failed to remove " + e_failed_count + " known extra file(s)" - " (will be shown under FAILURES below)") -if ed_failed_count > 0: - print("(failed to remove " + ed_failed_count + " known extra" - " folder(s) (will be shown under FAILURES below)") -print("Removed " + str(d_removed_count) + " folder(s) (skipped not" - " present:" + - str(d_skipped_count) + "; failed:" + str(d_failed_count) + ")") + d_skipped_count += 1 + print("Removed " + str(d_removed_count) + " folder(s) (skipped not" + " present:" + str(d_skipped_count) + "; failed:" + + str(d_failed_count) + ")") + if e_failed_count > 0: + print("(failed to remove " + e_failed_count + " known extra file(s)" + " (will be shown under FAILURES below)") + if ed_failed_count > 0: + print("(failed to remove " + ed_failed_count + " known extra" + " folder(s) (will be shown under FAILURES below)") + print("Removed " + str(d_removed_count) + " folder(s) (skipped not" + " present:" + + str(d_skipped_count) + "; failed:" + str(d_failed_count) + ")") -if f_failed_count+d_failed_count+ed_failed_count <= 0: - print("") - if f_removed_count+d_removed_count <= 0: - print("Nothing to do (minetest+minetestserver has 0 known files" - " on system--you apparently already uninstalled the local" - " version that was installed using 'sudo make install')") + code = 0 + if f_failed_count+d_failed_count+ed_failed_count <= 0: + print("") + if f_removed_count+d_removed_count <= 0: + print("Nothing to do (minetest+minetestserver has 0 known files" + " on system--you apparently already uninstalled the local" + " version that was installed using 'sudo make install')") + else: + print("OK [finished uninstalling all installed files]") + print("") else: - print("OK [finished uninstalling all installed files]") - print("") -else: - print("") - print("") - print(CMD_REM+"FAILURES:") - for rl in retry_lines: - print(rl) - print("") - print("In case of any failures are counted above, " - "try running this script with administrative privileges." - "If any more remain, you may have to remove them manually.") - print("") - print("") -if not ins.closed: - print("ERROR: ins was not closed (this should never happen)--" - "closing manually...") - ins.close() + print("") + print("") + print(CMD_REM+"FAILURES:") + for rl in retry_lines: + print(rl) + print("") + print("In case of any failures are counted above, " + "try running this script with administrative privileges." + "If any more remain, you may have to remove them manually.") + print("") + print("") + code = 1 + if not ins.closed: + print("ERROR: ins was not closed (this should never happen)--" + "closing manually...") + ins.close() + code = 1 + return code + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/utilities/compatiblizemod.py b/utilities/compatiblizemod.py index 29fc97b..d0d3f1a 100755 --- a/utilities/compatiblizemod.py +++ b/utilities/compatiblizemod.py @@ -8,13 +8,13 @@ import re import sys import os -myDir = os.path.dirname(os.path.realpath(__file__)) -repoDir = os.path.dirname(myDir) +UTILITIES_DIR = os.path.dirname(os.path.realpath(__file__)) +REPO_DIR = os.path.dirname(UTILITIES_DIR) # try: # from pyenliven.compatiblizemod import main # except ModuleNotFoundError: -if os.path.isdir(os.path.join(repoDir, "pyenliven")): - sys.path.append(repoDir) +if os.path.isfile(os.path.join(REPO_DIR, "pyenliven", "__init__.py")): + sys.path.append(REPO_DIR) from pyenliven.compatiblizemod import main diff --git a/utilities/enissue.py b/utilities/enissue.py index 8b2abd4..8b84047 100755 --- a/utilities/enissue.py +++ b/utilities/enissue.py @@ -93,7 +93,7 @@ except ImportError: # see -def error(*args, **kwargs): +def echo0(*args, **kwargs): print(*args, file=sys.stderr, **kwargs) @@ -261,7 +261,7 @@ def debug(*args, **kwargs): if verbose: if len(args) > 0: msg = args[0] - error("[debug] " + msg) + echo0("[debug] " + msg) def set_verbose(on): @@ -353,6 +353,8 @@ match_all_labels = [] trues = ["true", "on", "yes"] falses = ["false", "off", "no"] +# TODO: Consider from pycodetool import to_syntax_error +# (to replace instances of {}:{}: formatted by `path, line` below). def str_to_value(valueStr, typeName=None, lineN=-1, path="(generated)"): ''' @@ -387,7 +389,7 @@ def str_to_value(valueStr, typeName=None, lineN=-1, path="(generated)"): if typeName is not None: if valueStr == "None": - error("{}:{}: WARNING: The program expected a(n) '{}' but" + echo0("{}:{}: WARNING: The program expected a(n) '{}' but" " the value was 'None' and will become" " None." "".format(conf_path, lineN, typeName)) @@ -490,7 +492,7 @@ def modify_dict_by_conf(options, conf_path, always_lower=False, continue signI = line.find("=") if signI < 1: - error("{}:{}: A value is expected before '='." + echo0("{}:{}: A value is expected before '='." "".format(conf_path, lineN)) name = line[:signI].strip() valueStr = line[signI+1:].strip() @@ -499,11 +501,11 @@ def modify_dict_by_conf(options, conf_path, always_lower=False, value = None if always_lower: if name.lower() != name: - error("{}:{}: A lowercase name is expected." + echo0("{}:{}: A lowercase name is expected." "".format(conf_path, lineN)) continue if (valueStr is None) and no_value_error: - error("{}:{}: A value is expected." + echo0("{}:{}: A value is expected." "".format(conf_path, lineN)) else: typeName = None @@ -514,11 +516,11 @@ def modify_dict_by_conf(options, conf_path, always_lower=False, path=conf_path, lineN=lineN) options[name] = value if not quiet: - error("[settings] {}: Set {} to {}" + echo0("[settings] {}: Set {} to {}" "".format(conf_name, name, value)) else: if no_file_error: - error("Error: \"{}\" Doesn't exist" + echo0("Error: \"{}\" Doesn't exist" "".format(conf_path, lineN)) @@ -664,7 +666,7 @@ class Repo: self.remote_user = "almikes@aol.com" # Wuzzy2 if self.api_id is not None: if self.api_id != 'git_instaweb': - error("WARNING: URL has [] but self.api_id was {}" + echo0("WARNING: URL has [] but self.api_id was {}" "".format(urlParts[-2], self.api_id)) self.api_id = "git_instaweb" # Such as https://repo.or.cz/minetest_treasurer.git @@ -701,8 +703,8 @@ class Repo: if self.api_id is None: self.api_id = "Gitea" if "github.com" in repo_url.lower(): - error("WARNING: assuming Gitea but URL has github.com.") - error(" * assuming API is {} for {}" + echo0("WARNING: assuming Gitea but URL has github.com.") + echo0(" * assuming API is {} for {}" "".format(self.api_id, )) if self.api_id is None: raise RuntimeError("api_id is not set") @@ -1113,7 +1115,7 @@ class Repo: results = result err = to_error(result) if err is not None: - error("WARNING: a website error was saved" + echo0("WARNING: a website error was saved" " as an issue, so it will be deleted:" " \"{}\"" "".format(c_path)) @@ -1126,7 +1128,7 @@ class Repo: "".format(results_key)) results = results[results_key] else: - error("WARNING: expected {} in dict" + echo0("WARNING: expected {} in dict" "".format(results_key)) if result is not None: if hasattr(results, 'keys'): @@ -1461,9 +1463,9 @@ class Repo: fn += ".json" c_path += ".json" else: - error("url: {}".format(url)) - error("self.labels_url: {}".format(self.labels_url)) - error("self.issues_url: {}".format(self.issues_url)) + echo0("url: {}".format(url)) + echo0("self.labels_url: {}".format(self.labels_url)) + echo0("self.issues_url: {}".format(self.issues_url)) raise NotImplementedError("getCachedJsonDict" " doesn't have a cache directory" " for {}. Try --refresh" @@ -1494,8 +1496,8 @@ class Repo: try: result = json.load(json_file) except json.decoder.JSONDecodeError as ex: - error("") - error(p+"The file {} isn't valid JSON" + echo0("") + echo0(p+"The file {} isn't valid JSON" " and will be overwritten if loads" "".format(c_path)) result = None @@ -1505,7 +1507,7 @@ class Repo: err = to_error(result) if err is not None: result = None - error("Error: An error was saved as an issue" + echo0("Error: An error was saved as an issue" " so it will be deleted: {}" "".format(c_path)) os.remove(c_path) @@ -1691,8 +1693,8 @@ class Repo: msg = ("WARNING: comments={} but there is no" " comments_url in:" "".format(comments)) - # error(msg) - # error(json.dumps(issue_data, indent=4, sort_keys=True)) + # echo0(msg) + # echo0(json.dumps(issue_data, indent=4, sort_keys=True)) for evt in data: user = evt.get('user') @@ -1784,7 +1786,7 @@ class Repo: never_expire=never_expire, ) if err is not None: - error("Accessing the reactions URL failed: {}" + echo0("Accessing the reactions URL failed: {}" "".format(err.get('reason'))) if reac_data is not None: for reac in reac_data: @@ -2009,10 +2011,10 @@ class Repo: if results is None: if err is not None: if err.get('code') == 410: - # error("The issue was deleted") + # echo0("The issue was deleted") pass elif err.get('code') == 404: - # error("The issue doesn't exist") + # echo0("The issue doesn't exist") pass return None, err else: @@ -2111,10 +2113,10 @@ def main(custom_args=None): else: if issue_no is not None: usage() - error("Error: Only one issue number can be" + echo0("Error: Only one issue number can be" " specified but you also specified" " {}.".format(arg)) - exit(1) + return 1 issue_no = i is_text = False except ValueError: @@ -2129,15 +2131,15 @@ def main(custom_args=None): state = 'closed' elif arg == "--test": tests() - error("All tests passed.") - sys.exit(0) + echo0("All tests passed.") + return 0 elif arg == "--verbose": verbose = True elif arg == "--debug": verbose = True elif arg == "--help": usage() - exit(0) + return 0 elif arg in collect_logic: save_key = arg.strip("-").replace("-", "_") elif arg in collect_options: @@ -2149,9 +2151,9 @@ def main(custom_args=None): # else: the next arg will be the value. elif arg.startswith("--"): usage() - error("Error: The argument \"{}\" is not valid" + echo0("Error: The argument \"{}\" is not valid" "".format(arg)) - exit(1) + return 2 elif prev_arg in SEARCH_COMMANDS: search_terms.append(arg) isValue = True @@ -2162,15 +2164,15 @@ def main(custom_args=None): # print("* adding criteria: {}".format(arg)) if len(search_terms) < 1: usage() - error("You can only specify \"AND\" after" + echo0("You can only specify \"AND\" after" " the \"find\" command. To literally" " search for the word \"AND\", place" " the \"find\" command before it." " Examples:") for andI in modes['find']['AND_EXAMPLES']: - error(me + echo0(me + modes['find']['examples'][andI]) - exit(1) + return 3 mode = "list" elif save_key is not None: logic[save_key] = arg @@ -2220,7 +2222,7 @@ def main(custom_args=None): usage() print() print() - sys.exit(0) + return 0 elif mode not in valid_modes: print() print() @@ -2229,12 +2231,12 @@ def main(custom_args=None): print(mode + " is not a valid command.") print() print() - sys.exit(0) + return 0 elif mode == "list": if issue_no is not None: print("Error: You must specify either an issue number" " or query criteria, not both.") - sys.exit(1) + return 4 print("") if caches_path is not None: @@ -2287,12 +2289,12 @@ def main(custom_args=None): db_type = logic.get('db-type') if db_type is None: db_type = "PostgresQL" - error("WARNING: No db-type was specified, so db-type was" + echo0("WARNING: No db-type was specified, so db-type was" " set to the default: {}".format(db_type)) db_u = logic.get("db-user") if db_u is None: db_u = Repo.os_user - error("WARNING: No db-type was specified, so db-user was" + echo0("WARNING: No db-type was specified, so db-user was" " set to the default: {}".format(db_u)) pass db_p = logic.get('db-password') @@ -2301,7 +2303,7 @@ def main(custom_args=None): if "deleted" in msg: is_deleted = True if db_p is None: - error("WARNING: No db-password was specified, so the db" + echo0("WARNING: No db-password was specified, so the db" " operation will be attempted without it." " Success will depend on your database type and" " settings.") @@ -2309,14 +2311,14 @@ def main(custom_args=None): 'repo_url': dstRepoUrl, }) # print("* rewriting Gitea issue {}...".format(issue_no)) - sys.exit(0) # Change based on return of the method. + return 5 # TODO: Change based on return of the method. if msg is not None: - error(msg) + echo0(msg) if "deleted" in msg: - sys.exit(0) + return 0 else: - sys.exit(1) + return 6 total_count = 0 print() # ^ This blank line goes after "@ Cache" messages and before @@ -2324,11 +2326,11 @@ def main(custom_args=None): if mode == "labels": if repo.labels is None: print("There were no labels.") - sys.exit(0) + return 0 else: if repo.issues is None: print("There were no issues.") - sys.exit(0) + return 0 match_all_labels_lower = [] p = repo.log_prefix @@ -2494,7 +2496,8 @@ def main(custom_args=None): else: debug("There is no summary output due to mode={}".format(mode)) print("") + return 0 if __name__ == "__main__": - main() + sys.exit(main()) diff --git a/utilities/enlynx.py b/utilities/enlynx.py index 73d58ea..6bccde1 100755 --- a/utilities/enlynx.py +++ b/utilities/enlynx.py @@ -30,31 +30,31 @@ Examples: ''' +import sys +import subprocess me = "enlynx.py" browserPath = "lynx" sessionPath = "/tmp/enlynx.lynx-session" -import sys -import subprocess enc = {} # URL Encoded single characters enc[':'] = '%3A' # ^ Do this with urllib if there are many more -# see -def error(*args, **kwargs): - print(*args, file=sys.stderr, **kwargs) - verbose = True -def debug(msg): + +def echo0(*args, **kwargs): + print(*args, file=sys.stderr, **kwargs) + + +def echo1(*args, **kwargs): if not verbose: return - sys.stderr.write("{}\n".format(msg)) - sys.stderr.flush() + print(*args, file=sys.stderr, **kwargs) def usage(): - error(__doc__) + echo0(__doc__) def toSubQueryValue(value): @@ -83,7 +83,8 @@ any_q = "?q=" + toSubQuery("is", "issue") closed_q = "?q=" + toSubQuery("is", "issue") + '+' + toSubQuery("is", "closed") -if __name__ == "__main__": +def main(): + global browserPath prev_arg = None findStrings = [] base_q = open_q + "+" @@ -101,7 +102,7 @@ if __name__ == "__main__": elif prev_arg == "--browser": browserPath = arg elif prev_arg == "page": - page_param="&page=2" + page_param = "&page=2" prev_arg = None else: if arg == "--closed": @@ -115,31 +116,31 @@ if __name__ == "__main__": elif arg == "AND": if len(findStrings) == 0: usage() - error("Error: You can only use AND after find" + echo0("Error: You can only use AND after find" " and after another keyword. To literally" " search for the word \"AND\" itself," " say find before the word:\n" " {} find CREEPS find AND find WEIRDOS\n" "".format(me)) - exit(1) + return 1 prev_arg = arg elif arg == "page": prev_arg = arg else: encArg = toSubQueryValue(arg) # if encArg != arg: - # debug("* encoding label as '{}'".format(encArg)) + # echo1("* encoding label as '{}'".format(encArg)) # else: - debug("* adding label {}".format(encArg)) + echo1("* adding label {}".format(encArg)) labels_subqueries += toSubQuery('label', encArg) + "+" # Ensure there aren't any dangling commands *after* the loop: if prev_arg is not None: usage() - error("Error: You must specify a search term after {}." + echo0("Error: You must specify a search term after {}." "".format(prev_arg)) - exit(1) + return 1 if (_closed is True) and (_open is True): base_q = any_q + '+' @@ -148,8 +149,6 @@ if __name__ == "__main__": elif _closed is True: base_q = closed_q + '+' - - for find_str in findStrings: base_q += find_str + "+" # else: (dangling '+' at the end when labels_subqueries=="" is ok) @@ -159,3 +158,7 @@ if __name__ == "__main__": print("URL: {}".format(url)) subprocess.call([browserPath, '-session=' + sessionPath, url]) + return 0 + +if __name__ == "__main__": + sys.exit(main()) diff --git a/utilities/extra/uninstall.py b/utilities/extra/uninstall.py index c370eb6..85c874b 100644 --- a/utilities/extra/uninstall.py +++ b/utilities/extra/uninstall.py @@ -1,117 +1,126 @@ #!/usr/bin/env python import os +import sys import platform -def doDie(msg, error_code=1): +def show_error(msg, error_code=1): print() print(msg) print() print() - exit(error_code) + return error_code -rem_cmd = "#" -rm_cmd = "rm " -rmdir_cmd = "rmdir " -if platform.system() == "Windows": - rm_cmd = "DEL " - rmdir_cmd = "RD " - rem_cmd = "REM " -profile_path1 = os.environ.get('HOME') -profile_path = profile_path1 -profile_path2 = os.environ.get('USERPROFILE') -if profile_path2 is not None: - profile_path = profile_path2 - if profile_path1 is not None: - print(rem_cmd + "WARNING: HOME is present, but USERPROFILE '" - + profile_path + "' is being used.") -else: - if profile_path1 is None: - doDie(rem_cmd + "ERROR: There is nothing to do since neither" - + " HOME nor USERPROFILE is present.") - -mnf_name = "install_manifest.txt" -mnf_path = os.path.join(profile_path, mnf_name) - -unsorted_list = [] - -if not os.path.isfile(mnf_path): - doDie(rem_cmd + "Uninstall cannot continue since '" + mnf_path - + "' is missing.") - -with open(mnf_path) as fp: - for cnt, line_original in enumerate(fp): - # print("Line {}: {}".format(cnt, line)) - line = line_original.strip() - if len(line) > 0: - unsorted_list.append(line) - -if len(unsorted_list) < 1: - doDie(rem_cmd + "ERROR: There are no files in the manifest '" - + mnf_path + "'") - -# See https://stackoverflow.com/questions/4659524/\ -# how-to-sort-by-length-of-string-followed-by-alphabetical-order -sorted_list = sorted(unsorted_list, key=len, reverse=True) -# reverse: descending -# or (also reverse): -# the_list.sort(key=lambda item: (-len(item), item)) - -print(rem_cmd + "Uninstalling...") -not_removed_files = [] -not_removed_dirs = [] -does_not_exist = [] -file_count = 0 -dir_count = 0 -for path in sorted_list: - if os.path.isfile(path): - if path[0:1] == ".": - print(rm_cmd + "\"" + path + "\"") - not_removed_files.append(path) - continue - try: - os.remove(path) - file_count += 1 - except PermissionError: - not_removed_files.append(path) - elif os.path.isdir(path): - if path[0:1] == ".": - print(rmdir_cmd + "\"" + path + "\"") - not_removed_dirs.append(path) - continue - try: - os.rmdir(path) - dir_count += 1 - except PermissionError: - not_removed_dirs.append(path) +def main(): + rem_cmd = "#" + rm_cmd = "rm " + rmdir_cmd = "rmdir " + if platform.system() == "Windows": + rm_cmd = "DEL " + rmdir_cmd = "RD " + rem_cmd = "REM " + profile_path1 = os.environ.get('HOME') + profile_path = profile_path1 + profile_path2 = os.environ.get('USERPROFILE') + if profile_path2 is not None: + profile_path = profile_path2 + if profile_path1 is not None: + print(rem_cmd + "WARNING: HOME is present, but USERPROFILE '" + + profile_path + "' is being used.") else: - does_not_exist.append(path) + if profile_path1 is None: + return show_error(rem_cmd + "ERROR: There is nothing to do" + " since neither" + " HOME nor USERPROFILE is present.") -if len(does_not_exist) > 0: - if len(does_not_exist) == len(sorted_list): - doDie(" " + rem_cmd + " The program is not installed such as" - + " at '" + sorted_list[-1] + "'.") + mnf_name = "install_manifest.txt" + mnf_path = os.path.join(profile_path, mnf_name) -show_dot_warning = True -print(rem_cmd + "Uninstall is complete.") -print(rem_cmd + "- files: " + str(file_count)) -print(rem_cmd + "- directories: " + str(dir_count)) -print(rem_cmd + "- missing: " + len(does_not_exist)) -if (len(not_removed_files) + len(not_removed_dirs)) > 0: - for path in not_removed_files: - if path[0:1] == ".": - if show_dot_warning: - print(rem_cmd + "Paths starting with '.' are not yet" - " implemented.") - show_dot_warning = False - print(rm_cmd + "\"" + path + "\"") - for path in not_removed_dirs: - print(rmdir_cmd + "\"" + path + "\"") - print(rem_cmd + "Deleting items above FAILED:") - print(" " + rem_cmd + "- files: " + str(not_removed_file_count)) - print(" " + rem_cmd + "- directories: " - + str(not_removed_dir_count)) + unsorted_list = [] -print("") -print("") + if not os.path.isfile(mnf_path): + return show_error(rem_cmd + "Uninstall cannot continue since '" + + mnf_path + "' is missing.") + + with open(mnf_path) as fp: + for cnt, line_original in enumerate(fp): + # print("Line {}: {}".format(cnt, line)) + line = line_original.strip() + if len(line) > 0: + unsorted_list.append(line) + + if len(unsorted_list) < 1: + return show_error(rem_cmd + "ERROR: There are no files in the manifest" + " '"+ mnf_path + "'") + + # See https://stackoverflow.com/questions/4659524/\ + # how-to-sort-by-length-of-string-followed-by-alphabetical-order + sorted_list = sorted(unsorted_list, key=len, reverse=True) + # reverse: descending + # or (also reverse): + # the_list.sort(key=lambda item: (-len(item), item)) + + print(rem_cmd + "Uninstalling...") + not_removed_files = [] + not_removed_dirs = [] + does_not_exist = [] + file_count = 0 + dir_count = 0 + for path in sorted_list: + if os.path.isfile(path): + if path[0:1] == ".": + print(rm_cmd + "\"" + path + "\"") + not_removed_files.append(path) + continue + try: + os.remove(path) + file_count += 1 + except PermissionError: + not_removed_files.append(path) + elif os.path.isdir(path): + if path[0:1] == ".": + print(rmdir_cmd + "\"" + path + "\"") + not_removed_dirs.append(path) + continue + try: + os.rmdir(path) + dir_count += 1 + except PermissionError: + not_removed_dirs.append(path) + else: + does_not_exist.append(path) + + if len(does_not_exist) > 0: + if len(does_not_exist) == len(sorted_list): + return show_error(rem_cmd + 'The program is not installed such as' + ' at "{}".' + ''.format(sorted_list[-1])) + + show_dot_warning = True + print(rem_cmd + "Uninstall is complete.") + print(rem_cmd + "- files: " + str(file_count)) + print(rem_cmd + "- directories: " + str(dir_count)) + print(rem_cmd + "- missing: " + len(does_not_exist)) + if (len(not_removed_files) + len(not_removed_dirs)) > 0: + for path in not_removed_files: + if path[0:1] == ".": + if show_dot_warning: + print(rem_cmd + "Paths starting with '.' are not yet" + " implemented.") + show_dot_warning = False + print(rm_cmd + "\"" + path + "\"") + for path in not_removed_dirs: + print(rmdir_cmd + "\"" + path + "\"") + print(rem_cmd + "Deleting items above FAILED:") + print(" " + rem_cmd + "- files: " + str(not_removed_file_count)) + print(" " + rem_cmd + "- directories: " + + str(not_removed_dir_count)) + + print("") + print("") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/utilities/generatemod.py b/utilities/generatemod.py index 0f42ff9..7bc6fe1 100644 --- a/utilities/generatemod.py +++ b/utilities/generatemod.py @@ -7,13 +7,13 @@ myPath = os.path.realpath(__file__) myDir = os.path.dirname(myPath) -def customExit(msg, code=1): +def show_error(msg, code=1): print("") print("ERROR:") print(msg) print("") print("") - exit(code) + return code def usage(): @@ -44,155 +44,162 @@ def usage(): print("") -licSrc = "example_license.txt" -licDestName = "LICENSE.txt" -licDesc = "MIT License" -if not os.path.isfile(licSrc): - tryLicSrc = os.path.join(myDir, licSrc) - if not os.path.isfile(tryLicSrc): - print("ERROR: missing " + licSrc) - exit(1) - else: - licSrc = tryLicSrc -toMod = None -fromName = None -toName = None -extraArgCount = 0 -enableFill = False -options = [] -for i in range(1, len(sys.argv)): - if sys.argv[i] == "--fill": - extraArgCount += 1 - enableFill = True - else: - if (len(sys.argv[i]) >= 2) and (sys.argv[i][:2] == "--"): - usage() - customExit("Invalid option: " + sys.argv[i]) - options.append(sys.argv[i]) -if (len(options) != 1) and (len(options) != 3): - usage() - exit(1) -thisName = options[0] -if os.path.isdir(thisName): - if not enableFill: - print("") - print("ERROR: A mod named " + thisName + " cannot be ") - print("generated when the directory already exists.") - print("") - exit(1) -else: - os.mkdir(thisName) -if (len(options) == 3): - fromName = options[1] - toName = options[2] - delimI = toName.rfind(":") - if delimI > -1: - toMod = toName[:delimI] - if toMod.find(":") > -1: - usage() - customExit("Your modname contains too many colons.") - exit(1) - else: - toMod = "default" - -mobAPI = None -if toMod is not None: - if not os.path.isfile(os.path.join(thisName, "depends.txt")): - dependsOut = open(os.path.join(thisName, "depends.txt"), 'w') - dependsOut.write(toMod+"\n") - dependsOut.close() - if toMod.find("mob") > -1: - mobAPI = toMod - -if not os.path.isfile(os.path.join(thisName, "description.txt")): - descOut = open(os.path.join(thisName, "description.txt"), 'w') - descOut.write("\n") - descOut.close() - -if not os.path.isfile(os.path.join(thisName, "mod.conf")): - confOut = open(os.path.join(thisName, "mod.conf"), 'w') - confOut.write("name = "+thisName+"\n") - confOut.close() - -if not os.path.isfile(os.path.join(thisName, "readme.md")): - readmeOut = open(os.path.join(thisName, "readme.md"), 'w') - readmeLine1 = thisName + " Minetest Mod" - readmeOut.write(readmeLine1+"\n") - readmeOut.write("="*len(readmeLine1)+"\n") - readmeOut.write("See description.txt\n") - readmeOut.write("\n") - readmeOut.write("## License\n") - readmeOut.write("See " + licDestName + "\n") - readmeOut.close() - -licDest = os.path.join(thisName, licDestName) -if not os.path.isfile(licDest): - shutil.copyfile(licSrc, licDest) -luaOut = None -if not os.path.isfile(os.path.join(thisName, "init.lua")): - luaOut = open(os.path.join(thisName, "init.lua"), 'w') - # luaOut.write("#!/usr/bin/env lua\n") - luaOut.write("-- " + sys.argv[0] + " (EnlivenMinetest) generated\n") - luaOut.write("-- the original version of this file.\n") -fromMod = None # not required -step0 = "" - -if (len(options) == 3): - delimI = fromName.find(":") - if delimI > -1: - fromMod = fromName[:delimI] - else: - fromMod = "" - apiLinePrefix = "" - mobLinePrefix = "" - if luaOut is not None: - if mobAPI is not None: - apiLinePrefix = "-- " +def main(): + licSrc = "example_license.txt" + licDestName = "LICENSE.txt" + licDesc = "MIT License" + if not os.path.isfile(licSrc): + tryLicSrc = os.path.join(myDir, licSrc) + if not os.path.isfile(tryLicSrc): + print("ERROR: missing " + licSrc) + return 1 else: - mobLinePrefix = "-- " - luaOut.write("-- If your mobs API doesn't contain the\n") - luaOut.write("-- word 'mobs', your alias method is not\n") - luaOut.write("-- known. In that case, you may have to\n") - luaOut.write("-- change minetest.register_alias to your\n") - luaOut.write("-- mob API's (if your alias is for a mob).\n") - luaOut.write(mobLinePrefix + mobAPI + ':alias_mob("' - + fromName + '", "' + toName + '")' + "\n") - luaOut.write(apiLinePrefix + 'minetest.register_alias("' - + fromName + '", "' + toName + '")' + "\n") -else: - step0 = "Add your code init.lua." -if luaOut is not None: - luaOut.write("\n") - luaOut.close() + licSrc = tryLicSrc + toMod = None + fromName = None + toName = None + extraArgCount = 0 + enableFill = False + options = [] + for i in range(1, len(sys.argv)): + if sys.argv[i] == "--fill": + extraArgCount += 1 + enableFill = True + else: + if (len(sys.argv[i]) >= 2) and (sys.argv[i][:2] == "--"): + usage() + return show_error("Invalid option: " + sys.argv[i], + code=2) + options.append(sys.argv[i]) + if (len(options) != 1) and (len(options) != 3): + usage() + return 3 + thisName = options[0] + if os.path.isdir(thisName): + if not enableFill: + print("") + print("ERROR: A mod named " + thisName + " cannot be ") + print("generated when the directory already exists.") + print("") + return 4 + else: + os.mkdir(thisName) + if (len(options) == 3): + fromName = options[1] + toName = options[2] + delimI = toName.rfind(":") + if delimI > -1: + toMod = toName[:delimI] + if toMod.find(":") > -1: + usage() + return show_error("Your modname contains too many colons.", + code=5) + else: + toMod = "default" -print("") -print("") -print(step0) -print("The new mod is the " + thisName + " folder. Remember to:") -ender = "." -if (toMod is not None) and (len(toMod) > 0): - ender = "" -print("1. Edit depends.txt if your mod requires some mod" + ender) -if (toMod is not None) and (len(toMod) > 0): - print(" other than '" + toMod + "'.") -print("") -print("2. Edit description.txt to contain a brief description of") -print(" your mod (less than 100 characters).") -print("") -print("3. Edit LICENSE.txt and add the year and the name of all ") -print(" authors, and change the license if desired (The included") -print(" " + licSrc) -print(" should be the " + licDesc + ".") -print( - ''' The MIT License is good for Minetest mods so they can be used - most widely such as on app stores where replacing the program as per - the GPL v3 is not compliant with mobile OS security--the license of - most Minetest releases is the MIT License). Some joke licenses exist - but DO NOT protect your work in cases where they explicitly allow - others to copy your work and claim it as their own especially if they - modify it in any way. They would just be doing what you said they - could do! -''' -) -print("") -print("") + mobAPI = None + if toMod is not None: + if not os.path.isfile(os.path.join(thisName, "depends.txt")): + dependsOut = open(os.path.join(thisName, "depends.txt"), 'w') + dependsOut.write(toMod+"\n") + dependsOut.close() + if toMod.find("mob") > -1: + mobAPI = toMod + + if not os.path.isfile(os.path.join(thisName, "description.txt")): + descOut = open(os.path.join(thisName, "description.txt"), 'w') + descOut.write("\n") + descOut.close() + + if not os.path.isfile(os.path.join(thisName, "mod.conf")): + confOut = open(os.path.join(thisName, "mod.conf"), 'w') + confOut.write("name = "+thisName+"\n") + confOut.close() + + if not os.path.isfile(os.path.join(thisName, "readme.md")): + readmeOut = open(os.path.join(thisName, "readme.md"), 'w') + readmeLine1 = thisName + " Minetest Mod" + readmeOut.write(readmeLine1+"\n") + readmeOut.write("="*len(readmeLine1)+"\n") + readmeOut.write("See description.txt\n") + readmeOut.write("\n") + readmeOut.write("## License\n") + readmeOut.write("See " + licDestName + "\n") + readmeOut.close() + + licDest = os.path.join(thisName, licDestName) + if not os.path.isfile(licDest): + shutil.copyfile(licSrc, licDest) + luaOut = None + if not os.path.isfile(os.path.join(thisName, "init.lua")): + luaOut = open(os.path.join(thisName, "init.lua"), 'w') + # luaOut.write("#!/usr/bin/env lua\n") + luaOut.write("-- " + sys.argv[0] + " (EnlivenMinetest) generated\n") + luaOut.write("-- the original version of this file.\n") + fromMod = None # not required + step0 = "" + + if (len(options) == 3): + delimI = fromName.find(":") + if delimI > -1: + fromMod = fromName[:delimI] + else: + fromMod = "" + apiLinePrefix = "" + mobLinePrefix = "" + if luaOut is not None: + if mobAPI is not None: + apiLinePrefix = "-- " + else: + mobLinePrefix = "-- " + luaOut.write("-- If your mobs API doesn't contain the\n") + luaOut.write("-- word 'mobs', your alias method is not\n") + luaOut.write("-- known. In that case, you may have to\n") + luaOut.write("-- change minetest.register_alias to your\n") + luaOut.write("-- mob API's (if your alias is for a mob).\n") + luaOut.write(mobLinePrefix + mobAPI + ':alias_mob("' + + fromName + '", "' + toName + '")' + "\n") + luaOut.write(apiLinePrefix + 'minetest.register_alias("' + + fromName + '", "' + toName + '")' + "\n") + else: + step0 = "Add your code init.lua." + if luaOut is not None: + luaOut.write("\n") + luaOut.close() + + print("") + print("") + print(step0) + print("The new mod is the " + thisName + " folder. Remember to:") + ender = "." + if (toMod is not None) and (len(toMod) > 0): + ender = "" + print("1. Edit depends.txt if your mod requires some mod" + ender) + if (toMod is not None) and (len(toMod) > 0): + print(" other than '" + toMod + "'.") + print("") + print("2. Edit description.txt to contain a brief description of") + print(" your mod (less than 100 characters).") + print("") + print("3. Edit LICENSE.txt and add the year and the name of all ") + print(" authors, and change the license if desired (The included") + print(" " + licSrc) + print(" should be the " + licDesc + ".") + print( + ''' The MIT License is good for Minetest mods so they can be used + most widely such as on app stores where replacing the program as per + the GPL v3 is not compliant with mobile OS security--the license of + most Minetest releases is the MIT License). Some joke licenses exist + but DO NOT protect your work in cases where they explicitly allow + others to copy your work and claim it as their own especially if they + modify it in any way. They would just be doing what you said they + could do! + ''' + ) + print("") + print("") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/utilities/mtcompile-program-local.py b/utilities/mtcompile-program-local.py index 6c5bde2..9524cb3 100755 --- a/utilities/mtcompile-program-local.py +++ b/utilities/mtcompile-program-local.py @@ -39,13 +39,13 @@ import platform import os -def error(msg): - sys.stderr.write(msg + "\n") +def echo0(*args, **kwargs): + print(*args, file=sys.stderr, **kwargs) def customExit(msg): - error(msg) - exit(1) + echo0(msg) + sys.exit(1) def isExecutableFile(path): @@ -575,7 +575,7 @@ def main(): # Confirm that script is running in the right place. if not os.path.isdir('mtsrc'): - error(""" + echo0(""" Error: This script should be stored, and executed, in the directory which contains the "mtsrc" directory. """) @@ -1237,7 +1237,8 @@ again. print("Done\n") # end main + return 0 if __name__ == "__main__": - main() + sys.exit(main()) diff --git a/utilities/mtoldtonew.py b/utilities/mtoldtonew.py index b4436b4..442549d 100644 --- a/utilities/mtoldtonew.py +++ b/utilities/mtoldtonew.py @@ -92,20 +92,28 @@ def oldToNew(path, quotechar='"'): print("* wrote '%s'" % newName) -if __name__ == "__main__": +def main(): for i in range(1, len(sys.argv)): try_path = sys.argv[i] if os.path.isfile(try_path): files.append(try_path) else: print("MISSING file: '" + try_path + "'") + return 1 if len(files) < 1: usage() print("") print("You must specify a plain-text schem such as a\n" ".we file, or any file containing double-quoted node names.") + return 2 for oldName in files: print("Processing %s..." % oldName) oldToNew(oldName) + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/utilities/showmissing.py b/utilities/showmissing.py index a75dde2..3952306 100755 --- a/utilities/showmissing.py +++ b/utilities/showmissing.py @@ -11,16 +11,6 @@ def usage(): print("") -argCount = len(sys.argv) - 1 - -if argCount < 2: - usage() - exit(1) - -oldPath = sys.argv[1] -newPath = sys.argv[2] - - def getStrings(path, delimiter='"', unique=True): ret = [] got = "" @@ -46,8 +36,23 @@ def getStrings(path, delimiter='"', unique=True): return ret -olds = getStrings(oldPath) -news = getStrings(newPath) -for v in olds: - if v not in news: - print(v) +def main(): + argCount = len(sys.argv) - 1 + + if argCount < 2: + usage() + return 1 + + oldPath = sys.argv[1] + newPath = sys.argv[2] + + olds = getStrings(oldPath) + news = getStrings(newPath) + for v in olds: + if v not in news: + print(v) + return 0 + + +if __name__ == "__main__": + sys.exit(main())