#!/usr/bin/env python3 import os import sys import shutil import subprocess import hashlib import zipfile import tempfile import json import requests from pathlib import Path from dotenv import load_dotenv # Load environment variables from .env file load_dotenv() def create_gitea_repo(gitea_url, gitea_username, gitea_token, repo_name, description): """Create a new repository on Gitea using the API.""" api_url = f"{gitea_url}/api/v1/user/repos" headers = { "Authorization": f"token {gitea_token}", "Content-Type": "application/json" } data = { "name": repo_name, "description": description, "private": False, "auto_init": False } print(f"Creating repository {repo_name} on Gitea...") response = requests.post(api_url, headers=headers, json=data) if response.status_code == 201: print(f"Repository {repo_name} created successfully.") return response.json() else: print(f"Error creating repository: {response.status_code} - {response.text}") return None def create_zip(font_files, zip_path): """Create a zip file with the font files.""" print(f"Creating zip file at {zip_path} with the following font files:") with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf: for font_file in font_files: print(f" - {font_file}") # Add each font file to the zip with its original name (no path) arcname = os.path.basename(font_file) zipf.write(font_file, arcname=arcname) print(f"Zip file created at {zip_path}") def generate_sha256(zip_path): """Generate SHA256 hash for the zip file.""" sha256_hash = hashlib.sha256() with open(zip_path, "rb") as f: # Read in 4k chunks to hash for byte_block in iter(lambda: f.read(4096), b""): sha256_hash.update(byte_block) return sha256_hash.hexdigest() def create_font_repo(font_name, font_files, gitea_url, gitea_username, gitea_token): """Create a new repository for the font and set it up with the necessary files.""" # Create a temporary directory for the font repository with tempfile.TemporaryDirectory() as temp_dir: # Create the zip file zip_filename = f"{font_name}.zip" zip_path = os.path.join(temp_dir, zip_filename) create_zip(font_files, zip_path) # Generate SHA256 hash for the zip file sha256_hash = generate_sha256(zip_path) print(f"SHA256 hash generated: {sha256_hash}") # Create the repository on Gitea repo_name = f"font-{font_name}" description = f"Font files for {font_name}" repo_data = create_gitea_repo(gitea_url, gitea_username, gitea_token, repo_name, description) if not repo_data: print("Failed to create repository on Gitea.") return None, None, None # Clone the repository repo_url = repo_data["clone_url"] repo_path = os.path.join(temp_dir, repo_name) subprocess.run(["git", "clone", repo_url, repo_path], check=True) # Copy the zip file to the repository shutil.copy(zip_path, os.path.join(repo_path, zip_filename)) # Create a README.md file with open(os.path.join(repo_path, "README.md"), "w") as f: f.write(f"# {font_name} Font\n\n") f.write(f"This repository contains the font files for {font_name}.\n\n") f.write(f"SHA256: {sha256_hash}\n") # Commit and push the changes subprocess.run(["git", "-C", repo_path, "add", "."], check=True) subprocess.run(["git", "-C", repo_path, "commit", "-m", f"Add {font_name} font files"], check=True) subprocess.run(["git", "-C", repo_path, "push"], check=True) # Create a local copy of the zip file for the formula local_zip_path = os.path.join(os.getcwd(), zip_filename) shutil.copy(zip_path, local_zip_path) return repo_path, sha256_hash, zip_filename def create_formula(font_name, sha256_hash, gitea_url, gitea_username, zip_filename): """Create the Homebrew formula for the font.""" # Get the font filename without extension (assuming it's a valid font file in the zip) font_file = os.path.basename(font_files[0]) # Assumes the first font file is the primary font file # Convert font_name to CamelCase for the class name class_name = ''.join(word.capitalize() for word in font_name.split('-')) # Create the formula content formula_content = f"""class {class_name} < Formula desc "A custom font" homepage "{gitea_url}/{gitea_username}/font-{font_name}" url "{gitea_url}/{gitea_username}/font-{font_name}/raw/branch/master/{zip_filename}" sha256 "{sha256_hash}" version "1.0.0" def install (share/"fonts").install "{font_file}" end test do # Test installation by checking that the font exists system "fc-list | grep '{font_file.split('.')[0]}'" end end """ # Create the formula directory if it doesn't exist formula_dir = os.path.join(os.getcwd(), "Formula") os.makedirs(formula_dir, exist_ok=True) # Write the formula to a file formula_path = os.path.join(formula_dir, f"font-{font_name}.rb") with open(formula_path, "w") as f: f.write(formula_content) print(f"Formula created at {formula_path}") return formula_path def add_submodule(font_name, gitea_url, gitea_username): """Add the font repository as a submodule.""" # Create the fonts directory if it doesn't exist fonts_dir = os.path.join(os.getcwd(), "fonts") os.makedirs(fonts_dir, exist_ok=True) # Add the submodule submodule_path = os.path.join(fonts_dir, font_name) repo_url = f"{gitea_url}/{gitea_username}/font-{font_name}.git" # Check if the submodule already exists if os.path.exists(submodule_path): print(f"Submodule {submodule_path} already exists. Removing it first.") subprocess.run(["git", "submodule", "deinit", "-f", submodule_path], check=True) subprocess.run(["git", "rm", "-f", submodule_path], check=True) subprocess.run(["rm", "-rf", f".git/modules/{submodule_path}"], check=True) # Add the submodule print(f"Adding submodule {submodule_path}...") subprocess.run(["git", "submodule", "add", repo_url, submodule_path], check=True) return submodule_path def update_submodule_index(font_name, submodule_path): """Update the submodule index file.""" # Create the index file if it doesn't exist index_path = os.path.join(os.getcwd(), "fonts", "index.json") if not os.path.exists(index_path): with open(index_path, "w") as f: json.dump({"fonts": []}, f, indent=2) # Read the index file with open(index_path, "r") as f: index = json.load(f) # Add the font to the index font_info = { "name": font_name, "path": submodule_path, "formula": f"font-{font_name}" } # Check if the font is already in the index for i, font in enumerate(index.get("fonts", [])): if font["name"] == font_name: index["fonts"][i] = font_info break else: # Add the font to the index if "fonts" not in index: index["fonts"] = [] index["fonts"].append(font_info) # Write the updated index back to the file with open(index_path, "w") as f: json.dump(index, f, indent=2) print(f"Index updated at {index_path}") def main(): # Get the Gitea URL from environment variable or prompt gitea_url = os.getenv("GITEA_URL") if not gitea_url: gitea_url = input("Enter your Gitea URL (e.g., http://clancy.genet-godzilla.ts.net:3002): ") # Get the Gitea username from environment variable or prompt gitea_username = os.getenv("GITEA_USERNAME") if not gitea_username: gitea_username = input("Enter your Gitea username: ") # Get the Gitea token from environment variable or prompt gitea_token = os.getenv("GITEA_API_TOKEN") if not gitea_token: gitea_token = input("Enter your Gitea API token: ") # Get the font name font_name = input("Enter the name of the font (e.g., FiraCode): ").lower() # Get the font files font_folder = input("Enter the location of the font folder: ").strip("'\"") # Strip quotes from the input print(f"Looking for font files in: {font_folder}") # Check if the folder exists if not os.path.exists(font_folder): print(f"Error: The folder '{font_folder}' does not exist.") return # Find all the font files in the provided folder font_files = [os.path.join(font_folder, f) for f in os.listdir(font_folder) if f.endswith(('ttf', 'otf'))] if not font_files: print("No font files found in the provided folder.") return print(f"Found {len(font_files)} font files:") for font_file in font_files: print(f" - {os.path.basename(font_file)}") # Create the font repository font_repo_path, sha256_hash, zip_filename = create_font_repo(font_name, font_files, gitea_url, gitea_username, gitea_token) if not font_repo_path: print("Failed to create font repository. Exiting.") return # Create the formula formula_path = create_formula(font_name, sha256_hash, gitea_url, gitea_username, zip_filename) # Add the submodule submodule_path = add_submodule(font_name, gitea_url, gitea_username) # Update the submodule index update_submodule_index(font_name, submodule_path) # Stage and commit the changes subprocess.run(["git", "add", formula_path, "fonts/index.json", submodule_path], check=True) subprocess.run(["git", "commit", "-m", f"Add {font_name} font as submodule"], check=True) print(f"Font {font_name} has been added successfully as a submodule.") print("Remember to push your changes to Gitea manually.") if __name__ == "__main__": main()