import os import re import logging from configparser import ConfigParser import requests from logger import setup_log from package import Package ## Autopkg Apps apps = { "bitcoinknots": { "name": "Bitcoin Knots", "url": "https://api.github.com/repos/bitcoinknots/bitcoin/releases/latest", "versioningScheme": r"^v(\d+)\.(\d+)\.knots(\d{8})$" }, "electrs": { "name": "electrs", "url": "https://api.github.com/repos/romanz/electrs/releases/latest", } } class Autopkg: def __init__(self): # Logging Setup setup_log() logging.info( "Running autopkg (c) 2025 phantom https://shadeouts.net/" ) # Environment Setup target = os.getenv("APKG_TARGET") os.environ["APKG_RUNTIME_DIR"] = os.path.dirname(os.path.abspath(__file__)) # Set runtime directory match target: case "prod": self.datafile = "/etc/autopkg/data.ini" case "test" | "debug": logging.warning("Running autopkg in testing mode!") self.datafile = os.getenv("APKG_RUNTIME_DIR") + "/dev/data.ini" if os.path.exists(self.datafile): os.remove(self.datafile) case _: raise ValueError("APKG_TARGET environment variable not setup correctly!") ## Config File Setup self.data = ConfigParser() self.data.read(self.datafile) # Write datafile changes def write_data(self): with open(self.datafile, "w") as f: self.data.write(f) # Main Application def main(self): # Handle apps for app, info in apps.items(): # Setup INI file if f"tags.{app}" not in self.data: self.data.add_section(f"tags.{app}") self.write_data() # Grab data from data file data_section = f"tags.{app}" data_tag = [list.append(i[1]) for i in self.data.items(data_section)] app_name = info["name"] # Ping API response = requests.get(info["url"]) # Fetch data from Git API # Parse through JSON data if response.status_code == 200: json = response.json() api_tag = json["tag_name"] # App version from API pre_release = json["prerelease"] # Package new versions if available api_tag_higher = is_tag_higher(api_tag, data_tag, info["versioningScheme"]) if not pre_release and api_tag_higher[0]: logging.info(f"Found new version ({api_tag}) for {app_name}, packaging..") try: # REMOVE!!! if Package(app, api_tag).build(): ini_version = str(api_tag) self.write_data() except Exception as e: logging.error(f"Error starting docker container for {app_name}") else: logging.log(f"No new versions were found for {app_name}") else: logging.error(f"Failed to ping {app_name}'s API.") def is_tag_higher(api_tag: str, data_tag: list, data_scheme: str) -> tuple: regular_scheme = r"^v(\d+)\.(\d+)\.(\d+)$" # Derive version from API tag try: version = re.match(data_scheme, api_tag) except: version = re.match(regular_scheme, api_tag) if not version: logging.warning(f"New tag for {data_info["name"]} doesn't follow versioning schemes, ignoring..") return (False,) # Compare versions re_tag = map(int, version.groups()) is_higher = tuple(map(lambda a, b: a >= b, re_tag, data_tag)) return (True, re_tag) if all(is_higher) else (False,) if __name__ == "__main__": # Call main function Autopkg().main()