Files
desktop/scripts/update_external_patches.py
2026-02-06 22:40:38 +01:00

100 lines
3.5 KiB
Python

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import os
import sys
import json
import requests
from json_with_comments import JSONWithCommentsDecoder
BASE_URI = "https://phabricator.services.mozilla.com"
OUTPUT_DIR = os.path.join(os.getcwd(), "src", "external-patches")
def die(message):
print(f"Error: {message}")
sys.exit(1)
def download_phab_patch(phab_id, output_file):
"""Download a Phabricator patch by its ID and save it to output_file."""
patch_url = f"{BASE_URI}/{phab_id}?download=true"
try:
print(f"Downloading patch from {patch_url}")
response = requests.get(patch_url)
response.raise_for_status() # Raise an error for bad responses
with open(output_file, 'wb') as f:
f.write(response.content)
print(f"Patch saved to {output_file}")
except requests.RequestException as e:
die(f"Failed to download patch {phab_id}: {e}")
def download_patch_from_url(url, output_file):
"""Download a patch from a given URL and save it to output_file."""
try:
print(f"Downloading patch from {url}")
response = requests.get(url)
response.raise_for_status() # Raise an error for bad responses
with open(output_file, 'wb') as f:
f.write(response.content)
print(f"Patch saved to {output_file}")
except requests.RequestException as e:
die(f"Failed to download patch from {url}: {e}")
def main():
with open(os.path.join(OUTPUT_DIR, "manifest.json"), 'r') as f:
manifest = json.load(f, cls=JSONWithCommentsDecoder)
expected_files = set()
for patch in manifest:
if patch.get("type") == "phabricator":
phab_id = patch.get("id")
name = patch.get("name")
if not phab_id or not name:
die(f"Patch entry missing 'id' or 'name': {patch}")
name = name.replace(" ", "_").lower()
output_file = os.path.join(OUTPUT_DIR, "firefox", f"{name}.patch")
print(f"Processing Phabricator patch: {phab_id} -> {output_file}")
download_phab_patch(phab_id, output_file)
expected_files.add(output_file)
elif patch.get("type") == "local":
print(f"Local patch: {patch.get('path')}")
expected_files.add(os.path.join(OUTPUT_DIR, patch.get("path")))
elif patch.get("type") == "patch":
url = patch.get("url")
dest = patch.get("dest")
if not url or not dest:
die(f"Patch entry missing 'url' or 'dest': {patch}")
filename = url.split("/")[-1]
output_file = os.path.join(OUTPUT_DIR, dest, filename)
download_patch_from_url(url, output_file)
replaces = patch.get("replaces", {})
for replace in replaces.keys():
value = replaces[replace]
with open(output_file, 'r') as f:
content = f.read()
if replace not in content:
die(f"Replace string '{replace}' not found in {output_file}")
with open(output_file, 'w') as f:
f.write(content.replace(replace, value))
expected_files.add(output_file)
else:
die(f"Unknown patch type: {patch.get('type')}")
# Check for unexpected files in the output directory
# and remove them if they are not in the expected_files set.
for root, dirs, files in os.walk(OUTPUT_DIR):
for file in files:
if file.endswith(".patch"):
file_path = os.path.join(root, file)
if file_path not in expected_files:
print(f"Removing unexpected patch file: {file_path}")
os.remove(file_path)
if __name__ == "__main__":
main()