mirror of
https://github.com/daijro/camoufox.git
synced 2026-08-19 00:00:58 +00:00
08ecd86746
Add comprehensive task list documenting the Firefox upgrade from v135.0.1 to v147.0b3 (12 major versions). Includes status tracking for all 45 patches after syncing with upstream LibreWolf (Firefox 146) and Playwright repositories. Key changes: - 25 broken patches identified (56% failure rate) - 20 patches applying cleanly (44% success rate) - LibreWolf patches updated from upstream: 17 patches synced, 5 deleted, 2 auto-fixed -
241 lines
7.3 KiB
Python
241 lines
7.3 KiB
Python
#!/usr/bin/env python3
|
|
|
|
"""
|
|
The script that patches the Firefox source into the Camoufox source.
|
|
Based on LibreWolf's patch script:
|
|
https://gitlab.com/librewolf-community/browser/source/-/blob/main/scripts/librewolf-patches.py
|
|
|
|
Run:
|
|
python3 scripts/init-patch.py <version> <release>
|
|
"""
|
|
|
|
import hashlib
|
|
import os
|
|
import re
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
from dataclasses import dataclass
|
|
|
|
from _mixin import (
|
|
find_src_dir,
|
|
get_moz_target,
|
|
get_options,
|
|
list_patches,
|
|
patch,
|
|
run,
|
|
temp_cd,
|
|
)
|
|
|
|
options, args = get_options()
|
|
|
|
"""
|
|
Main patcher functions
|
|
"""
|
|
|
|
|
|
@dataclass
|
|
class Patcher:
|
|
"""Patch and prepare the Camoufox source"""
|
|
|
|
moz_target: str
|
|
target: str
|
|
|
|
def camoufox_patches(self):
|
|
"""
|
|
Apply all patches
|
|
"""
|
|
version, release = extract_args()
|
|
with temp_cd(find_src_dir('.', version, release)):
|
|
# Reset to unpatched state first (like "Find broken patches")
|
|
print("Resetting to unpatched state...")
|
|
run('git reset --hard unpatched', exit_on_fail=False)
|
|
|
|
# Create the base mozconfig file
|
|
run('cp -v ../assets/base.mozconfig mozconfig')
|
|
# Set cross building target
|
|
print(f'Using target: {self.moz_target}')
|
|
self._update_mozconfig()
|
|
|
|
if not options.mozconfig_only:
|
|
# Apply patches with roverfox patches at the very end
|
|
all_patches = list_patches()
|
|
# Normalize paths and partition into non-roverfox and roverfox
|
|
non_roverfox = []
|
|
roverfox = []
|
|
for p in all_patches:
|
|
norm = os.path.normpath(p)
|
|
parts = norm.split(os.sep)
|
|
if 'roverfox' in parts:
|
|
roverfox.append(p)
|
|
else:
|
|
non_roverfox.append(p)
|
|
|
|
# Track patch failures
|
|
failed_patches = []
|
|
|
|
# Apply non-roverfox patches first
|
|
for patch_file in non_roverfox:
|
|
rejects = self._apply_and_check(patch_file)
|
|
if rejects:
|
|
failed_patches.append((patch_file, rejects))
|
|
|
|
# Apply roverfox patches last
|
|
for patch_file in roverfox:
|
|
rejects = self._apply_and_check(patch_file)
|
|
if rejects:
|
|
failed_patches.append((patch_file, rejects))
|
|
|
|
# Report failures
|
|
if failed_patches:
|
|
print('\n' + '='*70)
|
|
print(f'ERROR: {len(failed_patches)} patch(es) failed to apply cleanly:')
|
|
print('='*70)
|
|
for patch_file, rejects in failed_patches:
|
|
print(f'\n{patch_file}:')
|
|
for reject in rejects:
|
|
print(f' - {reject}')
|
|
print('='*70)
|
|
sys.exit(1)
|
|
|
|
print('Complete!')
|
|
|
|
def _apply_and_check(self, patch_file):
|
|
"""
|
|
Apply a patch and check for reject files.
|
|
Returns list of reject files if any, empty list otherwise.
|
|
"""
|
|
import subprocess
|
|
|
|
# Apply the patch and capture output
|
|
result = subprocess.run(
|
|
['patch', '-p1', '-i', patch_file],
|
|
capture_output=True,
|
|
text=True
|
|
)
|
|
|
|
print(f"\n*** -> patch -p1 -i {patch_file}")
|
|
if result.stdout:
|
|
print(result.stdout, end='')
|
|
if result.stderr:
|
|
print(result.stderr, end='', file=sys.stderr)
|
|
|
|
# Look for reject files in the output
|
|
rejects = []
|
|
for line in (result.stdout + result.stderr).splitlines():
|
|
if '.rej' in line and 'saving rejects to file' in line:
|
|
# Extract the reject file path
|
|
match = re.search(r'saving rejects to file (.+\.rej)', line)
|
|
if match:
|
|
rejects.append(match.group(1))
|
|
|
|
return rejects
|
|
|
|
def _update_mozconfig(self):
|
|
"""
|
|
Helper for adding additional mozconfig code from assets/<target>.mozconfig
|
|
"""
|
|
mozconfig_backup = "mozconfig.backup"
|
|
mozconfig = "mozconfig"
|
|
mozconfig_hash = "mozconfig.hash"
|
|
|
|
# Create backup if it doesn't exist
|
|
if not os.path.exists(mozconfig_backup):
|
|
if os.path.exists(mozconfig):
|
|
shutil.copy2(mozconfig, mozconfig_backup)
|
|
else:
|
|
with open(mozconfig_backup, 'w', encoding='utf-8') as f:
|
|
pass
|
|
|
|
# Read backup content
|
|
with open(mozconfig_backup, 'r', encoding='utf-8') as f:
|
|
content = f.read()
|
|
|
|
# Add target option
|
|
content += f"\nac_add_options --target={self.moz_target}\n"
|
|
|
|
# Add target-specific mozconfig if it exists
|
|
target_mozconfig = os.path.join("..", "assets", f"{self.target}.mozconfig")
|
|
if os.path.exists(target_mozconfig):
|
|
with open(target_mozconfig, 'r', encoding='utf-8') as f:
|
|
content += f.read()
|
|
|
|
# Calculate new hash
|
|
new_hash = hashlib.sha256(content.encode()).hexdigest()
|
|
|
|
# Update mozconfig
|
|
print(f"-> Updating mozconfig, target is {self.moz_target}")
|
|
with open(mozconfig, 'w', encoding='utf-8') as f:
|
|
f.write(content)
|
|
with open(mozconfig_hash, 'w', encoding='utf-8') as f:
|
|
f.write(new_hash)
|
|
|
|
|
|
def add_rustup(*targets):
|
|
"""Add rust targets"""
|
|
for rust_target in targets:
|
|
run(f'~/.cargo/bin/rustup target add "{rust_target}"')
|
|
|
|
|
|
def _update_rustup(target):
|
|
"""Add rust targets for the given target"""
|
|
if target == "linux":
|
|
add_rustup("aarch64-unknown-linux-gnu", "i686-unknown-linux-gnu")
|
|
elif target == "windows":
|
|
add_rustup("x86_64-pc-windows-msvc", "aarch64-pc-windows-msvc", "i686-pc-windows-msvc")
|
|
elif target == "macos":
|
|
add_rustup("x86_64-apple-darwin", "aarch64-apple-darwin")
|
|
|
|
|
|
"""
|
|
Preparation
|
|
"""
|
|
|
|
|
|
def extract_args():
|
|
"""Get version and release from args"""
|
|
if len(args) != 2:
|
|
sys.stderr.write('error: please specify version and release of camoufox source')
|
|
sys.exit(1)
|
|
return args[0], args[1]
|
|
|
|
|
|
AVAILABLE_TARGETS = ["linux", "windows", "macos"]
|
|
AVAILABLE_ARCHS = ["x86_64", "arm64", "i686"]
|
|
|
|
|
|
def extract_build_target():
|
|
"""Get moz_target if passed to BUILD_TARGET environment variable"""
|
|
|
|
if os.environ.get('BUILD_TARGET'):
|
|
target, arch = os.environ['BUILD_TARGET'].split(',')
|
|
assert target in AVAILABLE_TARGETS, f"Unsupported target: {target}"
|
|
assert arch in AVAILABLE_ARCHS, f"Unsupported architecture: {arch}"
|
|
else:
|
|
target, arch = "macos", "arm64"
|
|
return target, arch
|
|
|
|
|
|
"""
|
|
Launcher
|
|
"""
|
|
|
|
if __name__ == "__main__":
|
|
# Extract args
|
|
VERSION, RELEASE = extract_args()
|
|
|
|
TARGET, ARCH = extract_build_target()
|
|
MOZ_TARGET = get_moz_target(TARGET, ARCH)
|
|
_update_rustup(TARGET)
|
|
|
|
# Check if the folder exists
|
|
if not os.path.exists(f'camoufox-{VERSION}-{RELEASE}/configure.py'):
|
|
sys.stderr.write('error: folder doesn\'t look like a Firefox folder.')
|
|
sys.exit(1)
|
|
|
|
# Apply the patches
|
|
patcher = Patcher(MOZ_TARGET, TARGET)
|
|
patcher.camoufox_patches()
|
|
|
|
sys.exit(0) # ensure 0 exit code
|