From 3534aa5b5d7ee187afe64914cd7b5e3080a050c3 Mon Sep 17 00:00:00 2001 From: Minecon724 Date: Thu, 24 Oct 2024 12:49:37 +0200 Subject: [PATCH] Initial commit --- README.md | 9 +++ channel.py | 54 ++++++++++++++++ release.py | 183 +++++++++++++++++++++++++++++++++++++++++++++++++++++ reset.py | 15 +++++ url.txt | 1 + 5 files changed, 262 insertions(+) create mode 100644 README.md create mode 100644 channel.py create mode 100644 release.py create mode 100644 reset.py create mode 100644 url.txt diff --git a/README.md b/README.md new file mode 100644 index 0000000..9584269 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +Scripts to manage jarupdater metadata + +Files: +- `url.txt`: Change this to the URL of the repo, like `https://git.m724.eu/Minecon724/myplugin-metadata/raw/branch/master` + +Scripts: +- `channel.py`: creates and removes channels +- `release.py`: creates and pushes releases +- `reset.py`: removes data/ diff --git a/channel.py b/channel.py new file mode 100644 index 0000000..09b4849 --- /dev/null +++ b/channel.py @@ -0,0 +1,54 @@ +from sys import argv +from os import path, mkdir +from shutil import rmtree + +channels = argv[1:] + +if not path.isdir('data'): + print("Creating data") + mkdir('data') + +if path.isfile('data/channels.txt'): + file = open('data/channels.txt', 'r+') + existing = [c.strip() for c in file] +# print(existing) +else: + file = open('data/channels.txt', 'w') + existing = [] + +if channels == []: + if existing == []: + print("No channels") + else: + print("Channels: " + ','.join(existing)) + +for ch in channels: + remove = ch.startswith('-') + if remove: + ch = ch[1:] + + if ch not in existing: + print(f"Channel {ch} doesn't exist") + continue + + rmtree('data/' + ch) + existing.remove(ch) + + file.truncate(0) + file.seek(0) + file.writelines([e + '\n' for e in existing]) + + print("Removed " + ch) + else: + if ch in existing: + print(f"Channel {ch} already exists") + continue + + file.write(ch + '\n') + try: + mkdir('data/' + ch) + except FileExistsError: + print(f"Channel {ch} already exists but wasn't in channels.txt, now added") + + existing += [ch] + print("Created " + ch) diff --git a/release.py b/release.py new file mode 100644 index 0000000..1701f28 --- /dev/null +++ b/release.py @@ -0,0 +1,183 @@ +#!/usr/bin/python3 + +import json, os, time, tempfile, shutil +from hashlib import sha256 + +META_FILENAME = 'meta-v1.json' +BASE_URL = open('url.txt').read().strip() +BASE_DIR = 'data' +WAITING_DIR = 'pending' +TEMP_DIR = tempfile.TemporaryDirectory() + +# file scanner functions + +def match_name(filename: str, extension: str=None, exact_name: str=None): + if exact_name is not None: + return filename == exact_name + elif extension is not None: + return filename.lower().endswith(extension.lower()) + return True + +def scan_for_file(ask: bool=False, extension: str=None, exact_name: str=None) -> tuple[str]: + for file in os.scandir(): + if file.is_dir(): continue + if not match_name(file.name, extension, exact_name): continue + + if ask: + if not confirm(f"Found {file.name} in the current directory, do you want to proceed with it?"): + return (None, None) + + return (file.path, file.name) + return (None, None) + +def wait_for_file(waiting_dir: str, extension: str=None) -> tuple[str]: + print(f"Please put a {extension} file in {waiting_dir}") + while True: + files = [i for i in os.scandir(waiting_dir)] + + if len(files) == 0: + time.sleep(0.5) + continue + + file = files[0] + filepath = file.path + filename = file.name + + if match_name(filename, extension): + break + else: + os.remove(filepath) + print(f"Not a {extension} file: {filename}") + + return (filepath, filename) + +def just_find_file(name: str) -> tuple[str]: + spl = name.split('.') + extension = spl[-1] + exact_name = name[:-len(extension)-1] if len(spl) > 1 else None + + filepath, filename = scan_for_file(True, extension, exact_name) + if filepath is None: + try: + os.makedirs(WAITING_DIR, exist_ok=True) + filepath, filename = wait_for_file(WAITING_DIR, extension) + except KeyboardInterrupt: + os.rmdir(WAITING_DIR) + return + + if filepath is not None: + tpath = os.path.join(TEMP_DIR.name, filename) + shutil.move(filepath, tpath) + filepath = tpath + + return (filepath, filename) + +# directory util fnctions + +def make_path(channel: str, version: str=None, filename: str=None) -> str: + args = [channel, version, filename] + args = [i for i in args if i is not None] + return os.path.join(BASE_DIR, *args) + +def list_channels() -> list[str]: + return next(os.walk(BASE_DIR))[1] + +# verification functions + +def channel_exists(channel: str) -> bool: + """Checks if channel exists""" + return os.path.isdir(make_path(channel)) + +def check_version_exists(version: str) -> str | None: + """ + Check if version exists in any channel. + If yes, returns that channel, otherwise None + """ + for channel in list_channels(): + if os.path.isdir(make_path(channel, version)): + return channel + +# metadata functions + +def load_latest_data(channel: str) -> dict: + path = make_path(channel, 'latest', META_FILENAME) + if os.path.isfile(path): + return json.loads(open(path).read()) + return {'id': 0} + +def write_metadata(channel: str, metadata: dict): + version = metadata['label'] + metadata = json.dumps(metadata) + for filepath in [make_path(channel, version, META_FILENAME), make_path(channel, 'latest', META_FILENAME)]: + with open(filepath, 'w') as file: + file.write(metadata) + +def commit_and_push(channel: str, version: str): + os.system('git add .') + os.system(f'git commit -m "[releaser] Release {version} on {channel}"') + os.system('git push') + +# other + +def confirm(prompt: str) -> bool: + confirmed = input(prompt + ' (Y/N) ') + return confirmed.lower() == 'y' + +def hash_file(filepath: str) -> str: + with open(filepath, 'rb') as file: + return sha256(file.read()).hexdigest() + +# main + +def main(): + channel = input('Channel? ({}) '.format(', '.join(list_channels()))) + if channel == '' or not channel_exists(channel): + print(f"Channel {channel} doesn't exist") + return + + version = input('New version? ') + exists_in = check_version_exists(version) + if exists_in is not None: + print(f"This version already exists in channel {exists_in}. Choose a different version.") + return + + jar_filepath, jar_filename = just_find_file('jar') + + changelog = confirm('Do you want to include a changelog?') + if changelog: + chlog_filepath, chlog_filename = just_find_file('changelog.txt') + + # + + latest_data = load_latest_data(channel) + hash = hash_file(jar_filepath) + + version_dir = make_path(channel, version) + + os.makedirs(make_path(channel, 'latest'), exist_ok=True) + os.mkdir(version_dir) + shutil.move(jar_filepath, os.path.join(version_dir, jar_filename)) + if changelog: shutil.move(chlog_filepath, os.path.join(version_dir, 'changelog.txt')) + + metadata = { + 'label': version, + 'id': latest_data['id'] + 1, + 'timestamp': int(time.time()), + 'file': f'{BASE_URL}/{BASE_DIR}/{channel}/{version}/{jar_filename}', + 'sha256': hash + } + + write_metadata(channel, metadata) + + try: + os.rmdir(WAITING_DIR) + except FileNotFoundError: + pass + + if confirm("Commit and push?"): + commit_and_push(channel, version) + + print("Done") + +if __name__ == "__main__": + main() diff --git a/reset.py b/reset.py new file mode 100644 index 0000000..45e47de --- /dev/null +++ b/reset.py @@ -0,0 +1,15 @@ +#!/usr/bin/python3 + +from shutil import rmtree + +BASE_DIR = 'data' + +confirmation = input('If you really want to delete all releases and channels, type CONFIRM: ') + +if confirmation != 'CONFIRM': + print('Cancelled') + exit() + +rmtree(BASE_DIR) + +print('Reset complete') diff --git a/url.txt b/url.txt new file mode 100644 index 0000000..b851aa1 --- /dev/null +++ b/url.txt @@ -0,0 +1 @@ +https://git.m724.eu/Minecon724/myplugin-metadata/raw/branch/master