diff --git a/.gitignore b/.gitignore index 0494d76..32d88a1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -/firefox-* /camoufox-* /mozilla-unified /extra-docs @@ -8,4 +7,5 @@ dist/ /bundle/fonts/extra launch launch.exe -*.old \ No newline at end of file +*.old +__pycache__/ diff --git a/Makefile b/Makefile index 0848672..e84264b 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,13 @@ include upstream.sh export -ff_source_dir := firefox-$(version) -lw_source_dir := camoufox-$(version)-$(release) +cf_source_dir := camoufox-$(version)-$(release) debs := python3 python3-dev python3-pip p7zip-full golang-go msitools wget rpms := python3 python3-devel p7zip golang msitools wget pacman := python python-pip p7zip go msitools wget -.PHONY: help fetch clean distclean build package build-launcher check-arch edits run bootstrap mozbootstrap dir package-common package-linux package-macos package-windows +.PHONY: help fetch clean distclean build package build-launcher check-arch revert edits run bootstrap mozbootstrap dir package-common package-linux package-macos package-windows help: @echo "Available targets:" @@ -16,6 +15,7 @@ help: @echo " bootstrap - Set up build environment" @echo " mozbootstrap - Sets up mach" @echo " dir - Prepare Camoufox source directory" + @echo " revert - Kill all working changes" @echo " edits - Camoufox developer UI" @echo " build-launcher - Build launcher" @echo " clean - Remove build artifacts" @@ -27,35 +27,40 @@ help: @echo " run - Run Camoufox" fetch: - git clone --depth 1 --branch $(BASE_BRANCH) --single-branch $(REMOTE_URL) $(ff_source_dir) - cd $(ff_source_dir) && git fetch --depth 1 origin $(BASE_REVISION) && git checkout $(BASE_REVISION) + git clone --depth 1 --branch $(BASE_BRANCH) --single-branch $(REMOTE_URL) $(cf_source_dir) + cd $(cf_source_dir) && git fetch --depth 1 origin $(BASE_REVISION) + make revert + +revert: + cd $(cf_source_dir) && git reset --hard $(BASE_REVISION) + python3 scripts/init-patch.py $(version) $(release) dir: - @if [ ! -d $(ff_source_dir) ]; then \ + @if [ ! -d $(cf_source_dir) ]; then \ make fetch; \ fi - rm -rf $(lw_source_dir) - cp -r $(ff_source_dir) $(lw_source_dir) + make clean python3 scripts/patch.py $(version) $(release) mozbootstrap: - cd $(ff_source_dir) && MOZBUILD_STATE_PATH=$$HOME/.mozbuild ./mach --no-interactive bootstrap --application-choice=browser + cd $(cf_source_dir) && MOZBUILD_STATE_PATH=$$HOME/.mozbuild ./mach --no-interactive bootstrap --application-choice=browser bootstrap: dir (sudo apt-get -y install $(debs) || sudo dnf -y install $(rpms) || sudo pacman -Sy $(pacman)) make mozbootstrap clean: - rm -rf $(lw_source_dir) + cd $(cf_source_dir) && git clean -fdx && ./mach clobber + make revert distclean: clean - rm -rf $(ff_source_dir) + rm -rf $(cf_source_dir) build: - @if [ ! -d $(lw_source_dir) ]; then \ + @if [ ! -d $(cf_source_dir) ]; then \ make dir; \ fi - cd $(lw_source_dir) && ./mach build + cd $(cf_source_dir) && ./mach build edits: python ./scripts/developer.py @@ -70,8 +75,8 @@ build-launcher: check-arch cd launcher && ./build.sh $(arch) $(os) package-common: check-arch - cd $(lw_source_dir) && cat browser/locales/shipped-locales | xargs ./mach package-multi-locale --locales - cp -v $(lw_source_dir)/obj-*/dist/camoufox-$(version)-$(release).*.* . + cd $(cf_source_dir) && cat browser/locales/shipped-locales | xargs ./mach package-multi-locale --locales + cp -v $(cf_source_dir)/obj-*/dist/camoufox-$(version)-$(release).*.* . package-linux: package-common make build-launcher arch=$(arch) os=linux; @@ -106,4 +111,4 @@ package-windows: package-common --fonts macos linux run: - cd $(lw_source_dir) && rm -rf ~/.camoufox && ./mach run + cd $(cf_source_dir) && rm -rf ~/.camoufox && ./mach run diff --git a/scripts/developer.py b/scripts/developer.py index 89a7b93..f9b46f6 100644 --- a/scripts/developer.py +++ b/scripts/developer.py @@ -1,37 +1,43 @@ +#!/usr/bin/env python3 + +""" +GUI for managing Camoufox patches. +""" + import os +import contextlib import easygui from patch import list_files, patch, run -# Cd to the camoufox-* folder (this is located ..) -os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -folders = os.listdir('.') -for folder in folders: - if os.path.isdir(folder) and folder.startswith('camoufox-'): - os.chdir(folder) - break -else: - raise Exception('No camoufox-* folder found') + +def into_camoufox_dir(): + """Find and cd to the camoufox-* folder (this is located ..)""" + os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + folders = os.listdir('.') + for folder in folders: + if os.path.isdir(folder) and folder.startswith('camoufox-'): + os.chdir(folder) + break + else: + raise FileNotFoundError('No camoufox-* folder found') -""" -GUI Choicebox with the following options: -- Reset: - `git checkout -- .` - then patch *.bootstrap (required) -- Patch all BUT: - Checklist of *.patch files in ../patches to exclude. The rest gets patched. -- Find broken: - Resets, runs patches, then finds broken patches. - If all show good error code, show at the top of the message box "All patches applied successfully" - If any show bad error code, show at the top of the message box "Some patches failed to apply", then the rej output -""" +@contextlib.contextmanager +def temp_cd(path): + # Temporarily change to a different working directory + _old_cwd = os.getcwd() + os.chdir(os.path.abspath(path)) + + try: + yield + finally: + os.chdir(_old_cwd) def reset_camoufox(): - run('git checkout -- .') - for patch_file in list_files('../patches', suffix='*.bootstrap'): - patch(patch_file) + with temp_cd('..'): + run('make clean') def run_patches(reverse=False): @@ -58,49 +64,72 @@ choices = [ "Write workspace to patch", ] -choice = easygui.choicebox("Select an option:", "Camoufox Patcher", choices) +""" +GUI Choicebox with the following options: +- Reset: + `make clean` +- Patch all BUT: + Checklist of *.patch files in ../patches to exclude. The rest gets patched. +- Find broken: + Resets, runs patches, then finds broken patches. + If all show good error code, show at the top of the message box "All patches applied successfully" + If any show bad error code, show at the top of the message box "Some patches failed to apply", then the rej output +""" -if choice == "Reset workspace": - reset_camoufox() - easygui.msgbox("Reset completed and bootstrap patches applied.", "Reset Complete") -elif choice == "Select patches": - run_patches(reverse=False) - easygui.msgbox("Patching completed.", "Patching Complete") +def handle_choice(choice): + match choice: + case "Reset workspace": + reset_camoufox() + easygui.msgbox("Reset completed and bootstrap patches applied.", "Reset Complete") -elif choice == "Reverse patches": - run_patches(reverse=True) - easygui.msgbox("Unpatching completed.", "Unpatching Complete") + case "Select patches": + run_patches(reverse=False) + easygui.msgbox("Patching completed.", "Patching Complete") -elif choice == "Find broken patches": - reset_camoufox() + case "Reverse patches": + run_patches(reverse=True) + easygui.msgbox("Unpatching completed.", "Unpatching Complete") - broken_patches = [] - for patch_file in list_files('../patches', suffix='*.patch'): - cmd = rf'patch -p1 -i "{patch_file}" | tee /dev/stderr | sed -r --quiet \'s/^.*saving rejects to file (.*\.rej)$/\\1/p\'' - result = os.popen(cmd).read().strip() - print(result) - if result: - broken_patches.append((patch_file, result)) + case "Find broken patches": + reset_camoufox() - if not broken_patches: - easygui.msgbox("All patches applied successfully", "Patching Result") - else: - message = "Some patches failed to apply:\n\n" - for patch_file, rejects in broken_patches: - message += f"Patch: {patch_file}\nRejects: {rejects}\n\n" - easygui.textbox("Patching Result", "Failed Patches", message) + broken_patches = [] + for patch_file in list_files('../patches', suffix='*.patch'): + cmd = rf'patch -p1 -i "{patch_file}" | tee /dev/stderr | sed -r --quiet \'s/^.*saving rejects to file (.*\.rej)$/\\1/p\'' + result = os.popen(cmd).read().strip() + print(result) + if result: + broken_patches.append((patch_file, result)) -elif choice == "See current workspace": - result = os.popen('git diff').read() - easygui.textbox("Diff", "Diff", result) + if not broken_patches: + easygui.msgbox("All patches applied successfully", "Patching Result") + else: + message = "Some patches failed to apply:\n\n" + for patch_file, rejects in broken_patches: + message += f"Patch: {patch_file}\nRejects: {rejects}\n\n" + easygui.textbox("Patching Result", "Failed Patches", message) -elif choice == "Write workspace to patch": - # Open a file dialog to select a file to write the diff to - file_path = easygui.filesavebox( - "Select a file to write the diff to", "Write Diff", filetypes="*.patch" - ) - if not file_path: - exit() - run(f'git diff > {file_path}') - easygui.msgbox("Diff written to file", "Diff Written") + case "See current workspace": + result = os.popen('git diff').read() + easygui.textbox("Diff", "Diff", result) + + case "Write workspace to patch": + # Open a file dialog to select a file to write the diff to + file_path = easygui.filesavebox( + "Select a file to write the diff to", "Write Diff", filetypes="*.patch" + ) + if not file_path: + exit() + run(f'git diff > {file_path}') + easygui.msgbox("Diff written to file", "Diff Written") + + case _: + print('No choice selected') + + +if __name__ == "__main__": + into_camoufox_dir() + + choice = easygui.choicebox("Select an option:", "Camoufox Dev Tools", choices) + handle_choice(choice) diff --git a/scripts/init-patch.py b/scripts/init-patch.py new file mode 100644 index 0000000..428e04f --- /dev/null +++ b/scripts/init-patch.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 + +""" +Simple script to apply *.bootstrap patches +This was separated from the main patch script because its indended to run on docker build. + +Run: + python3 scripts/init-patch.py +""" + +from patch import list_files, patch, enter_srcdir, leave_srcdir + + +def apply_bootstrap_patches(): + enter_srcdir() + + # Apply bootstraps first + for patch_file in list_files('../patches', suffix='*.bootstrap'): + patch(patch_file) + + leave_srcdir() + + +if __name__ == "__main__": + apply_bootstrap_patches() diff --git a/scripts/patch.py b/scripts/patch.py index 6eabb1c..81f2fe9 100644 --- a/scripts/patch.py +++ b/scripts/patch.py @@ -1,7 +1,12 @@ #!/usr/bin/env python3 """ -The script that patches the firefox source into the camoufox source. +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 """ import fnmatch @@ -69,6 +74,7 @@ def patch(patchfile, reverse=False): def enter_srcdir(_dir=None): if _dir is None: + version, release = extract_args() dir = f"camoufox-{version}-{release}" else: dir = _dir @@ -121,9 +127,6 @@ def camoufox_patches(): # Copy the search-config.json file run('cp -v ../assets/search-config.json services/settings/dumps/main/search-config.json') - # Apply bootstraps first - for patch_file in list_files('../patches', suffix='*.bootstrap'): - patch(patch_file) # Then apply all other patches for patch_file in list_files('../patches'): patch(patch_file) @@ -210,10 +213,6 @@ def _update_mozconfig(): with open(target_mozconfig, 'r') as f: content += f.read() - # Add macOS-specific hack - # if target == "macos" and arch == "x86_64": - # content += 'export NASM="$MOZBUILD/nasm/nasm"\n' - # Calculate new hash new_hash = hashlib.sha256(content.encode()).hexdigest() @@ -238,12 +237,17 @@ def _update_mozconfig(): Preparation """ -if __name__ == "__main__": - # Extract args + +def extract_args(): if len(args) != 2: sys.stderr.write('error: please specify version and release of camoufox source') sys.exit(1) - version, release = args[0], args[1] + return args[0], args[1] + + +if __name__ == "__main__": + # Extract args + version, release = extract_args() # Get moz_target if passed to BUILD_TARGET environment variable AVAILABLE_TARGETS = ["linux", "windows", "macos"]