diff options
-rw-r--r-- | downloads.txt | 37 | ||||
-rw-r--r-- | latest-urls.txt | 37 | ||||
-rw-r--r-- | mods.txt | 4 | ||||
-rwxr-xr-x | update.py | 202 | ||||
-rw-r--r-- | version.txt | 4 | ||||
-rw-r--r-- | whitelist.txt | 1 |
6 files changed, 152 insertions, 133 deletions
diff --git a/downloads.txt b/downloads.txt deleted file mode 100644 index 47ca892..0000000 --- a/downloads.txt +++ /dev/null @@ -1,37 +0,0 @@ -# Format: <jarname> <hex digested sha1> <direct download url> -jei-01.jar f7672ddb5b7ac55ce3b49b55ad39977092737469 https://media.forgecdn.net/files/2635/239/jei_1.12.2-4.13.1.222.jar -projectredinteg-01.jar 851f7fdfaa8a545cbee59c61455a949049e12075 https://media.forgecdn.net/files/2572/427/ProjectRed-1.12.2-4.9.1.92-integration.jar -forgemultipart-01.jar 7b67222f2a61bb8574250b37df933a2f3b9c39e2 https://media.forgecdn.net/files/2626/992/ForgeMultipart-1.12.2-2.6.0.79-universal.jar -projectredcore-01.jar c9012fa49e8eb9150085b00395b3bf99cb0a2972 https://media.forgecdn.net/files/2572/409/MrTJPCore-1.12.2-2.1.3.35-universal.jar -thermaldynamics-01.jar a41bc51c0b659f80c6e90a0d60cc02b3f84a7b6b https://media.forgecdn.net/files/2624/182/ThermalDynamics-1.12.2-2.5.3.16-universal.jar -thermalfoundation-01.jar 4d7b2f42799e3dff84c7c517d3162e645863bb7d https://media.forgecdn.net/files/2623/991/ThermalFoundation-1.12.2-2.6.1.22-universal.jar -thermalexpansion-01.jar 9c81d89d97cff26c09bae1146012e1873cb884ae https://media.forgecdn.net/files/2624/855/ThermalExpansion-1.12.2-5.5.2.39-universal.jar -twilightforest-01.jar 418e55d39800696341d888dd9f407daee3748276 https://media.forgecdn.net/files/2618/264/twilightforest-1.12.2-3.8.689-universal.jar -idklib-01.jar 34244f742099f077ec0519969b3989784343ae02 https://media.forgecdn.net/files/2626/982/mcjtylib-1.12-3.0.6.jar -projectredmech-01.jar 6d491aeddba2c5c22596ecb65b3d5621edf419d8 https://media.forgecdn.net/files/2572/422/ProjectRed-1.12.2-4.9.1.92-mechanical.jar -chickenchunks-01.jar 22646ea2acdad735b5e82d8b80e4e40ec27aa62b https://media.forgecdn.net/files/2594/241/ChickenChunks-1.12.2-2.4.1.73-universal.jar -translocators-01.jar 455f6b3e51821ad70d37f51a7b0a1aae2a9cac6c https://media.forgecdn.net/files/2594/249/Translocators-1.12.2-2.5.1.77-universal.jar -tinkers-01.jar 7d31986c8c714bb588a63e1c686f38abcedeb914 https://media.forgecdn.net/files/2571/785/TConstruct-1.12.2-2.10.1.87.jar -imersiveengineering-01.jar dba5544ae411b9ed1165edde345bbab901f84096 https://media.forgecdn.net/files/2625/312/ImmersiveEngineering-0.12-86.jar -baubles-01.jar cb13fcfb18a9cb0cbd825fd5fe8d813c77368549 https://media.forgecdn.net/files/2518/667/Baubles-1.12-1.5.2.jar -cofhcore-01.jar a448365b93842d40f8d52e823fd7acc69263269c https://media.forgecdn.net/files/2623/990/CoFHCore-1.12.2-4.6.1.22-universal.jar -projectredcompat-01.jar bcfa9a8198b6a0f14bb8a79df5d94a3d5aea9666 https://media.forgecdn.net/files/2572/420/ProjectRed-1.12.2-4.9.1.92-compat.jar -cofhworld-01.jar df965eac4acfabc3874efe6517d032467313855c https://media.forgecdn.net/files/2623/91/CoFHWorld-1.12.2-1.3.0.6-universal.jar -enderio-01.jar 7c84b758a309fabb2fcba69b658ab4e2bb5d0629 https://media.forgecdn.net/files/2632/831/EnderIO-1.12.2-5.0.37.jar -projectred-01.jar 334d4d68ef71f6aedb0fc5855dc672f7b6ac2aec https://media.forgecdn.net/files/2572/421/ProjectRed-1.12.2-4.9.1.92-world.jar -mantle-01.jar bb23a99220319ebd1e6452e7a7e973aca6b286b3 https://media.forgecdn.net/files/2630/843/Mantle-1.12-1.3.3.39.jar -tech-reborn-01.jar 87c0e64c49ee066b85771cffc1bcd3b9defe326d https://media.forgecdn.net/files/2633/989/TechReborn-1.12.2-2.17.7.840-universal.jar -passwordlib-01.jar 7dbb26e59a96db83f3e64b4078bfd6339e3055fc https://media.forgecdn.net/files/2616/338/p455w0rdslib-1.12-2.0.35.jar -redstoneflux-01.jar ed67a4ce69c8831b7536b2623a857fefc8257e62 https://media.forgecdn.net/files/2623/90/RedstoneFlux-1.12-2.1.0.6-universal.jar -projectredcore2-01.jar 89744b1a82275d12cd9cf95014544c0f79ba7467 https://media.forgecdn.net/files/2572/423/ProjectRed-1.12.2-4.9.1.92-Base.jar -opencomputers-02.jar 70feadd549255477810dff7145cade9d507b2dec https://media.forgecdn.net/files/2638/675/OpenComputers-MC1.12.2-1.7.3.146.jar -reborncore-01.jar c750c0eb1b31fa8c8ef6aedfc69ebe42a8d83d78 https://media.forgecdn.net/files/2634/706/RebornCore-1.12.2-3.10.4.348-universal.jar -connectedtextures-01.jar 02c17c9af47b54439cb22b9c17f6c93a1fd3ffe5 https://media.forgecdn.net/files/2629/306/CTM-MC1.12.2-0.3.2.20.jar -foamfix.jar 69a9086f2084d3cbc3a410ee64369d719a212330 https://media.forgecdn.net/files/2638/380/foamfix-0.10.3-1.12.2.jar -thaumcraft-01.jar fe0899048f1796df04e9727bbf1898df30492a00 https://media.forgecdn.net/files/2629/23/Thaumcraft-1.12.2-6.1.BETA26.jar -codechickenlib-01.jar 1ead040eeee13c474d448f976363778e2918a7d0 https://media.forgecdn.net/files/2618/630/CodeChickenLib-1.12.2-3.2.2.353-universal.jar -endercore-01.jar cb35af97775e257eedb94e6f09e2d50606cdb9bd https://media.forgecdn.net/files/2632/476/EnderCore-1.12.2-0.5.43.jar -rftools-01.jar 09dfed39207c757c7b8120673f98a00c3c83cca1 https://media.forgecdn.net/files/2616/385/rftools-1.12-7.56.jar -wirelesscraftingterminal-02.jar 5d78cfb2bf3033950b76c499589148de20b70f14 https://media.forgecdn.net/files/2619/932/WirelessCraftingTerminal-1.12.2-3.10.82.jar -ae2-01.jar a7dfa60f06388091f13a42f2025f9d96a4ea7e18 https://media.forgecdn.net/files/2630/108/appliedenergistics2-rv6-stable-3.jar -enderstorage-01.jar 4b44e4b5d4aa7887e2f0969acc9cf7b83c8c81f5 https://media.forgecdn.net/files/2594/243/EnderStorage-1.12.2-2.4.5.135-universal.jar diff --git a/latest-urls.txt b/latest-urls.txt deleted file mode 100644 index 7309b64..0000000 --- a/latest-urls.txt +++ /dev/null @@ -1,37 +0,0 @@ -thaumcraft-01.jar https://minecraft.curseforge.com/projects/thaumcraft/files/2629023/download -baubles-01.jar https://minecraft.curseforge.com/projects/baubles/files/2518667/download -ae2-01.jar https://media.forgecdn.net/files/2630/108/appliedenergistics2-rv6-stable-3.jar -tech-reborn-01.jar https://media.forgecdn.net/files/2633/989/TechReborn-1.12.2-2.17.7.840-universal.jar -rftools-01.jar https://media.forgecdn.net/files/2616/385/rftools-1.12-7.56.jar -tinkers-01.jar https://media.forgecdn.net/files/2571/785/TConstruct-1.12.2-2.10.1.87.jar -enderio-01.jar https://media.forgecdn.net/files/2632/831/EnderIO-1.12.2-5.0.37.jar -imersiveengineering-01.jar https://media.forgecdn.net/files/2625/312/ImmersiveEngineering-0.12-86.jar -thermalexpansion-01.jar https://media.forgecdn.net/files/2624/855/ThermalExpansion-1.12.2-5.5.2.39-universal.jar -thermaldynamics-01.jar https://media.forgecdn.net/files/2624/182/ThermalDynamics-1.12.2-2.5.3.16-universal.jar -wirelesscraftingterminal-02.jar https://media.forgecdn.net/files/2619/932/WirelessCraftingTerminal-1.12.2-3.10.82.jar -projectredcore-01.jar https://media.forgecdn.net/files/2572/409/MrTJPCore-1.12.2-2.1.3.35-universal.jar -projectred-01.jar https://media.forgecdn.net/files/2572/421/ProjectRed-1.12.2-4.9.1.92-world.jar -projectredcompat-01.jar https://media.forgecdn.net/files/2572/420/ProjectRed-1.12.2-4.9.1.92-compat.jar -projectredmech-01.jar https://media.forgecdn.net/files/2572/422/ProjectRed-1.12.2-4.9.1.92-mechanical.jar -projectredinteg-01.jar https://media.forgecdn.net/files/2572/427/ProjectRed-1.12.2-4.9.1.92-integration.jar -translocators-01.jar https://media.forgecdn.net/files/2594/249/Translocators-1.12.2-2.5.1.77-universal.jar -opencomputers-02.jar https://minecraft.curseforge.com/projects/opencomputers/files/2638675/download -jei-01.jar https://media.forgecdn.net/files/2635/239/jei_1.12.2-4.13.1.222.jar -thermalfoundation-01.jar https://media.forgecdn.net/files/2623/991/ThermalFoundation-1.12.2-2.6.1.22-universal.jar -chickenchunks-01.jar https://media.forgecdn.net/files/2594/241/ChickenChunks-1.12.2-2.4.1.73-universal.jar -enderstorage-01.jar https://media.forgecdn.net/files/2594/243/EnderStorage-1.12.2-2.4.5.135-universal.jar -codechickenlib-01.jar https://media.forgecdn.net/files/2618/630/CodeChickenLib-1.12.2-3.2.2.353-universal.jar -endercore-01.jar https://media.forgecdn.net/files/2632/476/EnderCore-1.12.2-0.5.43.jar -forgemultipart-01.jar https://media.forgecdn.net/files/2626/992/ForgeMultipart-1.12.2-2.6.0.79-universal.jar -cofhcore-01.jar https://media.forgecdn.net/files/2623/990/CoFHCore-1.12.2-4.6.1.22-universal.jar -mantle-01.jar https://media.forgecdn.net/files/2630/843/Mantle-1.12-1.3.3.39.jar -passwordlib-01.jar https://media.forgecdn.net/files/2616/338/p455w0rdslib-1.12-2.0.35.jar -cofhworld-01.jar https://media.forgecdn.net/files/2623/91/CoFHWorld-1.12.2-1.3.0.6-universal.jar -redstoneflux-01.jar https://media.forgecdn.net/files/2623/90/RedstoneFlux-1.12-2.1.0.6-universal.jar -projectredcore2-01.jar https://media.forgecdn.net/files/2572/423/ProjectRed-1.12.2-4.9.1.92-Base.jar -idklib-01.jar https://media.forgecdn.net/files/2626/982/mcjtylib-1.12-3.0.6.jar -reborncore-01.jar https://media.forgecdn.net/files/2634/706/RebornCore-1.12.2-3.10.4.348-universal.jar -twilightforest-01.jar https://minecraft.curseforge.com/projects/the-twilight-forest/files/2618264/download -connectedtextures-01.jar https://minecraft.curseforge.com/projects/ctm/files/2629306/download -foamfix.jar https://minecraft.curseforge.com/projects/foamfix-for-minecraft/files/latest -# planarartiface-01.jar https://minecraft.curseforge.com/projects/planarartifice/files/2624612/download diff --git a/mods.txt b/mods.txt new file mode 100644 index 0000000..e608825 --- /dev/null +++ b/mods.txt @@ -0,0 +1,4 @@ +# fill this file with the same as downloads.txt but with links to the latest urls instead +# e.g. +thaumcraft.jar https://minecraft.curseforge.com/projects/thaumcraft/files/latest +baubles.jar https://minecraft.curseforge.com/projects/baubles/files/latest @@ -1,90 +1,174 @@ #!/usr/bin/env python3 -import hashlib -import requests + +import argparse import os -import shutil import sys +import hashlib +import shutil + +import requests -# Initalize from config -INSTALL_DIR = "" -with open("pack-location.txt", "r") as f: - INSTALL_DIR = f.read().strip() +parser = argparse.ArgumentParser( + description="A Simple Git-Based Modpack Manager", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog='''\ +Available commands: + install : Downloads mods listed in version.txt and populates the mods folder specified in pack-location.txt + apply_updates : Using the urls in mods.txt, repopulates version.txt to reflect the most recent mod versions + check_updates : Compares version.txt and mods.txt to see if any mods can be updated +''') +parser.add_argument('command', + nargs='?', + default='install', + help="The action to perform (default: install)") +parser.add_argument('filename', + nargs='?', + default="mods.txt", + help="Optional filename to specify latest mods (default: mods.txt)") +parser.add_argument('--version-file', + type=str, + default="version.txt", + help="Optional custom version file to download mods from (default: version.txt)") +parser.add_argument('--pack-location', + type=str, + help="Optional custom modpack folder location (default: read from pack-location.txt)") +parser.add_argument('--whitelist-file', + type=str, + default="whitelist.txt", + help="Optional custom whitelist file that tells 'install' which files not to remove (default: whitelist.txt)") + +## loaded from version.txt +VERSION = 0 + +def read_file(fil): + strings = [] + with open(fil) as f: + for line in f: + string = line.strip().split() + if len(line) > 1 and line[0] != '#': + # run strip on each element + string = tuple(map(lambda x: x.strip(), string)) + strings.append(string) + + return strings # Apply updates to the actual mod pack -def install(): - print("Updating pack...") +def install(args): + print("Updating pack with version " + str(VERSION) + "...") + print() # (fname, checksum, url) - mods = read_file("downloads.txt") + mods = read_file(args.version_file) names = [mod[0] for mod in mods] + # whitelist client mods (e.g. optifine) + names += [line[0] for line in read_file(args.whitelist_file)] + for mod in mods: - if mod[0] in os.listdir(INSTALL_DIR) and hashlib.sha1(open(os.path.join(INSTALL_DIR, mod[0]), 'rb').read()).hexdigest() == mod[1]: - print("Skipping " + mod[0] + ", already up to date") + mod_path = os.path.join(args.pack_location, mod[0]) + if os.path.exists(mod_path) and os.path.isfile(mod_path) and \ + hashlib.sha1(open(mod_path, 'rb').read()).hexdigest() == mod[1]: + print("Skipping {mod[0]}, already up to date".format(mod=mod)) else: - print(f'Installing {mod[0]} from {mod[2]}...') + print('Installing {mod[0]} from {mod[2]}...'.format(mod=mod)) download_obj = requests.get(mod[2], stream=True) - with open(os.path.join(INSTALL_DIR, mod[0]), "wb") as write_file: + with open(mod_path, "wb") as write_file: shutil.copyfileobj(download_obj.raw, write_file) print("Done!") - print("\nRemoving old versions...") - for jar in os.listdir(INSTALL_DIR): + print() + print("Removing old mods...") + for jar in os.listdir(args.pack_location): if jar not in names and os.path.splitext(jar)[1] == ".jar": - os.remove(os.path.join(INSTALL_DIR, jar)) - print(f"Removing '{jar}'") + os.remove(os.path.join(args.pack_location, jar)) + print("Removing '{jar}'".format(jar=jar)) - print("\nFinished updating pack!") + print() + print("Finished installing mods!") -# Using the latest urls, update downloads.txt to match the urls and have the correct sha1 -def apply_updates(): - print("Reading update file...") - mods = read_file("latest-urls.txt") - print("Downloading new versions of all mods...") - with open('downloads.txt', 'w') as f: +# Using the latest urls, update downloads.txt to match and have the correct sha1 +def apply_updates(args): + print("Populating version File...") + mods = read_file(args.filename) + print("Getting new versions of all mods...") + with open(args.version_file, 'w') as f: f.write('# Format: <jarname> <hex digested sha1> <direct download url>\n') + f.write("#VERSION " + str(VERSION + 1) + "\n") for mod in mods: - print(f"Downloading {mod[0]}...") + print("Fetching {mod[0]}...".format(mod=mod)) resp = requests.get(mod[1]) - hsh = hashlib.sha1(resp.content) - f.write(f'{mod[0]} {hsh.hexdigest()} {resp.url}\n') - print("\nDone downloading updates!") + hsh = hashlib.sha1(resp.content).hexdigest() + f.write('{mod[0]} {hsh} {resp.url}\n'.format(mod=mod, hsh=hsh, resp=resp)) + print() + print("Done!") + print("Updates applied to {args.version_file}".format(args=args)) + print("New pack version is " + str(VERSION + 1)) + print("[!] No mods were installed. To update your mods folder, run 'update.py install'") + # Find if any updates are available -def check_updates(): - print("Reading update files...") - latest = read_file("latest-urls.txt") - old = read_file("downloads.txt") +def check_updates(args): + print("Checking for updates to version " + str(VERSION) + "...") + latest = read_file(args.filename) + old = read_file(args.version_file) old_urls = [mod[2] for mod in old] + num_updates = 0 - print("Checking updates...\nThe following mods have updates available:\n") + print("Checking updates...") for mod in latest: + print("Checking for updates to {mod[0]}...".format(mod=mod), end="") + sys.stdout.flush() # takes care of line-buffered terminals resp = requests.get(mod[1]) - if not resp.url in old_urls: - print(f" -> Found update for {mod[0]}: {resp.url.split('/')[-1]}") - print("\nFinished checking for updates!") + if resp.url in old_urls: + print(" No updates") + else: + print(" Found update: " + resp.url.split('/')[-1]) + num_updates += 1 + + print("Finished checking for updates. {num} mods can be updated".format(num=num_updates)) + if num_updates >= 0: + print("Run 'python update.py apply_updates' to create a new version with these updates applied.") -def read_file(fil): - strings = set() - with open(fil) as f: - for line in f: - string = line.strip().split() - if len(line) >= 1 and line[0] != '#': - # run strip on each element - string = tuple(map(lambda x: x.strip(), string)) - strings.add(string) - return strings +COMMAND_MAP = { + 'install': install, + 'apply_updates': apply_updates, + 'check_updates': check_updates, +} +if __name__ == "__main__": + args = parser.parse_args() + + if not args.pack_location: + # initialize from config + with open("pack-location.txt", "r") as f: + args.pack_location = f.read().strip() -if len(sys.argv) < 2: - print(f"Usage: {sys.argv[0]} <apply_updates|find_updates>") - sys.exit(-1) -elif sys.argv[1] == 'install': - install() -elif sys.argv[1] == 'apply_updates': - apply_updates() -elif sys.argv[1] == 'check_updates': - check_updates() -else: - print(f"Usage: {sys.argv[0]} <install|apply_updates|check_updates>") - sys.exit(-1) + if not os.path.exists(args.version_file): + print("Error: version file\"" + args.version_file + "\" does not exist.") + parser.print_help() + sys.exit(1) + if not os.path.exists(args.pack_location): + print("Error: mod folder \"" + args.pack_location + "\" does not exist.") + parser.print_help() + sys.exit(1) + elif not os.path.isdir(args.pack_location): + print("Error: mod folder \"" + args.pack_location + "\" is not actually a folder.") + parser.print_help() + sys.exit(1) + if not os.path.exists(args.whitelist_file): + print("Error: whitelist file \"" + args.whitelist_file + "\" does not exist.") + sys.exit(1) + + if not (args.command in COMMAND_MAP): + print("Error: command \"" + args.command + "\" does not exist") + parser.print_help() + sys.exit(1) + + # fetch version + with open(args.version_file) as f: + for line in f: + if line.strip().split()[0] == "#VERSION": + VERSION = int(line.strip().split()[1]) + break + # run the command + COMMAND_MAP[args.command](args) diff --git a/version.txt b/version.txt new file mode 100644 index 0000000..eb901a8 --- /dev/null +++ b/version.txt @@ -0,0 +1,4 @@ +# Format: <jarname> <hex digested sha1> <direct download url> +#VERSION 16 +thaumcraft.jar ef9f8aaf4a4bfe29afb9ebc0fb90b15f2a62a0fb https://minecraft.curseforge.com/projects/thaumcraft/files/latest +baubles.jar 498452d113a210bda499c49b650b4eae57866a19 https://minecraft.curseforge.com/projects/baubles/files/latest diff --git a/whitelist.txt b/whitelist.txt new file mode 100644 index 0000000..76c8d1f --- /dev/null +++ b/whitelist.txt @@ -0,0 +1 @@ +# file names in here are NOT removed from mods folder during 'install' |